QP is an event-driven, RTOS-like, active object framework for microcontrollers, such as mbed. The QP framework provides thread-safe execution of active objects (concurrent state machines) and support both manual and automatic coding of UML statecharts in readable, production-quality C or C++. Automatic code generation of QP code is supported by the free QM modeling tool.

Dependents:   qp_hangman qp_dpp qp_blinky

QP/C++ (Quantum Platform in C++) is a lightweight, open source active object (actor) framework for building responsive and modular real-time embedded applications as systems of asynchronous event-driven active objects (actors). The QP/C++ framework is a member of a larger family consisting of QP/C++, QP/C, and QP-nano frameworks, which are all strictly quality controlled, thoroughly documented, and available under GPLv3 with a special Exception for mbed (see http://www.state-machine.com/licensing/QP-mbed_GPL_Exception.txt).

The behavior of active objects is specified in QP/C++ by means of hierarchical state machines (UML statecharts). The framework supports manual coding of UML state machines in C++ as well as automatic code generation by means of the free QM modeling tool (http://www.state-machine.com/qm).

Please see the "QP/C++ Reference Manual" (http://www.state-machine.com/qpcpp) for more information.

Committer:
QL
Date:
Tue Sep 04 22:20:52 2012 +0000
Revision:
9:ca2e6010d9e2
Parent:
8:934bb9eea80b
QP/C++ 4.5.02 compatible with QM 2.2.xx

Who changed what in which revision?

UserRevisionLine numberNew contents of line
QL 9:ca2e6010d9e2 1 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2 // Product: QP/C++ platform-independent interface
QL 9:ca2e6010d9e2 3 // Last Updated for QP ver: 4.5.02 (modified to fit in one file)
QL 9:ca2e6010d9e2 4 // Date of the Last Update: Aug 24, 2012
QL 9:ca2e6010d9e2 5 //
QL 9:ca2e6010d9e2 6 // Q u a n t u m L e a P s
QL 9:ca2e6010d9e2 7 // ---------------------------
QL 9:ca2e6010d9e2 8 // innovating embedded systems
QL 9:ca2e6010d9e2 9 //
QL 9:ca2e6010d9e2 10 // Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved.
QL 9:ca2e6010d9e2 11 //
QL 9:ca2e6010d9e2 12 // This program is open source software: you can redistribute it and/or
QL 9:ca2e6010d9e2 13 // modify it under the terms of the GNU General Public License as published
QL 9:ca2e6010d9e2 14 // by the Free Software Foundation, either version 2 of the License, or
QL 9:ca2e6010d9e2 15 // (at your option) any later version.
QL 9:ca2e6010d9e2 16 //
QL 9:ca2e6010d9e2 17 // Alternatively, this program may be distributed and modified under the
QL 9:ca2e6010d9e2 18 // terms of Quantum Leaps commercial licenses, which expressly supersede
QL 9:ca2e6010d9e2 19 // the GNU General Public License and are specifically designed for
QL 9:ca2e6010d9e2 20 // licensees interested in retaining the proprietary status of their code.
QL 9:ca2e6010d9e2 21 //
QL 9:ca2e6010d9e2 22 // This program is distributed in the hope that it will be useful,
QL 9:ca2e6010d9e2 23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
QL 9:ca2e6010d9e2 24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
QL 9:ca2e6010d9e2 25 // GNU General Public License for more details.
QL 9:ca2e6010d9e2 26 //
QL 9:ca2e6010d9e2 27 // You should have received a copy of the GNU General Public License
QL 9:ca2e6010d9e2 28 // along with this program. If not, see <http://www.gnu.org/licenses/>.
QL 9:ca2e6010d9e2 29 //
QL 9:ca2e6010d9e2 30 // Contact information:
QL 9:ca2e6010d9e2 31 // Quantum Leaps Web sites: http://www.quantum-leaps.com
QL 9:ca2e6010d9e2 32 // http://www.state-machine.com
QL 9:ca2e6010d9e2 33 // e-mail: info@quantum-leaps.com
QL 9:ca2e6010d9e2 34 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 35 #ifndef qp_h
QL 9:ca2e6010d9e2 36 #define qp_h
QL 9:ca2e6010d9e2 37
QL 9:ca2e6010d9e2 38 // "qevt.h" ==================================================================
QL 9:ca2e6010d9e2 39 /// \brief QEvt class and basic macros used by all QP components.
QL 9:ca2e6010d9e2 40 ///
QL 9:ca2e6010d9e2 41 /// This header file must be included, perhaps indirectly, in all modules
QL 9:ca2e6010d9e2 42 /// (*.cpp files) that use any component of QP/C++ (such as QEP, QF, or QK).
QL 9:ca2e6010d9e2 43
QL 9:ca2e6010d9e2 44 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 45 /// \brief The current QP version number
QL 9:ca2e6010d9e2 46 ///
QL 9:ca2e6010d9e2 47 /// \return version of the QP as a hex constant constant 0xXYZZ, where X is
QL 9:ca2e6010d9e2 48 /// a 1-digit major version number, Y is a 1-digit minor version number, and
QL 9:ca2e6010d9e2 49 /// ZZ is a 2-digit release number.
QL 9:ca2e6010d9e2 50 #define QP_VERSION 0x4502U
QL 9:ca2e6010d9e2 51
QL 9:ca2e6010d9e2 52 #ifndef Q_ROM
QL 9:ca2e6010d9e2 53 /// \brief Macro to specify compiler-specific directive for placing a
QL 9:ca2e6010d9e2 54 /// constant object in ROM.
QL 9:ca2e6010d9e2 55 ///
QL 9:ca2e6010d9e2 56 /// Many compilers for Harvard-architecture MCUs provide non-stanard
QL 9:ca2e6010d9e2 57 /// extensions to support placement of objects in different memories.
QL 9:ca2e6010d9e2 58 /// In order to conserve the precious RAM, QP uses the Q_ROM macro for
QL 9:ca2e6010d9e2 59 /// all constant objects that can be allocated in ROM.
QL 9:ca2e6010d9e2 60 ///
QL 9:ca2e6010d9e2 61 /// To override the following empty definition, you need to define the
QL 9:ca2e6010d9e2 62 /// Q_ROM macro in the qep_port.h header file. Some examples of valid
QL 9:ca2e6010d9e2 63 /// Q_ROM macro definitions are: __code (IAR 8051 compiler), code (Keil
QL 9:ca2e6010d9e2 64 /// Cx51 compiler), PROGMEM (gcc for AVR), __flash (IAR for AVR).
QL 9:ca2e6010d9e2 65 #define Q_ROM
QL 9:ca2e6010d9e2 66 #endif
QL 9:ca2e6010d9e2 67 #ifndef Q_ROM_VAR // if NOT defined, provide the default definition
QL 9:ca2e6010d9e2 68 /// \brief Macro to specify compiler-specific directive for accessing a
QL 9:ca2e6010d9e2 69 /// constant object in ROM.
QL 9:ca2e6010d9e2 70 ///
QL 9:ca2e6010d9e2 71 /// Many compilers for MCUs provide different size pointers for
QL 9:ca2e6010d9e2 72 /// accessing objects in various memories. Constant objects allocated
QL 9:ca2e6010d9e2 73 /// in ROM (see #Q_ROM macro) often mandate the use of specific-size
QL 9:ca2e6010d9e2 74 /// pointers (e.g., far pointers) to get access to ROM objects. The
QL 9:ca2e6010d9e2 75 /// macro Q_ROM_VAR specifies the kind of the pointer to be used to access
QL 9:ca2e6010d9e2 76 /// the ROM objects.
QL 9:ca2e6010d9e2 77 ///
QL 9:ca2e6010d9e2 78 /// To override the following empty definition, you need to define the
QL 9:ca2e6010d9e2 79 /// Q_ROM_VAR macro in the qep_port.h header file. An example of valid
QL 9:ca2e6010d9e2 80 /// Q_ROM_VAR macro definition is: __far (Freescale HC(S)08 compiler).
QL 9:ca2e6010d9e2 81 #define Q_ROM_VAR
QL 9:ca2e6010d9e2 82 #endif
QL 9:ca2e6010d9e2 83 #ifndef Q_ROM_BYTE
QL 9:ca2e6010d9e2 84 /// \brief Macro to access a byte allocated in ROM
QL 9:ca2e6010d9e2 85 ///
QL 9:ca2e6010d9e2 86 /// Some compilers for Harvard-architecture MCUs, such as gcc for AVR, do
QL 9:ca2e6010d9e2 87 /// not generate correct code for accessing data allocated in the program
QL 9:ca2e6010d9e2 88 /// space (ROM). The workaround for such compilers is to explictly add
QL 9:ca2e6010d9e2 89 /// assembly code to access each data element allocated in the program
QL 9:ca2e6010d9e2 90 /// space. The macro Q_ROM_BYTE() retrieves a byte from the given ROM
QL 9:ca2e6010d9e2 91 /// address.
QL 9:ca2e6010d9e2 92 ///
QL 9:ca2e6010d9e2 93 /// The Q_ROM_BYTE() macro should be defined for the compilers that
QL 9:ca2e6010d9e2 94 /// cannot handle correctly data allocated in ROM (such as the gcc).
QL 9:ca2e6010d9e2 95 /// If the macro is left undefined, the default definition simply returns
QL 9:ca2e6010d9e2 96 /// the argument and lets the compiler generate the correct code.
QL 9:ca2e6010d9e2 97 #define Q_ROM_BYTE(rom_var_) (rom_var_)
QL 9:ca2e6010d9e2 98 #endif
QL 9:ca2e6010d9e2 99
QL 9:ca2e6010d9e2 100 #ifndef Q_SIGNAL_SIZE
QL 9:ca2e6010d9e2 101 /// \brief The size (in bytes) of the signal of an event. Valid values:
QL 9:ca2e6010d9e2 102 /// 1, 2, or 4; default 1
QL 9:ca2e6010d9e2 103 ///
QL 9:ca2e6010d9e2 104 /// This macro can be defined in the QEP port file (qep_port.h) to
QL 9:ca2e6010d9e2 105 /// configure the ::QSignal type. When the macro is not defined, the
QL 9:ca2e6010d9e2 106 /// default of 1 byte is chosen.
QL 9:ca2e6010d9e2 107 #define Q_SIGNAL_SIZE 2
QL 9:ca2e6010d9e2 108 #endif
QL 9:ca2e6010d9e2 109
QL 9:ca2e6010d9e2 110 #ifndef Q_NNAMESPACE
QL 9:ca2e6010d9e2 111
QL 9:ca2e6010d9e2 112 /// \brief begin of the namespace QP
QL 9:ca2e6010d9e2 113 ///
QL 9:ca2e6010d9e2 114 /// \note defines to nothing if #Q_USE_NAMESPACE is undefined
QL 9:ca2e6010d9e2 115 #define QP_BEGIN_ namespace QP {
QL 9:ca2e6010d9e2 116
QL 9:ca2e6010d9e2 117 /// \brief end of the namespace QP
QL 9:ca2e6010d9e2 118 ///
QL 9:ca2e6010d9e2 119 /// \note defines to nothing if #Q_USE_NAMESPACE is undefined
QL 9:ca2e6010d9e2 120 #define QP_END_ }
QL 9:ca2e6010d9e2 121
QL 9:ca2e6010d9e2 122 /// \brief namespace QP prefix
QL 9:ca2e6010d9e2 123 ///
QL 9:ca2e6010d9e2 124 /// \note defines to nothing if #Q_USE_NAMESPACE is undefined
QL 9:ca2e6010d9e2 125 #define QP_ QP::
QL 9:ca2e6010d9e2 126
QL 9:ca2e6010d9e2 127 #else
QL 9:ca2e6010d9e2 128
QL 9:ca2e6010d9e2 129 #define QP_BEGIN_
QL 9:ca2e6010d9e2 130 #define QP_END_
QL 9:ca2e6010d9e2 131 #define QP_
QL 9:ca2e6010d9e2 132
QL 9:ca2e6010d9e2 133 #endif
QL 9:ca2e6010d9e2 134
QL 9:ca2e6010d9e2 135 QP_BEGIN_
QL 9:ca2e6010d9e2 136
QL 9:ca2e6010d9e2 137 #if (Q_SIGNAL_SIZE == 1)
QL 9:ca2e6010d9e2 138 typedef uint8_t QSignal;
QL 9:ca2e6010d9e2 139 #elif (Q_SIGNAL_SIZE == 2)
QL 9:ca2e6010d9e2 140 /// \brief QSignal represents the signal of an event.
QL 9:ca2e6010d9e2 141 ///
QL 9:ca2e6010d9e2 142 /// The relationship between an event and a signal is as follows. A signal
QL 9:ca2e6010d9e2 143 /// in UML is the specification of an asynchronous stimulus that triggers
QL 9:ca2e6010d9e2 144 /// reactions [<A HREF="http://www.omg.org/docs/ptc/03-08-02.pdf">UML
QL 9:ca2e6010d9e2 145 /// document ptc/03-08-02</A>], and as such is an essential part of an
QL 9:ca2e6010d9e2 146 /// event. (The signal conveys the type of the occurrence-what happened?)
QL 9:ca2e6010d9e2 147 /// However, an event can also contain additional quantitative information
QL 9:ca2e6010d9e2 148 /// about the occurrence in form of event parameters. Please refer to the
QL 9:ca2e6010d9e2 149 typedef uint16_t QSignal;
QL 9:ca2e6010d9e2 150 #elif (Q_SIGNAL_SIZE == 4)
QL 9:ca2e6010d9e2 151 typedef uint32_t QSignal;
QL 9:ca2e6010d9e2 152 #else
QL 9:ca2e6010d9e2 153 #error "Q_SIGNAL_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 154 #endif
QL 9:ca2e6010d9e2 155
QL 9:ca2e6010d9e2 156 #ifdef Q_EVT_CTOR // Provide the constructor for the QEvt class?
QL 9:ca2e6010d9e2 157
QL 9:ca2e6010d9e2 158 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 159 /// \brief QEvt base class.
QL 9:ca2e6010d9e2 160 ///
QL 9:ca2e6010d9e2 161 /// QEvt represents events without parameters and serves as the base class
QL 9:ca2e6010d9e2 162 /// for derivation of events with parameters.
QL 9:ca2e6010d9e2 163 ///
QL 9:ca2e6010d9e2 164 /// The following example illustrates how to add an event parameter by
QL 9:ca2e6010d9e2 165 /// inheriting from the QEvt class.
QL 9:ca2e6010d9e2 166 /// \include qep_qevent.cpp
QL 9:ca2e6010d9e2 167 class QEvt {
QL 9:ca2e6010d9e2 168 public:
QL 9:ca2e6010d9e2 169 QSignal sig; ///< signal of the event instance
QL 9:ca2e6010d9e2 170
QL 9:ca2e6010d9e2 171 QEvt(QSignal const s) // poolId_ intentionally uninitialized
QL 9:ca2e6010d9e2 172 : sig(s) {}
QL 9:ca2e6010d9e2 173
QL 9:ca2e6010d9e2 174 #ifdef Q_EVT_VIRTUAL
QL 9:ca2e6010d9e2 175 virtual ~QEvt() {} // virtual destructor
QL 9:ca2e6010d9e2 176 #endif
QL 9:ca2e6010d9e2 177
QL 9:ca2e6010d9e2 178 private:
QL 9:ca2e6010d9e2 179 uint8_t poolId_; ///< pool ID (0 for static event)
QL 9:ca2e6010d9e2 180 uint8_t refCtr_; ///< reference counter
QL 9:ca2e6010d9e2 181
QL 9:ca2e6010d9e2 182 friend class QF;
QL 9:ca2e6010d9e2 183 friend class QTimeEvt;
QL 9:ca2e6010d9e2 184 friend uint8_t QF_EVT_POOL_ID_ (QEvt const * const e);
QL 9:ca2e6010d9e2 185 friend uint8_t QF_EVT_REF_CTR_ (QEvt const * const e);
QL 9:ca2e6010d9e2 186 friend void QF_EVT_REF_CTR_INC_(QEvt const * const e);
QL 9:ca2e6010d9e2 187 friend void QF_EVT_REF_CTR_DEC_(QEvt const * const e);
QL 9:ca2e6010d9e2 188 };
QL 9:ca2e6010d9e2 189
QL 9:ca2e6010d9e2 190 #else // QEvt is a POD (Plain Old Datatype)
QL 9:ca2e6010d9e2 191
QL 9:ca2e6010d9e2 192 struct QEvt {
QL 9:ca2e6010d9e2 193 QSignal sig; ///< signal of the event instance
QL 9:ca2e6010d9e2 194 uint8_t poolId_; ///< pool ID (0 for static event)
QL 9:ca2e6010d9e2 195 uint8_t refCtr_; ///< reference counter
QL 9:ca2e6010d9e2 196 };
QL 9:ca2e6010d9e2 197
QL 9:ca2e6010d9e2 198 #endif // Q_EVT_CTOR
QL 9:ca2e6010d9e2 199
QL 9:ca2e6010d9e2 200 QP_END_
QL 9:ca2e6010d9e2 201
QL 9:ca2e6010d9e2 202 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 203 /// helper macro to calculate static dimension of a 1-dim array \a array_
QL 9:ca2e6010d9e2 204 #define Q_DIM(array_) (sizeof(array_) / sizeof(array_[0]))
QL 9:ca2e6010d9e2 205
QL 9:ca2e6010d9e2 206 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 207 // typedefs for basic numerical types; MISRA-C++ 2008 rule 3-9-2(req).
QL 9:ca2e6010d9e2 208
QL 9:ca2e6010d9e2 209 /// \brief typedef for character strings.
QL 9:ca2e6010d9e2 210 ///
QL 9:ca2e6010d9e2 211 /// This typedef specifies character type for exclusive use in character
QL 9:ca2e6010d9e2 212 /// strings. Use of this type, rather than plain 'char', is in compliance
QL 9:ca2e6010d9e2 213 /// with the MISRA-C 2004 Rules 6.1(req), 6.3(adv).
QL 9:ca2e6010d9e2 214 ///
QL 9:ca2e6010d9e2 215 typedef char char_t;
QL 9:ca2e6010d9e2 216
QL 9:ca2e6010d9e2 217 /// typedef for 32-bit IEEE 754 floating point numbers
QL 9:ca2e6010d9e2 218 typedef float float32_t;
QL 9:ca2e6010d9e2 219
QL 9:ca2e6010d9e2 220 /// typedef for 64-bit IEEE 754 floating point numbers
QL 9:ca2e6010d9e2 221 typedef double float64_t;
QL 9:ca2e6010d9e2 222
QL 9:ca2e6010d9e2 223 /// typedef for enumerations used for event signals
QL 9:ca2e6010d9e2 224 typedef int enum_t;
QL 9:ca2e6010d9e2 225
QL 9:ca2e6010d9e2 226 /// \brief Perform cast from unsigned integer \a uint_ to pointer
QL 9:ca2e6010d9e2 227 /// of type \a type_.
QL 9:ca2e6010d9e2 228 ///
QL 9:ca2e6010d9e2 229 /// This macro encapsulates the cast to (type_ *), which QP ports or
QL 9:ca2e6010d9e2 230 /// application might use to access embedded hardware registers.
QL 9:ca2e6010d9e2 231 /// Such uses can trigger PC-Lint "Note 923: cast from int to pointer"
QL 9:ca2e6010d9e2 232 /// and this macro helps to encapsulate this deviation.
QL 9:ca2e6010d9e2 233 ///
QL 9:ca2e6010d9e2 234 #define Q_UINT2PTR_CAST(type_, uint_) (reinterpret_cast<type_ *>(uint_))
QL 9:ca2e6010d9e2 235
QL 9:ca2e6010d9e2 236 /// \brief Initializer of static constant QEvt instances
QL 9:ca2e6010d9e2 237 ///
QL 9:ca2e6010d9e2 238 /// This macro encapsulates the ugly casting of enumerated signals
QL 9:ca2e6010d9e2 239 /// to QSignal and constants for QEvt.poolID and QEvt.refCtr_.
QL 9:ca2e6010d9e2 240 ///
QL 9:ca2e6010d9e2 241 #define QEVT_INITIALIZER(sig_) { static_cast<QP_ QSignal>(sig_), \
QL 9:ca2e6010d9e2 242 static_cast<uint8_t>(0), static_cast<uint8_t>(0) }
QL 9:ca2e6010d9e2 243
QL 9:ca2e6010d9e2 244 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 245 // facilities for backwards compatibility
QL 9:ca2e6010d9e2 246 //
QL 9:ca2e6010d9e2 247 #ifndef Q_NQEVENT
QL 9:ca2e6010d9e2 248 // typedef struct QEvt QEvent;
QL 9:ca2e6010d9e2 249 #define QEvent QEvt
QL 9:ca2e6010d9e2 250 #endif
QL 9:ca2e6010d9e2 251
QL 9:ca2e6010d9e2 252
QL 9:ca2e6010d9e2 253 // "qep.h" ===================================================================
QL 9:ca2e6010d9e2 254 /// \brief QEP/C++ platform-independent public interface.
QL 9:ca2e6010d9e2 255 ///
QL 9:ca2e6010d9e2 256 /// This header file must be included directly or indirectly
QL 9:ca2e6010d9e2 257 /// in all modules (*.cpp files) that use QEP/C++.
QL 9:ca2e6010d9e2 258
QL 9:ca2e6010d9e2 259 /// \brief Designates a target for an initial or regular transition.
QL 9:ca2e6010d9e2 260 /// Q_TRAN() can be used both in the FSMs and HSMs.
QL 9:ca2e6010d9e2 261 ///
QL 9:ca2e6010d9e2 262 /// \include qep_qtran.c
QL 9:ca2e6010d9e2 263 ///
QL 9:ca2e6010d9e2 264 #define Q_TRAN(target_) (me->tran(Q_STATE_CAST(target_)))
QL 9:ca2e6010d9e2 265
QL 9:ca2e6010d9e2 266 /// \brief Designates the superstate of a given state in an HSM.
QL 9:ca2e6010d9e2 267 ///
QL 9:ca2e6010d9e2 268 /// \include qep_qhsm.c
QL 9:ca2e6010d9e2 269 ///
QL 9:ca2e6010d9e2 270 #define Q_SUPER(super_) (me->super(Q_STATE_CAST(super_)))
QL 9:ca2e6010d9e2 271
QL 9:ca2e6010d9e2 272 /// \brief Perform cast to QStateHandler.
QL 9:ca2e6010d9e2 273 ///
QL 9:ca2e6010d9e2 274 /// This macro encapsulates the cast of a specific state handler function
QL 9:ca2e6010d9e2 275 /// pointer to QStateHandler, which violates MISRA-C 2004 rule 11.4(advisory).
QL 9:ca2e6010d9e2 276 /// This macro helps to localize this deviation.
QL 9:ca2e6010d9e2 277 ///
QL 9:ca2e6010d9e2 278 #define Q_STATE_CAST(handler_) \
QL 9:ca2e6010d9e2 279 (reinterpret_cast<QP_ QStateHandler>(handler_))
QL 9:ca2e6010d9e2 280
QL 9:ca2e6010d9e2 281 /// \brief Perform downcast of an event onto a subclass of QEvt \a class_
QL 9:ca2e6010d9e2 282 ///
QL 9:ca2e6010d9e2 283 /// This macro encapsulates the downcast of QEvt pointers, which violates
QL 9:ca2e6010d9e2 284 /// MISRA-C 2004 rule 11.4(advisory). This macro helps to localize this
QL 9:ca2e6010d9e2 285 /// deviation.
QL 9:ca2e6010d9e2 286 ///
QL 9:ca2e6010d9e2 287 #define Q_EVT_CAST(class_) (static_cast<class_ const *>(e))
QL 9:ca2e6010d9e2 288
QL 9:ca2e6010d9e2 289 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 290 QP_BEGIN_
QL 9:ca2e6010d9e2 291
QL 9:ca2e6010d9e2 292 /// \brief Provides miscellaneous QEP services.
QL 9:ca2e6010d9e2 293 class QEP {
QL 9:ca2e6010d9e2 294 public:
QL 9:ca2e6010d9e2 295 /// \brief get the current QEP version number string
QL 9:ca2e6010d9e2 296 ///
QL 9:ca2e6010d9e2 297 /// \return version of the QEP as a constant 6-character string of the
QL 9:ca2e6010d9e2 298 /// form x.y.zz, where x is a 1-digit major version number, y is a
QL 9:ca2e6010d9e2 299 /// 1-digit minor version number, and zz is a 2-digit release number.
QL 9:ca2e6010d9e2 300 static char_t const Q_ROM * Q_ROM_VAR getVersion(void);
QL 9:ca2e6010d9e2 301 };
QL 9:ca2e6010d9e2 302
QL 9:ca2e6010d9e2 303 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 304
QL 9:ca2e6010d9e2 305 /// \brief Type returned from a state-handler function
QL 9:ca2e6010d9e2 306 typedef uint8_t QState;
QL 9:ca2e6010d9e2 307 /// \brief pointer to state-handler function
QL 9:ca2e6010d9e2 308 typedef QState (*QStateHandler)(void * const me, QEvt const * const e);
QL 9:ca2e6010d9e2 309
QL 9:ca2e6010d9e2 310 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 311 /// \brief Value returned by a state-handler function when it handles
QL 9:ca2e6010d9e2 312 /// the event.
QL 9:ca2e6010d9e2 313 QState const Q_RET_HANDLED = static_cast<QState>(0);
QL 9:ca2e6010d9e2 314
QL 9:ca2e6010d9e2 315 /// \brief Value returned by a non-hierarchical state-handler function when
QL 9:ca2e6010d9e2 316 /// it ignores (does not handle) the event.
QL 9:ca2e6010d9e2 317 QState const Q_RET_IGNORED = static_cast<QState>(1);
QL 9:ca2e6010d9e2 318
QL 9:ca2e6010d9e2 319 /// \brief Value returned by a state-handler function when it takes a
QL 9:ca2e6010d9e2 320 /// regular state transition.
QL 9:ca2e6010d9e2 321 QState const Q_RET_TRAN = static_cast<QState>(2);
QL 9:ca2e6010d9e2 322
QL 9:ca2e6010d9e2 323 /// \brief Value returned by a state-handler function when it forwards
QL 9:ca2e6010d9e2 324 /// the event to the superstate to handle.
QL 9:ca2e6010d9e2 325 QState const Q_RET_SUPER = static_cast<QState>(3);
QL 9:ca2e6010d9e2 326
QL 9:ca2e6010d9e2 327 /// \brief Value returned by a state-handler function when a guard
QL 9:ca2e6010d9e2 328 /// condition prevents it from handling the event.
QL 9:ca2e6010d9e2 329 ///
QL 9:ca2e6010d9e2 330 QState const Q_RET_UNHANDLED = static_cast<QState>(4);
QL 9:ca2e6010d9e2 331
QL 9:ca2e6010d9e2 332
QL 9:ca2e6010d9e2 333 /// Offset or the user signals
QL 9:ca2e6010d9e2 334 enum_t const Q_USER_SIG = static_cast<enum_t>(4);
QL 9:ca2e6010d9e2 335
QL 9:ca2e6010d9e2 336
QL 9:ca2e6010d9e2 337 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 338 /// \brief Finite State Machine base class
QL 9:ca2e6010d9e2 339 ///
QL 9:ca2e6010d9e2 340 /// QFsm represents a traditional non-hierarchical Finite State Machine (FSM)
QL 9:ca2e6010d9e2 341 /// without state hierarchy, but with entry/exit actions.
QL 9:ca2e6010d9e2 342 ///
QL 9:ca2e6010d9e2 343 /// QFsm is also a base structure for the ::QHsm class.
QL 9:ca2e6010d9e2 344 ///
QL 9:ca2e6010d9e2 345 /// \note QFsm is not intended to be instantiated directly, but rather serves
QL 9:ca2e6010d9e2 346 /// as the base class for derivation of state machines in the application
QL 9:ca2e6010d9e2 347 /// code.
QL 9:ca2e6010d9e2 348 ///
QL 9:ca2e6010d9e2 349 /// The following example illustrates how to derive a state machine class
QL 9:ca2e6010d9e2 350 /// from QFsm.
QL 9:ca2e6010d9e2 351 /// \include qep_qfsm.cpp
QL 9:ca2e6010d9e2 352 class QFsm {
QL 9:ca2e6010d9e2 353 private:
QL 9:ca2e6010d9e2 354 QStateHandler m_state; ///< current active state (state-variable)
QL 9:ca2e6010d9e2 355 QStateHandler m_temp; ///< temporary state: target of tran. or superstate
QL 9:ca2e6010d9e2 356
QL 9:ca2e6010d9e2 357 public:
QL 9:ca2e6010d9e2 358 /// \brief virtual destructor
QL 9:ca2e6010d9e2 359 virtual ~QFsm();
QL 9:ca2e6010d9e2 360
QL 9:ca2e6010d9e2 361 /// \brief Performs the second step of FSM initialization by triggering
QL 9:ca2e6010d9e2 362 /// the top-most initial transition.
QL 9:ca2e6010d9e2 363 ///
QL 9:ca2e6010d9e2 364 /// The argument \a e is constant pointer to ::QEvt or a class
QL 9:ca2e6010d9e2 365 /// derived from ::QEvt.
QL 9:ca2e6010d9e2 366 ///
QL 9:ca2e6010d9e2 367 /// \note Must be called only ONCE before QFsm::dispatch()
QL 9:ca2e6010d9e2 368 ///
QL 9:ca2e6010d9e2 369 /// The following example illustrates how to initialize a FSM, and
QL 9:ca2e6010d9e2 370 /// dispatch events to it:
QL 9:ca2e6010d9e2 371 /// \include qep_qfsm_use.cpp
QL 9:ca2e6010d9e2 372 void init(QEvt const * const e = static_cast<QEvt const *>(0));
QL 9:ca2e6010d9e2 373
QL 9:ca2e6010d9e2 374 /// \brief Dispatches an event to a FSM
QL 9:ca2e6010d9e2 375 ///
QL 9:ca2e6010d9e2 376 /// Processes one event at a time in Run-to-Completion (RTC) fashion.
QL 9:ca2e6010d9e2 377 /// The argument \a e is a constant pointer the ::QEvt or a
QL 9:ca2e6010d9e2 378 /// class derived from ::QEvt.
QL 9:ca2e6010d9e2 379 ///
QL 9:ca2e6010d9e2 380 /// \note Must be called after QFsm::init().
QL 9:ca2e6010d9e2 381 ///
QL 9:ca2e6010d9e2 382 /// \sa example for QFsm::init()
QL 9:ca2e6010d9e2 383 void dispatch(QEvt const * const e);
QL 9:ca2e6010d9e2 384
QL 9:ca2e6010d9e2 385 protected:
QL 9:ca2e6010d9e2 386 /// \brief Protected constructor of a FSM.
QL 9:ca2e6010d9e2 387 ///
QL 9:ca2e6010d9e2 388 /// Performs the first step of FSM initialization by assigning the
QL 9:ca2e6010d9e2 389 /// initial pseudostate to the currently active state of the state
QL 9:ca2e6010d9e2 390 /// machine.
QL 9:ca2e6010d9e2 391 ///
QL 9:ca2e6010d9e2 392 /// \note The constructor is protected to prevent direct instantiating
QL 9:ca2e6010d9e2 393 /// of QFsm objects. This class is intended for subclassing only.
QL 9:ca2e6010d9e2 394 ///
QL 9:ca2e6010d9e2 395 /// \sa The ::QFsm example illustrates how to use the QHsm constructor
QL 9:ca2e6010d9e2 396 /// in the constructor initializer list of the derived state machines.
QL 9:ca2e6010d9e2 397 QFsm(QStateHandler const initial)
QL 9:ca2e6010d9e2 398 : m_state(Q_STATE_CAST(0)),
QL 9:ca2e6010d9e2 399 m_temp(initial)
QL 9:ca2e6010d9e2 400 {}
QL 9:ca2e6010d9e2 401
QL 9:ca2e6010d9e2 402 /// \brief Return the current active state.
QL 9:ca2e6010d9e2 403 QStateHandler state(void) const {
QL 9:ca2e6010d9e2 404 return m_state;
QL 9:ca2e6010d9e2 405 }
QL 9:ca2e6010d9e2 406
QL 9:ca2e6010d9e2 407 /// \brief Inline function to specify the return of a state-handler
QL 9:ca2e6010d9e2 408 /// when it igonres (does not handle in any way) the event.
QL 9:ca2e6010d9e2 409 static QState Q_IGNORED(void) { return Q_RET_IGNORED; }
QL 9:ca2e6010d9e2 410
QL 9:ca2e6010d9e2 411 /// \brief Inline function to specify the return of a state-handler
QL 9:ca2e6010d9e2 412 /// when it handles the event.
QL 9:ca2e6010d9e2 413 ///
QL 9:ca2e6010d9e2 414 /// \include qep_qhsm.cpp
QL 9:ca2e6010d9e2 415 static QState Q_HANDLED(void) { return Q_RET_HANDLED; }
QL 9:ca2e6010d9e2 416
QL 9:ca2e6010d9e2 417 /// \brief Macro to specify the return of a state-handler function when
QL 9:ca2e6010d9e2 418 /// it attempts to handle the event but a guard condition evaluates to
QL 9:ca2e6010d9e2 419 /// false and there is no other explicit way of handling the event.
QL 9:ca2e6010d9e2 420 static QState Q_UNHANDLED(void) { return Q_RET_UNHANDLED; }
QL 9:ca2e6010d9e2 421
QL 9:ca2e6010d9e2 422 /// \brief internal helper function to record a state transition
QL 9:ca2e6010d9e2 423 QState tran(QStateHandler const target) {
QL 9:ca2e6010d9e2 424 m_temp = target;
QL 9:ca2e6010d9e2 425 return Q_RET_TRAN;
QL 9:ca2e6010d9e2 426 }
QL 9:ca2e6010d9e2 427
QL 9:ca2e6010d9e2 428 enum ReservedFsmSignals {
QL 9:ca2e6010d9e2 429 Q_ENTRY_SIG = 1, ///< signal for entry actions
QL 9:ca2e6010d9e2 430 Q_EXIT_SIG ///< signal for exit actions
QL 9:ca2e6010d9e2 431 };
QL 9:ca2e6010d9e2 432 };
QL 9:ca2e6010d9e2 433
QL 9:ca2e6010d9e2 434 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 435 /// \brief Hierarchical State Machine base class
QL 9:ca2e6010d9e2 436 ///
QL 9:ca2e6010d9e2 437 /// QHsm represents a Hierarchical Finite State Machine (HSM). QHsm derives
QL 9:ca2e6010d9e2 438 /// from the ::QFsm class and extends the capabilities of a basic FSM
QL 9:ca2e6010d9e2 439 /// with state hierarchy.
QL 9:ca2e6010d9e2 440 ///
QL 9:ca2e6010d9e2 441 /// \note QHsm is not intended to be instantiated directly, but rather serves
QL 9:ca2e6010d9e2 442 /// as the base structure for derivation of state machines in the application
QL 9:ca2e6010d9e2 443 /// code.
QL 9:ca2e6010d9e2 444 ///
QL 9:ca2e6010d9e2 445 /// The following example illustrates how to derive a state machine class
QL 9:ca2e6010d9e2 446 /// from QHsm.
QL 9:ca2e6010d9e2 447 /// \include qep_qhsm.cpp
QL 9:ca2e6010d9e2 448 class QHsm {
QL 9:ca2e6010d9e2 449 private:
QL 9:ca2e6010d9e2 450 QStateHandler m_state; ///< current active state (state-variable)
QL 9:ca2e6010d9e2 451 QStateHandler m_temp; ///< temporary state: target of tran. or superstate
QL 9:ca2e6010d9e2 452
QL 9:ca2e6010d9e2 453 public:
QL 9:ca2e6010d9e2 454 /// \brief virtual destructor
QL 9:ca2e6010d9e2 455 virtual ~QHsm();
QL 9:ca2e6010d9e2 456
QL 9:ca2e6010d9e2 457 /// \brief Performs the second step of HSM initialization by triggering
QL 9:ca2e6010d9e2 458 /// the top-most initial transition.
QL 9:ca2e6010d9e2 459 ///
QL 9:ca2e6010d9e2 460 /// \param e constant pointer ::QEvt or a class derived from ::QEvt
QL 9:ca2e6010d9e2 461 /// \note Must be called only ONCE before QHsm::dispatch()
QL 9:ca2e6010d9e2 462 ///
QL 9:ca2e6010d9e2 463 /// The following example illustrates how to initialize a HSM, and
QL 9:ca2e6010d9e2 464 /// dispatch events to it:
QL 9:ca2e6010d9e2 465 /// \include qep_qhsm_use.cpp
QL 9:ca2e6010d9e2 466 void init(QEvt const * const e = static_cast<QEvt const *>(0));
QL 9:ca2e6010d9e2 467
QL 9:ca2e6010d9e2 468 /// \brief Dispatches an event to a HSM
QL 9:ca2e6010d9e2 469 ///
QL 9:ca2e6010d9e2 470 /// Processes one event at a time in Run-to-Completion (RTC) fashion.
QL 9:ca2e6010d9e2 471 /// The argument \a e is a constant pointer the ::QEvt or a
QL 9:ca2e6010d9e2 472 /// class derived from ::QEvt.
QL 9:ca2e6010d9e2 473 ///
QL 9:ca2e6010d9e2 474 /// \note Must be called after QHsm::init().
QL 9:ca2e6010d9e2 475 ///
QL 9:ca2e6010d9e2 476 /// \sa example for QHsm::init()
QL 9:ca2e6010d9e2 477 void dispatch(QEvt const * const e);
QL 9:ca2e6010d9e2 478
QL 9:ca2e6010d9e2 479 /// \brief Tests if a given state is part of the current active state
QL 9:ca2e6010d9e2 480 /// configuratioin
QL 9:ca2e6010d9e2 481 ///
QL 9:ca2e6010d9e2 482 /// \param state is a pointer to the state handler function, e.g.,
QL 9:ca2e6010d9e2 483 /// &QCalc::on.
QL 9:ca2e6010d9e2 484 bool isIn(QStateHandler const s);
QL 9:ca2e6010d9e2 485
QL 9:ca2e6010d9e2 486 protected:
QL 9:ca2e6010d9e2 487 /// \brief Protected constructor of a HSM.
QL 9:ca2e6010d9e2 488 ///
QL 9:ca2e6010d9e2 489 /// Performs the first step of HSM initialization by assigning the
QL 9:ca2e6010d9e2 490 /// initial pseudostate to the currently active state of the state
QL 9:ca2e6010d9e2 491 /// machine.
QL 9:ca2e6010d9e2 492 ///
QL 9:ca2e6010d9e2 493 /// \note The constructor is protected to prevent direct instantiating
QL 9:ca2e6010d9e2 494 /// of QHsm objects. This class is intended for subclassing only.
QL 9:ca2e6010d9e2 495 ///
QL 9:ca2e6010d9e2 496 /// \sa The ::QHsm example illustrates how to use the QHsm constructor
QL 9:ca2e6010d9e2 497 /// in the constructor initializer list of the derived state machines.
QL 9:ca2e6010d9e2 498 /// \sa QFsm::QFsm()
QL 9:ca2e6010d9e2 499 QHsm(QStateHandler const initial)
QL 9:ca2e6010d9e2 500 : m_state(Q_STATE_CAST(&QHsm::top)),
QL 9:ca2e6010d9e2 501 m_temp(initial)
QL 9:ca2e6010d9e2 502 {}
QL 9:ca2e6010d9e2 503
QL 9:ca2e6010d9e2 504 /// \brief Return the current active state.
QL 9:ca2e6010d9e2 505 QStateHandler state(void) const {
QL 9:ca2e6010d9e2 506 return m_state;
QL 9:ca2e6010d9e2 507 }
QL 9:ca2e6010d9e2 508
QL 9:ca2e6010d9e2 509 /// \brief the top-state.
QL 9:ca2e6010d9e2 510 ///
QL 9:ca2e6010d9e2 511 /// QHsm::top() is the ultimate root of state hierarchy in all HSMs
QL 9:ca2e6010d9e2 512 /// derived from ::QHsm. This state handler always returns (QSTATE)0,
QL 9:ca2e6010d9e2 513 /// which means that it "handles" all events.
QL 9:ca2e6010d9e2 514 ///
QL 9:ca2e6010d9e2 515 /// \sa Example of the QCalc::on() state handler.
QL 9:ca2e6010d9e2 516 static QState top(void * const me, QEvt const * const e);
QL 9:ca2e6010d9e2 517
QL 9:ca2e6010d9e2 518 /// \brief Inline function to specify the return of a state-handler
QL 9:ca2e6010d9e2 519 /// when it handles the event.
QL 9:ca2e6010d9e2 520 ///
QL 9:ca2e6010d9e2 521 /// \include qep_qhsm.cpp
QL 9:ca2e6010d9e2 522 static QState Q_HANDLED(void) { return Q_RET_HANDLED; }
QL 9:ca2e6010d9e2 523
QL 9:ca2e6010d9e2 524 /// \brief Macro to specify the return of a state-handler function when
QL 9:ca2e6010d9e2 525 /// it attempts to handle the event but a guard condition evaluates to
QL 9:ca2e6010d9e2 526 /// false and there is no other explicit way of handling the event.
QL 9:ca2e6010d9e2 527 static QState Q_UNHANDLED(void) { return Q_RET_UNHANDLED; }
QL 9:ca2e6010d9e2 528
QL 9:ca2e6010d9e2 529 /// \brief internal helper function to record a state transition
QL 9:ca2e6010d9e2 530 QState tran(QStateHandler const target) {
QL 9:ca2e6010d9e2 531 m_temp = target;
QL 9:ca2e6010d9e2 532 return Q_RET_TRAN;
QL 9:ca2e6010d9e2 533 }
QL 9:ca2e6010d9e2 534
QL 9:ca2e6010d9e2 535 /// \brief internal helper function to record the superstate
QL 9:ca2e6010d9e2 536 QState super(QStateHandler const superstate) {
QL 9:ca2e6010d9e2 537 m_temp = superstate;
QL 9:ca2e6010d9e2 538 return Q_RET_SUPER;
QL 9:ca2e6010d9e2 539 }
QL 9:ca2e6010d9e2 540
QL 9:ca2e6010d9e2 541 enum ReservedHsmSignals {
QL 9:ca2e6010d9e2 542 Q_ENTRY_SIG = 1, ///< signal for entry actions
QL 9:ca2e6010d9e2 543 Q_EXIT_SIG, ///< signal for exit actions
QL 9:ca2e6010d9e2 544 Q_INIT_SIG ///< signal for nested initial transitions
QL 9:ca2e6010d9e2 545 };
QL 9:ca2e6010d9e2 546 };
QL 9:ca2e6010d9e2 547
QL 9:ca2e6010d9e2 548 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 549
QL 9:ca2e6010d9e2 550 QP_END_
QL 9:ca2e6010d9e2 551
QL 9:ca2e6010d9e2 552 // "qequeue.h" ===============================================================
QL 9:ca2e6010d9e2 553 /// \brief platform-independent event queue interface.
QL 9:ca2e6010d9e2 554 ///
QL 9:ca2e6010d9e2 555 /// This header file must be included in all QF ports that use native QF
QL 9:ca2e6010d9e2 556 /// event queue implementation. Also, this file is needed when the "raw"
QL 9:ca2e6010d9e2 557 /// thread-safe queues are used for communication between active objects
QL 9:ca2e6010d9e2 558 /// and non-framework entities, such as ISRs, device drivers, or legacy
QL 9:ca2e6010d9e2 559 /// code.
QL 9:ca2e6010d9e2 560
QL 9:ca2e6010d9e2 561 #ifndef QF_EQUEUE_CTR_SIZE
QL 9:ca2e6010d9e2 562
QL 9:ca2e6010d9e2 563 /// \brief The size (in bytes) of the ring-buffer counters used in the
QL 9:ca2e6010d9e2 564 /// native QF event queue implementation. Valid values: 1, 2, or 4;
QL 9:ca2e6010d9e2 565 /// default 1.
QL 9:ca2e6010d9e2 566 ///
QL 9:ca2e6010d9e2 567 /// This macro can be defined in the QF port file (qf_port.h) to
QL 9:ca2e6010d9e2 568 /// configure the ::QEQueueCtr type. Here the macro is not defined so the
QL 9:ca2e6010d9e2 569 /// default of 1 byte is chosen.
QL 9:ca2e6010d9e2 570 #define QF_EQUEUE_CTR_SIZE 1
QL 9:ca2e6010d9e2 571 #endif
QL 9:ca2e6010d9e2 572
QL 9:ca2e6010d9e2 573 QP_BEGIN_
QL 9:ca2e6010d9e2 574
QL 9:ca2e6010d9e2 575 #if (QF_EQUEUE_CTR_SIZE == 1)
QL 9:ca2e6010d9e2 576 /// \brief The data type to store the ring-buffer counters based on
QL 9:ca2e6010d9e2 577 /// the macro #QF_EQUEUE_CTR_SIZE.
QL 9:ca2e6010d9e2 578 ///
QL 9:ca2e6010d9e2 579 /// The dynamic range of this data type determines the maximum length
QL 9:ca2e6010d9e2 580 /// of the ring buffer managed by the native QF event queue.
QL 9:ca2e6010d9e2 581 typedef uint8_t QEQueueCtr;
QL 9:ca2e6010d9e2 582 #elif (QF_EQUEUE_CTR_SIZE == 2)
QL 9:ca2e6010d9e2 583 typedef uint16_t QEQueueCtr;
QL 9:ca2e6010d9e2 584 #elif (QF_EQUEUE_CTR_SIZE == 4)
QL 9:ca2e6010d9e2 585 typedef uint32_t QEQueueCtr;
QL 9:ca2e6010d9e2 586 #else
QL 9:ca2e6010d9e2 587 #error "QF_EQUEUE_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 588 #endif
QL 9:ca2e6010d9e2 589
QL 9:ca2e6010d9e2 590
QL 9:ca2e6010d9e2 591 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 592 /// \brief Native QF Event Queue class
QL 9:ca2e6010d9e2 593 ///
QL 9:ca2e6010d9e2 594 /// This structure describes the native QF event queue, which can be used as
QL 9:ca2e6010d9e2 595 /// the event queue for active objects, or as a simple "raw" event queue for
QL 9:ca2e6010d9e2 596 /// thread-safe event passing among non-framework entities, such as ISRs,
QL 9:ca2e6010d9e2 597 /// device drivers, or other third-party components.
QL 9:ca2e6010d9e2 598 ///
QL 9:ca2e6010d9e2 599 /// The native QF event queue is configured by defining the macro
QL 9:ca2e6010d9e2 600 /// #QF_EQUEUE_TYPE as ::QEQueue in the specific QF port header file.
QL 9:ca2e6010d9e2 601 ///
QL 9:ca2e6010d9e2 602 /// The ::QEQueue structure contains only data members for managing an event
QL 9:ca2e6010d9e2 603 /// queue, but does not contain the storage for the queue buffer, which must
QL 9:ca2e6010d9e2 604 /// be provided externally during the queue initialization.
QL 9:ca2e6010d9e2 605 ///
QL 9:ca2e6010d9e2 606 /// The event queue can store only event pointers, not the whole events. The
QL 9:ca2e6010d9e2 607 /// internal implementation uses the standard ring-buffer plus one external
QL 9:ca2e6010d9e2 608 /// location that optimizes the queue operation for the most frequent case
QL 9:ca2e6010d9e2 609 /// of empty queue.
QL 9:ca2e6010d9e2 610 ///
QL 9:ca2e6010d9e2 611 /// The ::QEQueue structure is used with two sets of functions. One set is for
QL 9:ca2e6010d9e2 612 /// the active object event queue, which needs to block the active object
QL 9:ca2e6010d9e2 613 /// task when the event queue is empty and unblock it when events are posted
QL 9:ca2e6010d9e2 614 /// to the queue. The interface for the native active object event queue
QL 9:ca2e6010d9e2 615 /// consists of the following functions: QActive::postFIFO_(),
QL 9:ca2e6010d9e2 616 /// QActive::postLIFO_(), and QActive::get_(). Additionally the function
QL 9:ca2e6010d9e2 617 /// QEQueue_init() is used to initialize the queue.
QL 9:ca2e6010d9e2 618 ///
QL 9:ca2e6010d9e2 619 /// The other set of functions, uses this structure as a simple "raw" event
QL 9:ca2e6010d9e2 620 /// queue to pass events between entities other than active objects, such as
QL 9:ca2e6010d9e2 621 /// ISRs. The "raw" event queue is not capable of blocking on the get()
QL 9:ca2e6010d9e2 622 /// operation, but is still thread-safe because it uses QF critical section
QL 9:ca2e6010d9e2 623 /// to protect its integrity. The interface for the "raw" thread-safe queue
QL 9:ca2e6010d9e2 624 /// consists of the following functions: QEQueue::postFIFO(),
QL 9:ca2e6010d9e2 625 /// QEQueue::postLIFO(), and QEQueue::get(). Additionally the function
QL 9:ca2e6010d9e2 626 /// QEQueue::init() is used to initialize the queue.
QL 9:ca2e6010d9e2 627 ///
QL 9:ca2e6010d9e2 628 /// \note Most event queue operations (both the active object queues and
QL 9:ca2e6010d9e2 629 /// the "raw" queues) internally use the QF critical section. You should be
QL 9:ca2e6010d9e2 630 /// careful not to invoke those operations from other critical sections when
QL 9:ca2e6010d9e2 631 /// nesting of critical sections is not supported.
QL 9:ca2e6010d9e2 632 class QEQueue {
QL 9:ca2e6010d9e2 633 private:
QL 9:ca2e6010d9e2 634
QL 9:ca2e6010d9e2 635 /// \brief pointer to event at the front of the queue
QL 9:ca2e6010d9e2 636 ///
QL 9:ca2e6010d9e2 637 /// All incoming and outgoing events pass through the m_frontEvt location.
QL 9:ca2e6010d9e2 638 /// When the queue is empty (which is most of the time), the extra
QL 9:ca2e6010d9e2 639 /// m_frontEvt location allows to bypass the ring buffer altogether,
QL 9:ca2e6010d9e2 640 /// greatly optimizing the performance of the queue. Only bursts of events
QL 9:ca2e6010d9e2 641 /// engage the ring buffer.
QL 9:ca2e6010d9e2 642 ///
QL 9:ca2e6010d9e2 643 /// The additional role of this attribute is to indicate the empty status
QL 9:ca2e6010d9e2 644 /// of the queue. The queue is empty if the m_frontEvt location is NULL.
QL 9:ca2e6010d9e2 645 QEvt const *m_frontEvt;
QL 9:ca2e6010d9e2 646
QL 9:ca2e6010d9e2 647 /// \brief pointer to the start of the ring buffer
QL 9:ca2e6010d9e2 648 QEvt const **m_ring;
QL 9:ca2e6010d9e2 649
QL 9:ca2e6010d9e2 650 /// \brief offset of the end of the ring buffer from the start of the
QL 9:ca2e6010d9e2 651 /// buffer m_ring
QL 9:ca2e6010d9e2 652 QEQueueCtr m_end;
QL 9:ca2e6010d9e2 653
QL 9:ca2e6010d9e2 654 /// \brief offset to where next event will be inserted into the buffer
QL 9:ca2e6010d9e2 655 QEQueueCtr m_head;
QL 9:ca2e6010d9e2 656
QL 9:ca2e6010d9e2 657 /// \brief offset of where next event will be extracted from the buffer
QL 9:ca2e6010d9e2 658 QEQueueCtr m_tail;
QL 9:ca2e6010d9e2 659
QL 9:ca2e6010d9e2 660 /// \brief number of free events in the ring buffer
QL 9:ca2e6010d9e2 661 QEQueueCtr m_nFree;
QL 9:ca2e6010d9e2 662
QL 9:ca2e6010d9e2 663 /// \brief minimum number of free events ever in the ring buffer.
QL 9:ca2e6010d9e2 664 ///
QL 9:ca2e6010d9e2 665 /// \note this attribute remembers the low-watermark of the ring buffer,
QL 9:ca2e6010d9e2 666 /// which provides a valuable information for sizing event queues.
QL 9:ca2e6010d9e2 667 /// \sa QF::getQueueMargin().
QL 9:ca2e6010d9e2 668 QEQueueCtr m_nMin;
QL 9:ca2e6010d9e2 669
QL 9:ca2e6010d9e2 670 public:
QL 9:ca2e6010d9e2 671
QL 9:ca2e6010d9e2 672 /// \brief Initializes the native QF event queue
QL 9:ca2e6010d9e2 673 ///
QL 9:ca2e6010d9e2 674 /// The parameters are as follows: \a qSto[] is the ring buffer storage,
QL 9:ca2e6010d9e2 675 /// \a qLen is the length of the ring buffer in the units of event-
QL 9:ca2e6010d9e2 676 /// pointers.
QL 9:ca2e6010d9e2 677 ///
QL 9:ca2e6010d9e2 678 /// \note The actual capacity of the queue is qLen + 1, because of the
QL 9:ca2e6010d9e2 679 /// extra location fornEvt_.
QL 9:ca2e6010d9e2 680 void init(QEvt const *qSto[], QEQueueCtr const qLen);
QL 9:ca2e6010d9e2 681
QL 9:ca2e6010d9e2 682 /// \brief "raw" thread-safe QF event queue implementation for the
QL 9:ca2e6010d9e2 683 /// First-In-First-Out (FIFO) event posting. You can call this function
QL 9:ca2e6010d9e2 684 /// from any task context or ISR context. Please note that this function
QL 9:ca2e6010d9e2 685 /// uses internally a critical section.
QL 9:ca2e6010d9e2 686 ///
QL 9:ca2e6010d9e2 687 /// \note The function raises an assertion if the native QF queue becomes
QL 9:ca2e6010d9e2 688 /// full and cannot accept the event.
QL 9:ca2e6010d9e2 689 ///
QL 9:ca2e6010d9e2 690 /// \sa QEQueue::postLIFO(), QEQueue::get()
QL 9:ca2e6010d9e2 691 void postFIFO(QEvt const * const e);
QL 9:ca2e6010d9e2 692
QL 9:ca2e6010d9e2 693 /// \brief "raw" thread-safe QF event queue implementation for the
QL 9:ca2e6010d9e2 694 /// First-In-First-Out (FIFO) event posting. You can call this function
QL 9:ca2e6010d9e2 695 /// from any task context or ISR context. Please note that this function
QL 9:ca2e6010d9e2 696 /// uses internally a critical section.
QL 9:ca2e6010d9e2 697 ///
QL 9:ca2e6010d9e2 698 /// \note The function raises an assertion if the native QF queue becomes
QL 9:ca2e6010d9e2 699 /// full and cannot accept the event.
QL 9:ca2e6010d9e2 700 ///
QL 9:ca2e6010d9e2 701 /// \sa QEQueue::postLIFO(), QEQueue::get()
QL 9:ca2e6010d9e2 702 void postLIFO(QEvt const * const e);
QL 9:ca2e6010d9e2 703
QL 9:ca2e6010d9e2 704 /// \brief "raw" thread-safe QF event queue implementation for the
QL 9:ca2e6010d9e2 705 /// Last-In-First-Out (LIFO) event posting.
QL 9:ca2e6010d9e2 706 ///
QL 9:ca2e6010d9e2 707 /// \note The LIFO policy should be used only with great caution because
QL 9:ca2e6010d9e2 708 /// it alters order of events in the queue.
QL 9:ca2e6010d9e2 709 /// \note The function raises an assertion if the native QF queue becomes
QL 9:ca2e6010d9e2 710 /// full and cannot accept the event. You can call this function from
QL 9:ca2e6010d9e2 711 /// any task context or ISR context. Please note that this function uses
QL 9:ca2e6010d9e2 712 /// internally a critical section.
QL 9:ca2e6010d9e2 713 ///
QL 9:ca2e6010d9e2 714 /// \sa QEQueue::postFIFO(), QEQueue::get()
QL 9:ca2e6010d9e2 715 QEvt const *get(void);
QL 9:ca2e6010d9e2 716
QL 9:ca2e6010d9e2 717 /// \brief "raw" thread-safe QF event queue operation for
QL 9:ca2e6010d9e2 718 /// obtaining the number of free entries still available in the queue.
QL 9:ca2e6010d9e2 719 ///
QL 9:ca2e6010d9e2 720 /// \note This operation needs to be used with caution because the
QL 9:ca2e6010d9e2 721 /// number of free entries can change unexpectedly. The main intent for
QL 9:ca2e6010d9e2 722 /// using this operation is in conjunction with event deferral. In this
QL 9:ca2e6010d9e2 723 /// case the queue is accessed only from a single thread (by a single AO),
QL 9:ca2e6010d9e2 724 /// so the number of free entries cannot change unexpectedly.
QL 9:ca2e6010d9e2 725 ///
QL 9:ca2e6010d9e2 726 /// \sa QActive::defer(), QActive::recall()
QL 9:ca2e6010d9e2 727 QEQueueCtr getNFree(void) const {
QL 9:ca2e6010d9e2 728 return m_nFree;
QL 9:ca2e6010d9e2 729 }
QL 9:ca2e6010d9e2 730
QL 9:ca2e6010d9e2 731 private:
QL 9:ca2e6010d9e2 732 friend class QF;
QL 9:ca2e6010d9e2 733 friend class QActive;
QL 9:ca2e6010d9e2 734 };
QL 9:ca2e6010d9e2 735
QL 9:ca2e6010d9e2 736 QP_END_
QL 9:ca2e6010d9e2 737
QL 9:ca2e6010d9e2 738 // "qmpool.h" ================================================================
QL 9:ca2e6010d9e2 739 /// \brief platform-independent memory pool interface.
QL 9:ca2e6010d9e2 740 ///
QL 9:ca2e6010d9e2 741 /// This header file must be included in all QF ports that use native QF
QL 9:ca2e6010d9e2 742 /// memory pool implementation.
QL 9:ca2e6010d9e2 743
QL 9:ca2e6010d9e2 744 #ifndef QF_MPOOL_SIZ_SIZE
QL 9:ca2e6010d9e2 745 /// \brief macro to override the default ::QMPoolSize size.
QL 9:ca2e6010d9e2 746 /// Valid values 1, 2, or 4; default 2
QL 9:ca2e6010d9e2 747 #define QF_MPOOL_SIZ_SIZE 2
QL 9:ca2e6010d9e2 748 #endif
QL 9:ca2e6010d9e2 749
QL 9:ca2e6010d9e2 750 #ifndef QF_MPOOL_CTR_SIZE
QL 9:ca2e6010d9e2 751
QL 9:ca2e6010d9e2 752 /// \brief macro to override the default QMPoolCtr size.
QL 9:ca2e6010d9e2 753 /// Valid values 1, 2, or 4; default 2
QL 9:ca2e6010d9e2 754 #define QF_MPOOL_CTR_SIZE 2
QL 9:ca2e6010d9e2 755 #endif
QL 9:ca2e6010d9e2 756
QL 9:ca2e6010d9e2 757 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 758 QP_BEGIN_
QL 9:ca2e6010d9e2 759
QL 9:ca2e6010d9e2 760 #if (QF_MPOOL_SIZ_SIZE == 1)
QL 9:ca2e6010d9e2 761 /// \brief The data type to store the block-size based on the macro
QL 9:ca2e6010d9e2 762 /// #QF_MPOOL_SIZ_SIZE.
QL 9:ca2e6010d9e2 763 ///
QL 9:ca2e6010d9e2 764 /// The dynamic range of this data type determines the maximum size
QL 9:ca2e6010d9e2 765 /// of blocks that can be managed by the native QF event pool.
QL 9:ca2e6010d9e2 766 typedef uint8_t QMPoolSize;
QL 9:ca2e6010d9e2 767 #elif (QF_MPOOL_SIZ_SIZE == 2)
QL 9:ca2e6010d9e2 768
QL 9:ca2e6010d9e2 769 typedef uint16_t QMPoolSize;
QL 9:ca2e6010d9e2 770 #elif (QF_MPOOL_SIZ_SIZE == 4)
QL 9:ca2e6010d9e2 771 typedef uint32_t QMPoolSize;
QL 9:ca2e6010d9e2 772 #else
QL 9:ca2e6010d9e2 773 #error "QF_MPOOL_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 774 #endif
QL 9:ca2e6010d9e2 775
QL 9:ca2e6010d9e2 776 #if (QF_MPOOL_CTR_SIZE == 1)
QL 9:ca2e6010d9e2 777 /// \brief The data type to store the block-counter based on the macro
QL 9:ca2e6010d9e2 778 /// #QF_MPOOL_CTR_SIZE.
QL 9:ca2e6010d9e2 779 ///
QL 9:ca2e6010d9e2 780 /// The dynamic range of this data type determines the maximum number
QL 9:ca2e6010d9e2 781 /// of blocks that can be stored in the pool.
QL 9:ca2e6010d9e2 782 typedef uint8_t QMPoolCtr;
QL 9:ca2e6010d9e2 783 #elif (QF_MPOOL_CTR_SIZE == 2)
QL 9:ca2e6010d9e2 784 typedef uint16_t QMPoolCtr;
QL 9:ca2e6010d9e2 785 #elif (QF_MPOOL_CTR_SIZE == 4)
QL 9:ca2e6010d9e2 786 typedef uint32_t QMPoolCtr;
QL 9:ca2e6010d9e2 787 #else
QL 9:ca2e6010d9e2 788 #error "QF_MPOOL_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 789 #endif
QL 9:ca2e6010d9e2 790
QL 9:ca2e6010d9e2 791 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 792 /// \brief Native QF memory pool class
QL 9:ca2e6010d9e2 793 ///
QL 9:ca2e6010d9e2 794 /// This class describes the native QF memory pool, which can be used as
QL 9:ca2e6010d9e2 795 /// the event pool for dynamic event allocation, or as a fast, deterministic
QL 9:ca2e6010d9e2 796 /// fixed block-size heap for any other objects in your application.
QL 9:ca2e6010d9e2 797 ///
QL 9:ca2e6010d9e2 798 /// The ::QMPool structure contains only data members for managing a memory
QL 9:ca2e6010d9e2 799 /// pool, but does not contain the pool storage, which must be provided
QL 9:ca2e6010d9e2 800 /// externally during the pool initialization.
QL 9:ca2e6010d9e2 801 ///
QL 9:ca2e6010d9e2 802 /// The native QF event pool is configured by defining the macro
QL 9:ca2e6010d9e2 803 /// #QF_EPOOL_TYPE_ as QEQueue in the specific QF port header file.
QL 9:ca2e6010d9e2 804 class QMPool {
QL 9:ca2e6010d9e2 805 private:
QL 9:ca2e6010d9e2 806
QL 9:ca2e6010d9e2 807 /// start of the memory managed by this memory pool
QL 9:ca2e6010d9e2 808 void *m_start;
QL 9:ca2e6010d9e2 809
QL 9:ca2e6010d9e2 810 /// end of the memory managed by this memory pool
QL 9:ca2e6010d9e2 811 void *m_end;
QL 9:ca2e6010d9e2 812
QL 9:ca2e6010d9e2 813 /// linked list of free blocks
QL 9:ca2e6010d9e2 814 void *m_free;
QL 9:ca2e6010d9e2 815
QL 9:ca2e6010d9e2 816 /// maximum block size (in bytes)
QL 9:ca2e6010d9e2 817 QMPoolSize m_blockSize;
QL 9:ca2e6010d9e2 818
QL 9:ca2e6010d9e2 819 /// total number of blocks
QL 9:ca2e6010d9e2 820 QMPoolCtr m_nTot;
QL 9:ca2e6010d9e2 821
QL 9:ca2e6010d9e2 822 /// number of free blocks remaining
QL 9:ca2e6010d9e2 823 QMPoolCtr m_nFree;
QL 9:ca2e6010d9e2 824
QL 9:ca2e6010d9e2 825 /// minimum number of free blocks ever present in this pool
QL 9:ca2e6010d9e2 826 ///
QL 9:ca2e6010d9e2 827 /// \note this attribute remembers the low watermark of the pool,
QL 9:ca2e6010d9e2 828 /// which provides a valuable information for sizing event pools.
QL 9:ca2e6010d9e2 829 /// \sa QF::getPoolMargin().
QL 9:ca2e6010d9e2 830 QMPoolCtr m_nMin;
QL 9:ca2e6010d9e2 831
QL 9:ca2e6010d9e2 832 public:
QL 9:ca2e6010d9e2 833
QL 9:ca2e6010d9e2 834 /// \brief Initializes the native QF event pool
QL 9:ca2e6010d9e2 835 ///
QL 9:ca2e6010d9e2 836 /// The parameters are as follows: \a poolSto is the pool storage,
QL 9:ca2e6010d9e2 837 /// \a poolSize is the size of the pool storage in bytes, and
QL 9:ca2e6010d9e2 838 /// \a blockSize is the block size of this pool.
QL 9:ca2e6010d9e2 839 ///
QL 9:ca2e6010d9e2 840 /// The caller of this method must make sure that the \a poolSto pointer
QL 9:ca2e6010d9e2 841 /// is properly aligned. In particular, it must be possible to efficiently
QL 9:ca2e6010d9e2 842 /// store a pointer at the location pointed to by \a poolSto.
QL 9:ca2e6010d9e2 843 /// Internally, the QMPool::init() function rounds up the block size
QL 9:ca2e6010d9e2 844 /// \a blockSize so that it can fit an integer number of pointers.
QL 9:ca2e6010d9e2 845 /// This is done to achieve proper alignment of the blocks within the
QL 9:ca2e6010d9e2 846 /// pool.
QL 9:ca2e6010d9e2 847 ///
QL 9:ca2e6010d9e2 848 /// \note Due to the rounding of block size the actual capacity of the
QL 9:ca2e6010d9e2 849 /// pool might be less than (\a poolSize / \a blockSize). You can check
QL 9:ca2e6010d9e2 850 /// the capacity of the pool by calling the QF::getPoolMargin() function.
QL 9:ca2e6010d9e2 851 void init(void * const poolSto, uint32_t const poolSize,
QL 9:ca2e6010d9e2 852 QMPoolSize const blockSize);
QL 9:ca2e6010d9e2 853
QL 9:ca2e6010d9e2 854 /// \brief Obtains a memory block from a memory pool.
QL 9:ca2e6010d9e2 855 ///
QL 9:ca2e6010d9e2 856 /// The only parameter \a me is a pointer to the ::QMPool from which the
QL 9:ca2e6010d9e2 857 /// block is requested. The function returns a pointer to the allocated
QL 9:ca2e6010d9e2 858 /// memory block or NULL if no free blocks are available.
QL 9:ca2e6010d9e2 859 ///
QL 9:ca2e6010d9e2 860 /// A allocated block must be returned to the same pool from which it has
QL 9:ca2e6010d9e2 861 /// been allocated.
QL 9:ca2e6010d9e2 862 ///
QL 9:ca2e6010d9e2 863 /// This function can be called from any task level or ISR level.
QL 9:ca2e6010d9e2 864 ///
QL 9:ca2e6010d9e2 865 /// \note The memory pool \a me must be initialized before any events can
QL 9:ca2e6010d9e2 866 /// be requested from it. Also, the QMPool::get() function uses internally
QL 9:ca2e6010d9e2 867 /// a QF critical section, so you should be careful not to call it from
QL 9:ca2e6010d9e2 868 /// within a critical section when nesting of critical section is not
QL 9:ca2e6010d9e2 869 /// supported.
QL 9:ca2e6010d9e2 870 ///
QL 9:ca2e6010d9e2 871 /// \sa QMPool::put()
QL 9:ca2e6010d9e2 872 void *get(void);
QL 9:ca2e6010d9e2 873
QL 9:ca2e6010d9e2 874 /// \brief Returns a memory block back to a memory pool.
QL 9:ca2e6010d9e2 875 ///
QL 9:ca2e6010d9e2 876 ///
QL 9:ca2e6010d9e2 877 /// This function can be called from any task level or ISR level.
QL 9:ca2e6010d9e2 878 ///
QL 9:ca2e6010d9e2 879 /// \note The block must be allocated from the same memory pool to which
QL 9:ca2e6010d9e2 880 /// it is returned. The QMPool::put() function raises an assertion if the
QL 9:ca2e6010d9e2 881 /// returned pointer to the block points outside of the original memory
QL 9:ca2e6010d9e2 882 /// buffer managed by the memory pool. Also, the QMPool::put() function
QL 9:ca2e6010d9e2 883 /// uses internally a QF critical section, so you should be careful not
QL 9:ca2e6010d9e2 884 /// to call it from within a critical section when nesting of critical
QL 9:ca2e6010d9e2 885 /// section is not supported.
QL 9:ca2e6010d9e2 886 ///
QL 9:ca2e6010d9e2 887 /// \sa QMPool::get()
QL 9:ca2e6010d9e2 888 void put(void * const b);
QL 9:ca2e6010d9e2 889
QL 9:ca2e6010d9e2 890 /// \brief return the fixed block-size of the blocks managed by this pool
QL 9:ca2e6010d9e2 891 QMPoolSize getBlockSize(void) const {
QL 9:ca2e6010d9e2 892 return m_blockSize;
QL 9:ca2e6010d9e2 893 }
QL 9:ca2e6010d9e2 894
QL 9:ca2e6010d9e2 895 private:
QL 9:ca2e6010d9e2 896 friend class QF;
QL 9:ca2e6010d9e2 897 };
QL 9:ca2e6010d9e2 898
QL 9:ca2e6010d9e2 899 QP_END_
QL 9:ca2e6010d9e2 900
QL 9:ca2e6010d9e2 901 /// \brief Memory pool element to allocate correctly aligned storage
QL 9:ca2e6010d9e2 902 /// for QMPool class.
QL 9:ca2e6010d9e2 903 ///
QL 9:ca2e6010d9e2 904 #define QF_MPOOL_EL(type_) \
QL 9:ca2e6010d9e2 905 struct { void *sto_[((sizeof(type_) - 1U)/sizeof(void*)) + 1U]; }
QL 9:ca2e6010d9e2 906
QL 9:ca2e6010d9e2 907 // "qpset.h" =================================================================
QL 9:ca2e6010d9e2 908 /// \brief platform-independent priority sets of 8 or 64 elements.
QL 9:ca2e6010d9e2 909 ///
QL 9:ca2e6010d9e2 910 /// This header file must be included in those QF ports that use the
QL 9:ca2e6010d9e2 911 /// cooperative multitasking QF scheduler or the QK.
QL 9:ca2e6010d9e2 912
QL 9:ca2e6010d9e2 913 QP_BEGIN_
QL 9:ca2e6010d9e2 914
QL 9:ca2e6010d9e2 915 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 916 // useful lookup tables
QL 9:ca2e6010d9e2 917
QL 9:ca2e6010d9e2 918 /// \brief Lookup table for (log2(n) + 1), where n is the index
QL 9:ca2e6010d9e2 919 /// into the table.
QL 9:ca2e6010d9e2 920 ///
QL 9:ca2e6010d9e2 921 /// This lookup delivers the 1-based number of the most significant 1-bit
QL 9:ca2e6010d9e2 922 /// of a byte.
QL 9:ca2e6010d9e2 923 ///
QL 9:ca2e6010d9e2 924 /// \note Index range n = 0..255. The first index (n == 0) should never
QL 9:ca2e6010d9e2 925 /// be used.
QL 9:ca2e6010d9e2 926 ///
QL 9:ca2e6010d9e2 927 extern uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256];
QL 9:ca2e6010d9e2 928
QL 9:ca2e6010d9e2 929 /// \brief Lookup table for (1 << ((n-1) % 8)), where n is the index
QL 9:ca2e6010d9e2 930 /// into the table.
QL 9:ca2e6010d9e2 931 ///
QL 9:ca2e6010d9e2 932 /// \note Index range n = 0..64. The first index (n == 0) should never
QL 9:ca2e6010d9e2 933 /// be used.
QL 9:ca2e6010d9e2 934 extern uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65];
QL 9:ca2e6010d9e2 935
QL 9:ca2e6010d9e2 936 /// \brief Lookup table for ~(1 << ((n-1) % 8)), where n is the index
QL 9:ca2e6010d9e2 937 /// into the table.
QL 9:ca2e6010d9e2 938 ///
QL 9:ca2e6010d9e2 939 /// \note Index range n = 0..64. The first index (n == 0) should never
QL 9:ca2e6010d9e2 940 /// be used.
QL 9:ca2e6010d9e2 941 extern uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65];
QL 9:ca2e6010d9e2 942
QL 9:ca2e6010d9e2 943 /// \brief Lookup table for (n-1)/8
QL 9:ca2e6010d9e2 944 ///
QL 9:ca2e6010d9e2 945 /// \note Index range n = 0..64. The first index (n == 0) should never
QL 9:ca2e6010d9e2 946 /// be used.
QL 9:ca2e6010d9e2 947 extern uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65];
QL 9:ca2e6010d9e2 948
QL 9:ca2e6010d9e2 949
QL 9:ca2e6010d9e2 950 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 951 /// \brief Priority Set of up to 8 elements for building various schedulers,
QL 9:ca2e6010d9e2 952 /// but also useful as a general set of up to 8 elements of any kind.
QL 9:ca2e6010d9e2 953 ///
QL 9:ca2e6010d9e2 954 /// The priority set represents the set of active objects that are ready to
QL 9:ca2e6010d9e2 955 /// run and need to be considered by scheduling processing. The set is capable
QL 9:ca2e6010d9e2 956 /// of storing up to 8 priority levels.
QL 9:ca2e6010d9e2 957 class QPSet8 {
QL 9:ca2e6010d9e2 958
QL 9:ca2e6010d9e2 959 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 960 /// \brief bimask representing elements of the set
QL 9:ca2e6010d9e2 961 uint8_t m_bits;
QL 9:ca2e6010d9e2 962
QL 9:ca2e6010d9e2 963 public:
QL 9:ca2e6010d9e2 964
QL 9:ca2e6010d9e2 965 /// \brief the function evaluates to TRUE if the set is empty,
QL 9:ca2e6010d9e2 966 /// which means that no active objects are ready to run.
QL 9:ca2e6010d9e2 967 bool isEmpty(void) const {
QL 9:ca2e6010d9e2 968 return (m_bits == static_cast<uint8_t>(0));
QL 9:ca2e6010d9e2 969 }
QL 9:ca2e6010d9e2 970
QL 9:ca2e6010d9e2 971 /// \brief the function evaluates to TRUE if the set has elements,
QL 9:ca2e6010d9e2 972 /// which means that some active objects are ready to run.
QL 9:ca2e6010d9e2 973 bool notEmpty(void) const {
QL 9:ca2e6010d9e2 974 return (m_bits != static_cast<uint8_t>(0));
QL 9:ca2e6010d9e2 975 }
QL 9:ca2e6010d9e2 976
QL 9:ca2e6010d9e2 977 /// \brief the function evaluates to TRUE if the priority set has the
QL 9:ca2e6010d9e2 978 /// element \a n.
QL 9:ca2e6010d9e2 979 bool hasElement(uint8_t const n) const {
QL 9:ca2e6010d9e2 980 return ((m_bits & Q_ROM_BYTE(QF_pwr2Lkup[n]))
QL 9:ca2e6010d9e2 981 != static_cast<uint8_t>(0));
QL 9:ca2e6010d9e2 982 }
QL 9:ca2e6010d9e2 983
QL 9:ca2e6010d9e2 984 /// \brief insert element \a n into the set, n = 1..8
QL 9:ca2e6010d9e2 985 void insert(uint8_t const n) {
QL 9:ca2e6010d9e2 986 m_bits |= Q_ROM_BYTE(QF_pwr2Lkup[n]);
QL 9:ca2e6010d9e2 987 }
QL 9:ca2e6010d9e2 988
QL 9:ca2e6010d9e2 989 /// \brief remove element \a n from the set, n = 1..8
QL 9:ca2e6010d9e2 990 void remove(uint8_t const n) {
QL 9:ca2e6010d9e2 991 m_bits &= Q_ROM_BYTE(QF_invPwr2Lkup[n]);
QL 9:ca2e6010d9e2 992 }
QL 9:ca2e6010d9e2 993
QL 9:ca2e6010d9e2 994 /// \brief find the maximum element in the set,
QL 9:ca2e6010d9e2 995 /// \note returns zero if the set is empty
QL 9:ca2e6010d9e2 996 uint8_t findMax(void) const {
QL 9:ca2e6010d9e2 997 return Q_ROM_BYTE(QF_log2Lkup[m_bits]);
QL 9:ca2e6010d9e2 998 }
QL 9:ca2e6010d9e2 999
QL 9:ca2e6010d9e2 1000 friend class QPSet64;
QL 9:ca2e6010d9e2 1001 };
QL 9:ca2e6010d9e2 1002
QL 9:ca2e6010d9e2 1003 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1004 /// \brief Priority Set of up to 64 elements for building various schedulers,
QL 9:ca2e6010d9e2 1005 /// but also useful as a general set of up to 64 elements of any kind.
QL 9:ca2e6010d9e2 1006 ///
QL 9:ca2e6010d9e2 1007 /// The priority set represents the set of active objects that are ready to
QL 9:ca2e6010d9e2 1008 /// run and need to be considered by scheduling processing. The set is capable
QL 9:ca2e6010d9e2 1009 /// of storing up to 64 priority levels.
QL 9:ca2e6010d9e2 1010 ///
QL 9:ca2e6010d9e2 1011 /// The priority set allows to build cooperative multitasking schedulers
QL 9:ca2e6010d9e2 1012 /// to manage up to 64 tasks. It is also used in the Quantum Kernel (QK)
QL 9:ca2e6010d9e2 1013 /// preemptive scheduler.
QL 9:ca2e6010d9e2 1014 ///
QL 9:ca2e6010d9e2 1015 /// The inherited 8-bit set is used as the 8-elemtn set of of 8-bit subsets
QL 9:ca2e6010d9e2 1016 /// Each bit in the super.bits set represents a subset (8-elements)
QL 9:ca2e6010d9e2 1017 /// as follows: \n
QL 9:ca2e6010d9e2 1018 /// bit 0 in this->m_bits is 1 when subset[0] is not empty \n
QL 9:ca2e6010d9e2 1019 /// bit 1 in this->m_bits is 1 when subset[1] is not empty \n
QL 9:ca2e6010d9e2 1020 /// bit 2 in this->m_bits is 1 when subset[2] is not empty \n
QL 9:ca2e6010d9e2 1021 /// bit 3 in this->m_bits is 1 when subset[3] is not empty \n
QL 9:ca2e6010d9e2 1022 /// bit 4 in this->m_bits is 1 when subset[4] is not empty \n
QL 9:ca2e6010d9e2 1023 /// bit 5 in this->m_bits is 1 when subset[5] is not empty \n
QL 9:ca2e6010d9e2 1024 /// bit 6 in this->m_bits is 1 when subset[6] is not empty \n
QL 9:ca2e6010d9e2 1025 /// bit 7 in this->m_bits is 1 when subset[7] is not empty \n
QL 9:ca2e6010d9e2 1026 class QPSet64 {
QL 9:ca2e6010d9e2 1027
QL 9:ca2e6010d9e2 1028 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1029 /// \brief bimask representing 8-element subsets of the set
QL 9:ca2e6010d9e2 1030 uint8_t m_bytes;
QL 9:ca2e6010d9e2 1031
QL 9:ca2e6010d9e2 1032 /// \brief bits representing elements in the set as follows: \n
QL 9:ca2e6010d9e2 1033 /// m_bits[0] represent elements 1..8 \n
QL 9:ca2e6010d9e2 1034 /// m_bits[1] represent elements 9..16 \n
QL 9:ca2e6010d9e2 1035 /// m_bits[2] represent elements 17..24 \n
QL 9:ca2e6010d9e2 1036 /// m_bits[3] represent elements 25..32 \n
QL 9:ca2e6010d9e2 1037 /// m_bits[4] represent elements 33..40 \n
QL 9:ca2e6010d9e2 1038 /// m_bits[5] represent elements 41..48 \n
QL 9:ca2e6010d9e2 1039 /// m_bits[6] represent elements 49..56 \n
QL 9:ca2e6010d9e2 1040 /// m_bits[7] represent elements 57..64 \n
QL 9:ca2e6010d9e2 1041 uint8_t m_bits[8];
QL 9:ca2e6010d9e2 1042
QL 9:ca2e6010d9e2 1043 public:
QL 9:ca2e6010d9e2 1044
QL 9:ca2e6010d9e2 1045 /// \brief the function evaluates to TRUE if the set is empty,
QL 9:ca2e6010d9e2 1046 /// which means that no active objects are ready to run.
QL 9:ca2e6010d9e2 1047 bool isEmpty(void) const {
QL 9:ca2e6010d9e2 1048 return (m_bytes == static_cast<uint8_t>(0));
QL 9:ca2e6010d9e2 1049 }
QL 9:ca2e6010d9e2 1050
QL 9:ca2e6010d9e2 1051 /// \brief the function evaluates to TRUE if the set has elements,
QL 9:ca2e6010d9e2 1052 /// which means that some active objects are ready to run.
QL 9:ca2e6010d9e2 1053 bool notEmpty(void) const {
QL 9:ca2e6010d9e2 1054 return (m_bytes != static_cast<uint8_t>(0));
QL 9:ca2e6010d9e2 1055 }
QL 9:ca2e6010d9e2 1056
QL 9:ca2e6010d9e2 1057 /// \brief the function evaluates to TRUE if the priority set has the
QL 9:ca2e6010d9e2 1058 /// element \a n.
QL 9:ca2e6010d9e2 1059 bool hasElement(uint8_t const n) const {
QL 9:ca2e6010d9e2 1060 uint8_t const m = Q_ROM_BYTE(QF_div8Lkup[n]);
QL 9:ca2e6010d9e2 1061 return ((m_bits[m] & Q_ROM_BYTE(QF_pwr2Lkup[n]))
QL 9:ca2e6010d9e2 1062 != static_cast<uint8_t>(0));
QL 9:ca2e6010d9e2 1063 }
QL 9:ca2e6010d9e2 1064
QL 9:ca2e6010d9e2 1065 /// \brief insert element \a n into the set, n = 1..64
QL 9:ca2e6010d9e2 1066 void insert(uint8_t const n) {
QL 9:ca2e6010d9e2 1067 uint8_t m = Q_ROM_BYTE(QF_div8Lkup[n]);
QL 9:ca2e6010d9e2 1068 m_bits[m] |= Q_ROM_BYTE(QF_pwr2Lkup[n]);
QL 9:ca2e6010d9e2 1069 m_bytes |= Q_ROM_BYTE(QF_pwr2Lkup[m + static_cast<uint8_t>(1)]);
QL 9:ca2e6010d9e2 1070 }
QL 9:ca2e6010d9e2 1071
QL 9:ca2e6010d9e2 1072 /// \brief remove element \a n from the set, n = 1..64
QL 9:ca2e6010d9e2 1073 void remove(uint8_t const n) {
QL 9:ca2e6010d9e2 1074 uint8_t m = Q_ROM_BYTE(QF_div8Lkup[n]);
QL 9:ca2e6010d9e2 1075 if ((m_bits[m] &= Q_ROM_BYTE(QF_invPwr2Lkup[n]))
QL 9:ca2e6010d9e2 1076 == static_cast<uint8_t>(0))
QL 9:ca2e6010d9e2 1077 {
QL 9:ca2e6010d9e2 1078 m_bytes &=Q_ROM_BYTE(QF_invPwr2Lkup[m + static_cast<uint8_t>(1)]);
QL 9:ca2e6010d9e2 1079 }
QL 9:ca2e6010d9e2 1080 }
QL 9:ca2e6010d9e2 1081
QL 9:ca2e6010d9e2 1082 /// \brief find the maximum element in the set,
QL 9:ca2e6010d9e2 1083 /// \note returns zero if the set is empty
QL 9:ca2e6010d9e2 1084 uint8_t findMax(void) const {
QL 9:ca2e6010d9e2 1085 uint8_t n;
QL 9:ca2e6010d9e2 1086 if (m_bytes != static_cast<uint8_t>(0)) {
QL 9:ca2e6010d9e2 1087 n = static_cast<uint8_t>(Q_ROM_BYTE(QF_log2Lkup[m_bytes])
QL 9:ca2e6010d9e2 1088 - static_cast<uint8_t>(1));
QL 9:ca2e6010d9e2 1089 n = static_cast<uint8_t>(
QL 9:ca2e6010d9e2 1090 Q_ROM_BYTE(QF_log2Lkup[m_bits[n]])
QL 9:ca2e6010d9e2 1091 + static_cast<uint8_t>(n << 3));
QL 9:ca2e6010d9e2 1092 }
QL 9:ca2e6010d9e2 1093 else {
QL 9:ca2e6010d9e2 1094 n = static_cast<uint8_t>(0);
QL 9:ca2e6010d9e2 1095 }
QL 9:ca2e6010d9e2 1096 return n;
QL 9:ca2e6010d9e2 1097 }
QL 9:ca2e6010d9e2 1098 };
QL 9:ca2e6010d9e2 1099
QL 9:ca2e6010d9e2 1100 QP_END_
QL 9:ca2e6010d9e2 1101
QL 9:ca2e6010d9e2 1102
QL 9:ca2e6010d9e2 1103 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1104 // Kernel selection based on QK_PREEMPTIVE
QL 9:ca2e6010d9e2 1105 //
QL 9:ca2e6010d9e2 1106 #ifdef QK_PREEMPTIVE
QL 9:ca2e6010d9e2 1107
QL 9:ca2e6010d9e2 1108 // "qk.h" ====================================================================
QL 9:ca2e6010d9e2 1109 /// \brief This macro defines the type of the event queue used for the
QL 9:ca2e6010d9e2 1110 /// active objects.
QL 9:ca2e6010d9e2 1111 ///
QL 9:ca2e6010d9e2 1112 /// \note This is just an example of the macro definition. Typically, you need
QL 9:ca2e6010d9e2 1113 /// to define it in the specific QF port file (qf_port.h). In case of QK,
QL 9:ca2e6010d9e2 1114 /// which always depends on the native QF queue, this macro is defined at the
QL 9:ca2e6010d9e2 1115 /// level of the platform-independent interface qk.h.
QL 9:ca2e6010d9e2 1116 #define QF_EQUEUE_TYPE QEQueue
QL 9:ca2e6010d9e2 1117
QL 9:ca2e6010d9e2 1118 #if defined(QK_TLS) || defined(QK_EXT_SAVE)
QL 9:ca2e6010d9e2 1119 /// \brief This macro defines the type of the OS-Object used for blocking
QL 9:ca2e6010d9e2 1120 /// the native QF event queue when the queue is empty
QL 9:ca2e6010d9e2 1121 ///
QL 9:ca2e6010d9e2 1122 /// In QK, the OS object is used to hold the per-thread flags, which might
QL 9:ca2e6010d9e2 1123 /// be used, for example, to rembember the thread attributes (e.g.,
QL 9:ca2e6010d9e2 1124 /// if the thread uses a floating point co-processor). The OS object value
QL 9:ca2e6010d9e2 1125 /// is set on per-thread basis in QActive::start(). Later, the extended
QL 9:ca2e6010d9e2 1126 /// context switch macros (QK_EXT_SAVE() and QK_EXT_RESTORE()) might use
QL 9:ca2e6010d9e2 1127 /// the per-thread flags to determine what kind of extended context switch
QL 9:ca2e6010d9e2 1128 /// this particular thread needs (e.g., the thread might not be using the
QL 9:ca2e6010d9e2 1129 /// coprocessor or might be using a different one).
QL 9:ca2e6010d9e2 1130 #define QF_OS_OBJECT_TYPE uint8_t
QL 9:ca2e6010d9e2 1131
QL 9:ca2e6010d9e2 1132 /// \brief This macro defines the type of the thread handle used for the
QL 9:ca2e6010d9e2 1133 /// active objects.
QL 9:ca2e6010d9e2 1134 ///
QL 9:ca2e6010d9e2 1135 /// The thread type in QK is the pointer to the thread-local storage (TLS)
QL 9:ca2e6010d9e2 1136 /// This thread-local storage can be set on per-thread basis in
QL 9:ca2e6010d9e2 1137 /// QActive::start(). Later, the QK scheduler, passes the pointer to the
QL 9:ca2e6010d9e2 1138 /// thread-local storage to the macro #QK_TLS.
QL 9:ca2e6010d9e2 1139 #define QF_THREAD_TYPE void *
QL 9:ca2e6010d9e2 1140 #endif // QK_TLS || QK_EXT_SAVE
QL 9:ca2e6010d9e2 1141
QL 9:ca2e6010d9e2 1142 #if (QF_MAX_ACTIVE <= 8)
QL 9:ca2e6010d9e2 1143 extern "C" QP_ QPSet8 QK_readySet_; ///< ready set of QK
QL 9:ca2e6010d9e2 1144 #else
QL 9:ca2e6010d9e2 1145 extern "C" QP_ QPSet64 QK_readySet_; ///< ready set of QK
QL 9:ca2e6010d9e2 1146 #endif
QL 9:ca2e6010d9e2 1147
QL 9:ca2e6010d9e2 1148 extern "C" uint8_t QK_currPrio_; ///< current task/interrupt priority
QL 9:ca2e6010d9e2 1149 extern "C" uint8_t QK_intNest_; ///< interrupt nesting level
QL 9:ca2e6010d9e2 1150
QL 9:ca2e6010d9e2 1151 // QK active object queue implementation .....................................
QL 9:ca2e6010d9e2 1152
QL 9:ca2e6010d9e2 1153 /// \brief Platform-dependent macro defining how QF should block the calling
QL 9:ca2e6010d9e2 1154 /// task when the QF native queue is empty
QL 9:ca2e6010d9e2 1155 ///
QL 9:ca2e6010d9e2 1156 /// \note This is just an example of #QACTIVE_EQUEUE_WAIT_ for the QK-port
QL 9:ca2e6010d9e2 1157 /// of QF. QK never activates a task that has no events to process, so in this
QL 9:ca2e6010d9e2 1158 /// case the macro asserts that the queue is not empty. In other QF ports you
QL 9:ca2e6010d9e2 1159 // need to define the macro appropriately for the underlying kernel/OS you're
QL 9:ca2e6010d9e2 1160 /// using.
QL 9:ca2e6010d9e2 1161 #define QACTIVE_EQUEUE_WAIT_(me_) \
QL 9:ca2e6010d9e2 1162 Q_ASSERT((me_)->m_eQueue.m_frontEvt != static_cast<QEvt const *>(0))
QL 9:ca2e6010d9e2 1163
QL 9:ca2e6010d9e2 1164 /// \brief Platform-dependent macro defining how QF should signal the
QL 9:ca2e6010d9e2 1165 /// active object task that an event has just arrived.
QL 9:ca2e6010d9e2 1166 ///
QL 9:ca2e6010d9e2 1167 /// The macro is necessary only when the native QF event queue is used.
QL 9:ca2e6010d9e2 1168 /// The signaling of task involves unblocking the task if it is blocked.
QL 9:ca2e6010d9e2 1169 ///
QL 9:ca2e6010d9e2 1170 /// \note #QACTIVE_EQUEUE_SIGNAL_ is called from a critical section.
QL 9:ca2e6010d9e2 1171 /// It might leave the critical section internally, but must restore
QL 9:ca2e6010d9e2 1172 /// the critical section before exiting to the caller.
QL 9:ca2e6010d9e2 1173 ///
QL 9:ca2e6010d9e2 1174 /// \note This is just an example of #QACTIVE_EQUEUE_SIGNAL_ for the QK-port
QL 9:ca2e6010d9e2 1175 /// of QF. In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1176 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1177 #define QACTIVE_EQUEUE_SIGNAL_(me_) do { \
QL 9:ca2e6010d9e2 1178 QK_readySet_.insert((me_)->m_prio); \
QL 9:ca2e6010d9e2 1179 if (QK_intNest_ == static_cast<uint8_t>(0)) { \
QL 9:ca2e6010d9e2 1180 uint8_t p = QK_schedPrio_(); \
QL 9:ca2e6010d9e2 1181 if (p != static_cast<uint8_t>(0)) { \
QL 9:ca2e6010d9e2 1182 QK_sched_(p); \
QL 9:ca2e6010d9e2 1183 } \
QL 9:ca2e6010d9e2 1184 } \
QL 9:ca2e6010d9e2 1185 } while (false)
QL 9:ca2e6010d9e2 1186
QL 9:ca2e6010d9e2 1187 /// \brief Platform-dependent macro defining the action QF should take
QL 9:ca2e6010d9e2 1188 /// when the native QF event queue becomes empty.
QL 9:ca2e6010d9e2 1189 ///
QL 9:ca2e6010d9e2 1190 /// \note #QACTIVE_EQUEUE_ONEMPTY_ is called from a critical section.
QL 9:ca2e6010d9e2 1191 /// It should not leave the critical section.
QL 9:ca2e6010d9e2 1192 ///
QL 9:ca2e6010d9e2 1193 /// \note This is just an example of #QACTIVE_EQUEUE_ONEMPTY_ for the QK-port
QL 9:ca2e6010d9e2 1194 /// of QF. In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1195 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1196 #define QACTIVE_EQUEUE_ONEMPTY_(me_) \
QL 9:ca2e6010d9e2 1197 QK_readySet_.remove((me_)->m_prio)
QL 9:ca2e6010d9e2 1198
QL 9:ca2e6010d9e2 1199 // QK event pool operations ..................................................
QL 9:ca2e6010d9e2 1200
QL 9:ca2e6010d9e2 1201 /// \brief This macro defines the type of the event pool used in this QF port.
QL 9:ca2e6010d9e2 1202 ///
QL 9:ca2e6010d9e2 1203 /// \note This is a specific implementation for the QK-port of QF.
QL 9:ca2e6010d9e2 1204 /// In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1205 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1206 #define QF_EPOOL_TYPE_ QMPool
QL 9:ca2e6010d9e2 1207
QL 9:ca2e6010d9e2 1208 /// \brief Platform-dependent macro defining the event pool initialization
QL 9:ca2e6010d9e2 1209 ///
QL 9:ca2e6010d9e2 1210 /// \note This is a specific implementation for the QK-port of QF.
QL 9:ca2e6010d9e2 1211 /// In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1212 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1213 #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
QL 9:ca2e6010d9e2 1214 (p_).init((poolSto_), (poolSize_), \
QL 9:ca2e6010d9e2 1215 static_cast<QMPoolSize>(evtSize_))
QL 9:ca2e6010d9e2 1216
QL 9:ca2e6010d9e2 1217 /// \brief Platform-dependent macro defining how QF should obtain the
QL 9:ca2e6010d9e2 1218 /// event pool block-size
QL 9:ca2e6010d9e2 1219 ///
QL 9:ca2e6010d9e2 1220 /// \note This is a specific implementation for the QK-port of QF.
QL 9:ca2e6010d9e2 1221 /// In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1222 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1223 #define QF_EPOOL_EVENT_SIZE_(p_) \
QL 9:ca2e6010d9e2 1224 static_cast<uint32_t>((p_).getBlockSize())
QL 9:ca2e6010d9e2 1225
QL 9:ca2e6010d9e2 1226 /// \brief Platform-dependent macro defining how QF should obtain an event
QL 9:ca2e6010d9e2 1227 /// \a e_ from the event pool \a p_
QL 9:ca2e6010d9e2 1228 ///
QL 9:ca2e6010d9e2 1229 /// \note This is a specific implementation for the QK-port of QF.
QL 9:ca2e6010d9e2 1230 /// In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1231 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1232 #define QF_EPOOL_GET_(p_, e_) ((e_) = static_cast<QEvt *>((p_).get()))
QL 9:ca2e6010d9e2 1233
QL 9:ca2e6010d9e2 1234 /// \brief Platform-dependent macro defining how QF should return an event
QL 9:ca2e6010d9e2 1235 /// \a e_ to the event pool \a p_
QL 9:ca2e6010d9e2 1236 ///
QL 9:ca2e6010d9e2 1237 /// \note This is a specific implementation for the QK-port of QF.
QL 9:ca2e6010d9e2 1238 /// In other QF ports you need to define the macro appropriately for
QL 9:ca2e6010d9e2 1239 /// the underlying kernel/OS you're using.
QL 9:ca2e6010d9e2 1240 #define QF_EPOOL_PUT_(p_, e_) ((p_).put(e_))
QL 9:ca2e6010d9e2 1241
QL 9:ca2e6010d9e2 1242 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1243 QP_BEGIN_
QL 9:ca2e6010d9e2 1244
QL 9:ca2e6010d9e2 1245 #ifndef QK_NO_MUTEX
QL 9:ca2e6010d9e2 1246 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1247 /// \brief QK Mutex type.
QL 9:ca2e6010d9e2 1248 ///
QL 9:ca2e6010d9e2 1249 /// QMutex represents the priority-ceiling mutex available in QK.
QL 9:ca2e6010d9e2 1250 /// \sa QK::mutexLock()
QL 9:ca2e6010d9e2 1251 /// \sa QK::mutexUnlock()
QL 9:ca2e6010d9e2 1252 typedef uint8_t QMutex;
QL 9:ca2e6010d9e2 1253 #endif // QK_NO_MUTEX
QL 9:ca2e6010d9e2 1254
QL 9:ca2e6010d9e2 1255 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1256 /// \brief QK services.
QL 9:ca2e6010d9e2 1257 ///
QL 9:ca2e6010d9e2 1258 /// This class groups together QK services. It has only static members and
QL 9:ca2e6010d9e2 1259 /// should not be instantiated.
QL 9:ca2e6010d9e2 1260 ///
QL 9:ca2e6010d9e2 1261 // \note The QK scheduler, QK priority, QK ready set, etc. belong conceptually
QL 9:ca2e6010d9e2 1262 /// to the QK class (as static class members). However, to avoid C++ potential
QL 9:ca2e6010d9e2 1263 /// name-mangling problems in assembly language, these elements are defined
QL 9:ca2e6010d9e2 1264 /// outside of the QK class and use the extern "C" linkage specification.
QL 9:ca2e6010d9e2 1265 ///
QL 9:ca2e6010d9e2 1266 class QK {
QL 9:ca2e6010d9e2 1267 public:
QL 9:ca2e6010d9e2 1268
QL 9:ca2e6010d9e2 1269 /// \brief get the current QK version number string
QL 9:ca2e6010d9e2 1270 ///
QL 9:ca2e6010d9e2 1271 /// \return version of the QK as a constant 6-character string of the
QL 9:ca2e6010d9e2 1272 /// form x.y.zz, where x is a 1-digit major version number, y is a
QL 9:ca2e6010d9e2 1273 /// 1-digit minor version number, and zz is a 2-digit release number.
QL 9:ca2e6010d9e2 1274 static char_t const Q_ROM * Q_ROM_VAR getVersion(void);
QL 9:ca2e6010d9e2 1275
QL 9:ca2e6010d9e2 1276 /// \brief QK idle callback (customized in BSPs for QK)
QL 9:ca2e6010d9e2 1277 ///
QL 9:ca2e6010d9e2 1278 /// QK::onIdle() is called continously by the QK idle loop. This callback
QL 9:ca2e6010d9e2 1279 /// gives the application an opportunity to enter a power-saving CPU mode,
QL 9:ca2e6010d9e2 1280 /// or perform some other idle processing.
QL 9:ca2e6010d9e2 1281 ///
QL 9:ca2e6010d9e2 1282 /// \note QK::onIdle() is invoked with interrupts unlocked and must also
QL 9:ca2e6010d9e2 1283 /// return with interrupts unlocked.
QL 9:ca2e6010d9e2 1284 ///
QL 9:ca2e6010d9e2 1285 /// \sa QF::onIdle()
QL 9:ca2e6010d9e2 1286 static void onIdle(void);
QL 9:ca2e6010d9e2 1287
QL 9:ca2e6010d9e2 1288 #ifndef QK_NO_MUTEX
QL 9:ca2e6010d9e2 1289
QL 9:ca2e6010d9e2 1290 /// \brief QK priority-ceiling mutex lock
QL 9:ca2e6010d9e2 1291 ///
QL 9:ca2e6010d9e2 1292 /// Lock the QK scheduler up to the priority level \a prioCeiling.
QL 9:ca2e6010d9e2 1293 ///
QL 9:ca2e6010d9e2 1294 // \note This function should be always paired with QK::mutexUnlock().
QL 9:ca2e6010d9e2 1295 /// The code between QK::mutexLock() and QK::mutexUnlock() should be
QL 9:ca2e6010d9e2 1296 /// kept to the minimum.
QL 9:ca2e6010d9e2 1297 ///
QL 9:ca2e6010d9e2 1298 /// \include qk_mux.cpp
QL 9:ca2e6010d9e2 1299 static QMutex mutexLock(uint8_t const prioCeiling);
QL 9:ca2e6010d9e2 1300
QL 9:ca2e6010d9e2 1301 /// \brief QK priority-ceiling mutex unlock
QL 9:ca2e6010d9e2 1302 ///
QL 9:ca2e6010d9e2 1303 /// \note This function should be always paired with QK::mutexLock().
QL 9:ca2e6010d9e2 1304 /// The code between QK::mutexLock() and QK::mutexUnlock() should be
QL 9:ca2e6010d9e2 1305 /// kept to the minimum.
QL 9:ca2e6010d9e2 1306 ///
QL 9:ca2e6010d9e2 1307 /// \include qk_mux.cpp
QL 9:ca2e6010d9e2 1308 static void mutexUnlock(QMutex const mutex);
QL 9:ca2e6010d9e2 1309
QL 9:ca2e6010d9e2 1310 #endif // QK_NO_MUTEX
QL 9:ca2e6010d9e2 1311
QL 9:ca2e6010d9e2 1312 };
QL 9:ca2e6010d9e2 1313
QL 9:ca2e6010d9e2 1314 QP_END_
QL 9:ca2e6010d9e2 1315
QL 9:ca2e6010d9e2 1316 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1317 extern "C" {
QL 9:ca2e6010d9e2 1318
QL 9:ca2e6010d9e2 1319 /// \brief QK initialization
QL 9:ca2e6010d9e2 1320 ///
QL 9:ca2e6010d9e2 1321 /// QK_init() is called from QF_init() in qk.cpp. This function is
QL 9:ca2e6010d9e2 1322 /// defined in the QK ports.
QL 9:ca2e6010d9e2 1323 void QK_init(void);
QL 9:ca2e6010d9e2 1324
QL 9:ca2e6010d9e2 1325 /// \brief The QK scheduler
QL 9:ca2e6010d9e2 1326 ///
QL 9:ca2e6010d9e2 1327 /// \note The QK scheduler must be always called with the interrupts
QL 9:ca2e6010d9e2 1328 /// disabled and enables interrupts internally.
QL 9:ca2e6010d9e2 1329 ///
QL 9:ca2e6010d9e2 1330 /// \sa QK_schedPrio_()
QL 9:ca2e6010d9e2 1331 void QK_sched_(uint8_t p);
QL 9:ca2e6010d9e2 1332
QL 9:ca2e6010d9e2 1333 /// \brief The QK extended scheduler for interrupt context
QL 9:ca2e6010d9e2 1334 ///
QL 9:ca2e6010d9e2 1335 /// \note The QK extended exscheduler must be always called with the
QL 9:ca2e6010d9e2 1336 /// interrupts disabled and enables interrupts internally.
QL 9:ca2e6010d9e2 1337 ///
QL 9:ca2e6010d9e2 1338 /// \sa QK_schedPrio_()
QL 9:ca2e6010d9e2 1339 void QK_schedExt_(uint8_t p);
QL 9:ca2e6010d9e2 1340
QL 9:ca2e6010d9e2 1341 /// \brief Find the highest-priority task ready to run
QL 9:ca2e6010d9e2 1342 ///
QL 9:ca2e6010d9e2 1343 /// \note QK_schedPrio_() must be always called with interrupts disabled
QL 9:ca2e6010d9e2 1344 /// and returns with interrupts disabled.
QL 9:ca2e6010d9e2 1345 uint8_t QK_schedPrio_(void);
QL 9:ca2e6010d9e2 1346
QL 9:ca2e6010d9e2 1347 } // extern "C"
QL 9:ca2e6010d9e2 1348
QL 9:ca2e6010d9e2 1349 #else // QK_PREEMPTIVE
QL 9:ca2e6010d9e2 1350
QL 9:ca2e6010d9e2 1351 // "qvanilla.h" ==============================================================
QL 9:ca2e6010d9e2 1352 /// \brief platform-independent interface to the cooperative "vanilla" kernel.
QL 9:ca2e6010d9e2 1353
QL 9:ca2e6010d9e2 1354 QP_BEGIN_
QL 9:ca2e6010d9e2 1355 // the event queue type for the "Vanilla" kernel
QL 9:ca2e6010d9e2 1356 #define QF_EQUEUE_TYPE QEQueue
QL 9:ca2e6010d9e2 1357 // native event queue operations
QL 9:ca2e6010d9e2 1358 #define QACTIVE_EQUEUE_WAIT_(me_) \
QL 9:ca2e6010d9e2 1359 Q_ASSERT((me_)->m_eQueue.m_frontEvt != static_cast<QEvt const *>(0))
QL 9:ca2e6010d9e2 1360
QL 9:ca2e6010d9e2 1361 #define QACTIVE_EQUEUE_SIGNAL_(me_) \
QL 9:ca2e6010d9e2 1362 (QF_readySet_.insert((me_)->m_prio))
QL 9:ca2e6010d9e2 1363
QL 9:ca2e6010d9e2 1364 #define QACTIVE_EQUEUE_ONEMPTY_(me_) \
QL 9:ca2e6010d9e2 1365 (QF_readySet_.remove((me_)->m_prio))
QL 9:ca2e6010d9e2 1366
QL 9:ca2e6010d9e2 1367 // native QF event pool operations
QL 9:ca2e6010d9e2 1368 #define QF_EPOOL_TYPE_ QMPool
QL 9:ca2e6010d9e2 1369 #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
QL 9:ca2e6010d9e2 1370 (p_).init((poolSto_), (poolSize_), static_cast<QMPoolSize>(evtSize_))
QL 9:ca2e6010d9e2 1371 #define QF_EPOOL_EVENT_SIZE_(p_) \
QL 9:ca2e6010d9e2 1372 static_cast<uint32_t>((p_).getBlockSize())
QL 9:ca2e6010d9e2 1373 #define QF_EPOOL_GET_(p_, e_) ((e_) = static_cast<QEvt *>((p_).get()))
QL 9:ca2e6010d9e2 1374 #define QF_EPOOL_PUT_(p_, e_) ((p_).put(e_))
QL 9:ca2e6010d9e2 1375
QL 9:ca2e6010d9e2 1376 QP_END_
QL 9:ca2e6010d9e2 1377
QL 9:ca2e6010d9e2 1378 #if (QF_MAX_ACTIVE <= 8)
QL 9:ca2e6010d9e2 1379 extern "C" QP_ QPSet8 QF_readySet_; ///< ready set of active objects
QL 9:ca2e6010d9e2 1380 #else
QL 9:ca2e6010d9e2 1381 extern "C" QP_ QPSet64 QF_readySet_; ///< ready set of active objects
QL 9:ca2e6010d9e2 1382 #endif
QL 9:ca2e6010d9e2 1383
QL 9:ca2e6010d9e2 1384 extern "C" uint8_t QF_currPrio_; ///< current task/interrupt priority
QL 9:ca2e6010d9e2 1385 extern "C" uint8_t QF_intNest_; ///< interrupt nesting level
QL 9:ca2e6010d9e2 1386
QL 9:ca2e6010d9e2 1387 #endif // QK_PREEMPTIVE
QL 9:ca2e6010d9e2 1388
QL 9:ca2e6010d9e2 1389
QL 9:ca2e6010d9e2 1390 // qf.h (QF platform-independent public interface) ===========================
QL 9:ca2e6010d9e2 1391
QL 9:ca2e6010d9e2 1392 /// \brief QF/C++ platform-independent public interface.
QL 9:ca2e6010d9e2 1393 ///
QL 9:ca2e6010d9e2 1394 /// This header file must be included directly or indirectly
QL 9:ca2e6010d9e2 1395 /// in all modules (*.cpp files) that use QF/C++.
QL 9:ca2e6010d9e2 1396
QL 9:ca2e6010d9e2 1397 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1398 #ifdef Q_EVT_CTOR
QL 9:ca2e6010d9e2 1399 #include <new> // for placement new
QL 9:ca2e6010d9e2 1400 #endif
QL 9:ca2e6010d9e2 1401
QL 9:ca2e6010d9e2 1402 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1403 // apply defaults for all undefined configuration parameters
QL 9:ca2e6010d9e2 1404 //
QL 9:ca2e6010d9e2 1405 #ifndef QF_EVENT_SIZ_SIZE
QL 9:ca2e6010d9e2 1406 /// \brief Default value of the macro configurable value in qf_port.h
QL 9:ca2e6010d9e2 1407 #define QF_EVENT_SIZ_SIZE 2
QL 9:ca2e6010d9e2 1408 #endif
QL 9:ca2e6010d9e2 1409
QL 9:ca2e6010d9e2 1410 #ifndef QF_MAX_EPOOL
QL 9:ca2e6010d9e2 1411 /// \brief Default value of the macro configurable value in qf_port.h
QL 9:ca2e6010d9e2 1412 #define QF_MAX_EPOOL 3
QL 9:ca2e6010d9e2 1413 #endif
QL 9:ca2e6010d9e2 1414
QL 9:ca2e6010d9e2 1415 #ifndef QF_TIMEEVT_CTR_SIZE
QL 9:ca2e6010d9e2 1416 /// \brief macro to override the default QTimeEvtCtr size.
QL 9:ca2e6010d9e2 1417 /// Valid values 1, 2, or 4; default 2
QL 9:ca2e6010d9e2 1418 #define QF_TIMEEVT_CTR_SIZE 2
QL 9:ca2e6010d9e2 1419 #endif
QL 9:ca2e6010d9e2 1420
QL 9:ca2e6010d9e2 1421 #if (QF_MAX_ACTIVE < 1) || (63 < QF_MAX_ACTIVE)
QL 9:ca2e6010d9e2 1422 #error "QF_MAX_ACTIVE not defined or out of range. Valid range is 1..63"
QL 9:ca2e6010d9e2 1423 #endif
QL 9:ca2e6010d9e2 1424
QL 9:ca2e6010d9e2 1425 #ifndef QF_ACTIVE_SUPER_
QL 9:ca2e6010d9e2 1426
QL 9:ca2e6010d9e2 1427 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1428 /// \brief The macro defining the base class for QActive.
QL 9:ca2e6010d9e2 1429 ///
QL 9:ca2e6010d9e2 1430 /// By default, the ::QActive class is derived from ::QHsm. However,
QL 9:ca2e6010d9e2 1431 /// if the macro QF_ACTIVE_SUPER_ is defined, QActive is derived from
QL 9:ca2e6010d9e2 1432 /// QF_ACTIVE_SUPER_.
QL 9:ca2e6010d9e2 1433 ///
QL 9:ca2e6010d9e2 1434 /// Clients might choose, for example, to define QF_ACTIVE_SUPER_ as QFsm
QL 9:ca2e6010d9e2 1435 /// to avoid the 1-2KB overhead of the hierarchical event processor.
QL 9:ca2e6010d9e2 1436 ///
QL 9:ca2e6010d9e2 1437 /// Clients might also choose to define QF_ACTIVE_SUPER_ as their own
QL 9:ca2e6010d9e2 1438 /// completely customized class that has nothing to do with QHsm or QFsm.
QL 9:ca2e6010d9e2 1439 /// The QF_ACTIVE_SUPER_ class must provide member functions init() and
QL 9:ca2e6010d9e2 1440 /// dispatch(), consistent with the signatures of QHsm and QFsm. But
QL 9:ca2e6010d9e2 1441 /// the implementatin of these functions is completely open.
QL 9:ca2e6010d9e2 1442 #define QF_ACTIVE_SUPER_ QHsm
QL 9:ca2e6010d9e2 1443
QL 9:ca2e6010d9e2 1444 /// \brief The argument of the base class' constructor.
QL 9:ca2e6010d9e2 1445 #define QF_ACTIVE_STATE_ QStateHandler
QL 9:ca2e6010d9e2 1446
QL 9:ca2e6010d9e2 1447 #endif
QL 9:ca2e6010d9e2 1448
QL 9:ca2e6010d9e2 1449 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1450 QP_BEGIN_
QL 9:ca2e6010d9e2 1451
QL 9:ca2e6010d9e2 1452 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1453 #if (QF_EVENT_SIZ_SIZE == 1)
QL 9:ca2e6010d9e2 1454
QL 9:ca2e6010d9e2 1455 /// \brief The data type to store the block-size defined based on
QL 9:ca2e6010d9e2 1456 /// the macro #QF_EVENT_SIZ_SIZE.
QL 9:ca2e6010d9e2 1457 ///
QL 9:ca2e6010d9e2 1458 /// The dynamic range of this data type determines the maximum block
QL 9:ca2e6010d9e2 1459 /// size that can be managed by the pool.
QL 9:ca2e6010d9e2 1460 typedef uint8_t QEvtSize;
QL 9:ca2e6010d9e2 1461 #elif (QF_EVENT_SIZ_SIZE == 2)
QL 9:ca2e6010d9e2 1462 typedef uint16_t QEvtSize;
QL 9:ca2e6010d9e2 1463 #elif (QF_EVENT_SIZ_SIZE == 4)
QL 9:ca2e6010d9e2 1464 typedef uint32_t QEvtSize;
QL 9:ca2e6010d9e2 1465 #else
QL 9:ca2e6010d9e2 1466 #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 1467 #endif
QL 9:ca2e6010d9e2 1468
QL 9:ca2e6010d9e2 1469 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1470 #if (QF_TIMEEVT_CTR_SIZE == 1)
QL 9:ca2e6010d9e2 1471 /// \brief type of the Time Event counter, which determines the dynamic
QL 9:ca2e6010d9e2 1472 /// range of the time delays measured in clock ticks.
QL 9:ca2e6010d9e2 1473 ///
QL 9:ca2e6010d9e2 1474 /// This typedef is configurable via the preprocessor switch
QL 9:ca2e6010d9e2 1475 /// #QF_TIMEEVT_CTR_SIZE. The other possible values of this type are
QL 9:ca2e6010d9e2 1476 /// as follows: \n
QL 9:ca2e6010d9e2 1477 /// uint8_t when (QF_TIMEEVT_CTR_SIZE == 1), and \n
QL 9:ca2e6010d9e2 1478 /// uint32_t when (QF_TIMEEVT_CTR_SIZE == 4).
QL 9:ca2e6010d9e2 1479 typedef uint8_t QTimeEvtCtr;
QL 9:ca2e6010d9e2 1480 #elif (QF_TIMEEVT_CTR_SIZE == 2)
QL 9:ca2e6010d9e2 1481 typedef uint16_t QTimeEvtCtr;
QL 9:ca2e6010d9e2 1482 #elif (QF_TIMEEVT_CTR_SIZE == 4)
QL 9:ca2e6010d9e2 1483 typedef uint32_t QTimeEvtCtr;
QL 9:ca2e6010d9e2 1484 #else
QL 9:ca2e6010d9e2 1485 #error "QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 1486 #endif
QL 9:ca2e6010d9e2 1487
QL 9:ca2e6010d9e2 1488 class QEQueue; // forward declaration
QL 9:ca2e6010d9e2 1489
QL 9:ca2e6010d9e2 1490 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1491 /// \brief Base class for derivation of application-level active object
QL 9:ca2e6010d9e2 1492 /// classes.
QL 9:ca2e6010d9e2 1493 ///
QL 9:ca2e6010d9e2 1494 /// QActive is the base class for derivation of active objects. Active objects
QL 9:ca2e6010d9e2 1495 /// in QF are encapsulated tasks (each embedding a state machine and an event
QL 9:ca2e6010d9e2 1496 /// queue) that communicate with one another asynchronously by sending and
QL 9:ca2e6010d9e2 1497 /// receiving events. Within an active object, events are processed
QL 9:ca2e6010d9e2 1498 /// sequentially in a run-to-completion (RTC) fashion, while QF encapsulates
QL 9:ca2e6010d9e2 1499 /// all the details of thread-safe event exchange and queuing.
QL 9:ca2e6010d9e2 1500 ///
QL 9:ca2e6010d9e2 1501 /// \note QActive is not intended to be instantiated directly, but rather
QL 9:ca2e6010d9e2 1502 /// serves as the base class for derivation of active objects in the
QL 9:ca2e6010d9e2 1503 /// application code.
QL 9:ca2e6010d9e2 1504 ///
QL 9:ca2e6010d9e2 1505 /// The following example illustrates how to derive an active object from
QL 9:ca2e6010d9e2 1506 /// QActive.
QL 9:ca2e6010d9e2 1507 /// \include qf_qactive.cpp
QL 9:ca2e6010d9e2 1508 ///
QL 9:ca2e6010d9e2 1509 /// \sa #QF_ACTIVE_SUPER_ defines the base class for QActive
QL 9:ca2e6010d9e2 1510 class QActive : public QF_ACTIVE_SUPER_ {
QL 9:ca2e6010d9e2 1511
QL 9:ca2e6010d9e2 1512 #ifdef QF_EQUEUE_TYPE
QL 9:ca2e6010d9e2 1513 /// \brief OS-dependent event-queue type.
QL 9:ca2e6010d9e2 1514 ///
QL 9:ca2e6010d9e2 1515 /// The type of the queue depends on the underlying operating system or
QL 9:ca2e6010d9e2 1516 /// a kernel. Many kernels support "message queues" that can be adapted
QL 9:ca2e6010d9e2 1517 /// to deliver QF events to the active object. Alternatively, QF provides
QL 9:ca2e6010d9e2 1518 /// a native event queue implementation that can be used as well.
QL 9:ca2e6010d9e2 1519 ///
QL 9:ca2e6010d9e2 1520 /// The native QF event queue is configured by defining the macro
QL 9:ca2e6010d9e2 1521 /// #QF_EQUEUE_TYPE as ::QEQueue.
QL 9:ca2e6010d9e2 1522 QF_EQUEUE_TYPE m_eQueue;
QL 9:ca2e6010d9e2 1523 #endif
QL 9:ca2e6010d9e2 1524
QL 9:ca2e6010d9e2 1525 #ifdef QF_OS_OBJECT_TYPE
QL 9:ca2e6010d9e2 1526 /// \brief OS-dependent per-thread object.
QL 9:ca2e6010d9e2 1527 ///
QL 9:ca2e6010d9e2 1528 /// This data might be used in various ways, depending on the QF port.
QL 9:ca2e6010d9e2 1529 /// In some ports m_osObject is used to block the calling thread when
QL 9:ca2e6010d9e2 1530 /// the native QF queue is empty. In other QF ports the OS-dependent
QL 9:ca2e6010d9e2 1531 /// object might be used differently.
QL 9:ca2e6010d9e2 1532 QF_OS_OBJECT_TYPE m_osObject;
QL 9:ca2e6010d9e2 1533 #endif
QL 9:ca2e6010d9e2 1534
QL 9:ca2e6010d9e2 1535 #ifdef QF_THREAD_TYPE
QL 9:ca2e6010d9e2 1536 /// \brief OS-dependent representation of the thread of the active
QL 9:ca2e6010d9e2 1537 /// object.
QL 9:ca2e6010d9e2 1538 ///
QL 9:ca2e6010d9e2 1539 /// This data might be used in various ways, depending on the QF port.
QL 9:ca2e6010d9e2 1540 /// In some ports m_thread is used store the thread handle. In other ports
QL 9:ca2e6010d9e2 1541 /// m_thread can be a pointer to the Thread-Local-Storage (TLS).
QL 9:ca2e6010d9e2 1542 QF_THREAD_TYPE m_thread;
QL 9:ca2e6010d9e2 1543 #endif
QL 9:ca2e6010d9e2 1544
QL 9:ca2e6010d9e2 1545 /// \brief QF priority associated with the active object.
QL 9:ca2e6010d9e2 1546 /// \sa QActive::start()
QL 9:ca2e6010d9e2 1547 uint8_t m_prio;
QL 9:ca2e6010d9e2 1548
QL 9:ca2e6010d9e2 1549 public:
QL 9:ca2e6010d9e2 1550 /// \brief Starts execution of an active object and registers the object
QL 9:ca2e6010d9e2 1551 /// with the framework.
QL 9:ca2e6010d9e2 1552 ///
QL 9:ca2e6010d9e2 1553 /// The function takes six arguments.
QL 9:ca2e6010d9e2 1554 /// \a prio is the priority of the active object. QF allows you to start
QL 9:ca2e6010d9e2 1555 /// up to 63 active objects, each one having a unique priority number
QL 9:ca2e6010d9e2 1556 /// between 1 and 63 inclusive, where higher numerical values correspond
QL 9:ca2e6010d9e2 1557 /// to higher priority (urgency) of the active object relative to the
QL 9:ca2e6010d9e2 1558 /// others.
QL 9:ca2e6010d9e2 1559 /// \a qSto[] and \a qLen arguments are the storage and size of the event
QL 9:ca2e6010d9e2 1560 /// queue used by this active object.
QL 9:ca2e6010d9e2 1561 /// \a stkSto and \a stkSize are the stack storage and size in bytes.
QL 9:ca2e6010d9e2 1562 /// Please note that a per-active object stack is used only when the
QL 9:ca2e6010d9e2 1563 /// underlying OS requies it. If the stack is not required, or the
QL 9:ca2e6010d9e2 1564 /// underlying OS allocates the stack internally, the \a stkSto should be
QL 9:ca2e6010d9e2 1565 /// NULL and/or \a stkSize should be 0.
QL 9:ca2e6010d9e2 1566 /// \a ie is an optional initialization event that can be used to pass
QL 9:ca2e6010d9e2 1567 /// additional startup data to the active object. (Pass NULL if your
QL 9:ca2e6010d9e2 1568 /// active object does not expect the initialization event).
QL 9:ca2e6010d9e2 1569 ///
QL 9:ca2e6010d9e2 1570 /// \note This function is strongly OS-dependent and must be defined in
QL 9:ca2e6010d9e2 1571 /// the QF port to a particular platform.
QL 9:ca2e6010d9e2 1572 ///
QL 9:ca2e6010d9e2 1573 /// The following example shows starting of the Philosopher object when a
QL 9:ca2e6010d9e2 1574 /// per-task stack is required:
QL 9:ca2e6010d9e2 1575 /// \include qf_start.cpp
QL 9:ca2e6010d9e2 1576 void start(uint8_t const prio,
QL 9:ca2e6010d9e2 1577 QEvt const *qSto[], uint32_t const qLen,
QL 9:ca2e6010d9e2 1578 void * const stkSto, uint32_t const stkSize,
QL 9:ca2e6010d9e2 1579 QEvt const * const ie = static_cast<QEvt *>(0));
QL 9:ca2e6010d9e2 1580
QL 9:ca2e6010d9e2 1581 /// \brief Posts an event \a e directly to the event queue of the acitve
QL 9:ca2e6010d9e2 1582 /// object \a me using the First-In-First-Out (FIFO) policy.
QL 9:ca2e6010d9e2 1583 ///
QL 9:ca2e6010d9e2 1584 /// Direct event posting is the simplest asynchronous communication method
QL 9:ca2e6010d9e2 1585 /// available in QF. The following example illustrates how the Philosopher
QL 9:ca2e6010d9e2 1586 /// active obejct posts directly the HUNGRY event to the Table active
QL 9:ca2e6010d9e2 1587 /// object. \include qf_post.cpp
QL 9:ca2e6010d9e2 1588 ///
QL 9:ca2e6010d9e2 1589 /// \note The producer of the event (Philosopher in this case) must only
QL 9:ca2e6010d9e2 1590 /// "know" the recipient (Table) by a generic (QActive *QDPP_table)
QL 9:ca2e6010d9e2 1591 /// pointer, but the specific definition of the Table class is not
QL 9:ca2e6010d9e2 1592 /// required.
QL 9:ca2e6010d9e2 1593 ///
QL 9:ca2e6010d9e2 1594 /// \note Direct event posting should not be confused with direct event
QL 9:ca2e6010d9e2 1595 /// dispatching. In contrast to asynchronous event posting through event
QL 9:ca2e6010d9e2 1596 /// queues, direct event dispatching is synchronous. Direct event
QL 9:ca2e6010d9e2 1597 /// dispatching occurs when you call QHsm::dispatch(), or QFsm::dispatch()
QL 9:ca2e6010d9e2 1598 /// function.
QL 9:ca2e6010d9e2 1599 #ifndef Q_SPY
QL 9:ca2e6010d9e2 1600 void postFIFO(QEvt const * const e);
QL 9:ca2e6010d9e2 1601 #else
QL 9:ca2e6010d9e2 1602 void postFIFO(QEvt const * const e, void const * const sender);
QL 9:ca2e6010d9e2 1603 #endif
QL 9:ca2e6010d9e2 1604
QL 9:ca2e6010d9e2 1605 /// \brief Un-subscribes from the delivery of all signals to the active
QL 9:ca2e6010d9e2 1606 /// object.
QL 9:ca2e6010d9e2 1607 ///
QL 9:ca2e6010d9e2 1608 /// This function is part of the Publish-Subscribe event delivery
QL 9:ca2e6010d9e2 1609 /// mechanism available in QF. Un-subscribing from all events means that
QL 9:ca2e6010d9e2 1610 /// the framework will stop posting any published events to the event
QL 9:ca2e6010d9e2 1611 /// queue of the active object.
QL 9:ca2e6010d9e2 1612 ///
QL 9:ca2e6010d9e2 1613 /// \note Due to the latency of event queues, an active object should NOT
QL 9:ca2e6010d9e2 1614 /// assume that no events will ever be dispatched to the state machine of
QL 9:ca2e6010d9e2 1615 /// the active object after un-subscribing from all events.
QL 9:ca2e6010d9e2 1616 /// The events might be already in the queue, or just about to be posted
QL 9:ca2e6010d9e2 1617 /// and the un-subscribe operation will not flush such events. Also, the
QL 9:ca2e6010d9e2 1618 /// alternative event-delivery mechanisms, such as direct event posting or
QL 9:ca2e6010d9e2 1619 /// time events, can be still delivered to the event queue of the active
QL 9:ca2e6010d9e2 1620 /// object.
QL 9:ca2e6010d9e2 1621 ///
QL 9:ca2e6010d9e2 1622 /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribe()
QL 9:ca2e6010d9e2 1623 void unsubscribeAll(void) const;
QL 9:ca2e6010d9e2 1624
QL 9:ca2e6010d9e2 1625 protected:
QL 9:ca2e6010d9e2 1626 /// \brief protected constructor
QL 9:ca2e6010d9e2 1627 ///
QL 9:ca2e6010d9e2 1628 /// Performs the first step of active object initialization by assigning
QL 9:ca2e6010d9e2 1629 /// the initial pseudostate to the currently active state of the state
QL 9:ca2e6010d9e2 1630 /// machine.
QL 9:ca2e6010d9e2 1631 ///
QL 9:ca2e6010d9e2 1632 /// \note The constructor is protected to prevent direct instantiation
QL 9:ca2e6010d9e2 1633 /// of QActive objects. This class is intended only for derivation
QL 9:ca2e6010d9e2 1634 /// (abstract class).
QL 9:ca2e6010d9e2 1635 QActive(QF_ACTIVE_STATE_ const initial) : QF_ACTIVE_SUPER_(initial) {
QL 9:ca2e6010d9e2 1636 }
QL 9:ca2e6010d9e2 1637
QL 9:ca2e6010d9e2 1638 /// \brief Posts an event directly to the event queue of the active object
QL 9:ca2e6010d9e2 1639 /// \a me using the Last-In-First-Out (LIFO) policy.
QL 9:ca2e6010d9e2 1640 ///
QL 9:ca2e6010d9e2 1641 /// \note The LIFO policy should be used only for self-posting and with
QL 9:ca2e6010d9e2 1642 /// great caution because it alters order of events in the queue.
QL 9:ca2e6010d9e2 1643 ///
QL 9:ca2e6010d9e2 1644 /// \sa QActive::postFIFO()
QL 9:ca2e6010d9e2 1645 void postLIFO(QEvt const * const e);
QL 9:ca2e6010d9e2 1646
QL 9:ca2e6010d9e2 1647 /// \brief Stops execution of an active object and removes it from the
QL 9:ca2e6010d9e2 1648 /// framework's supervision.
QL 9:ca2e6010d9e2 1649 ///
QL 9:ca2e6010d9e2 1650 /// The preferred way of calling this function is from within the active
QL 9:ca2e6010d9e2 1651 /// object that needs to stop (that's why this function is protected).
QL 9:ca2e6010d9e2 1652 /// In other words, an active object should stop itself rather than being
QL 9:ca2e6010d9e2 1653 /// stopped by some other entity. This policy works best, because only
QL 9:ca2e6010d9e2 1654 /// the active object itself "knows" when it has reached the appropriate
QL 9:ca2e6010d9e2 1655 /// state for the shutdown.
QL 9:ca2e6010d9e2 1656 ///
QL 9:ca2e6010d9e2 1657 /// \note This function is strongly OS-dependent and should be defined in
QL 9:ca2e6010d9e2 1658 /// the QF port to a particular platform. This function is optional in
QL 9:ca2e6010d9e2 1659 /// embedded systems where active objects never need to be stopped.
QL 9:ca2e6010d9e2 1660 void stop(void);
QL 9:ca2e6010d9e2 1661
QL 9:ca2e6010d9e2 1662 /// \brief Subscribes for delivery of signal \a sig to the active object
QL 9:ca2e6010d9e2 1663 ///
QL 9:ca2e6010d9e2 1664 /// This function is part of the Publish-Subscribe event delivery
QL 9:ca2e6010d9e2 1665 /// mechanism available in QF. Subscribing to an event means that the
QL 9:ca2e6010d9e2 1666 /// framework will start posting all published events with a given signal
QL 9:ca2e6010d9e2 1667 /// \a sig to the event queue of the active object.
QL 9:ca2e6010d9e2 1668 ///
QL 9:ca2e6010d9e2 1669 /// The following example shows how the Table active object subscribes
QL 9:ca2e6010d9e2 1670 /// to three signals in the initial transition:
QL 9:ca2e6010d9e2 1671 /// \include qf_subscribe.cpp
QL 9:ca2e6010d9e2 1672 ///
QL 9:ca2e6010d9e2 1673 /// \sa QF::publish(), QActive::unsubscribe(), and
QL 9:ca2e6010d9e2 1674 /// QActive::unsubscribeAll()
QL 9:ca2e6010d9e2 1675 void subscribe(enum_t const sig) const;
QL 9:ca2e6010d9e2 1676
QL 9:ca2e6010d9e2 1677 /// \brief Un-subscribes from the delivery of signal \a sig to the
QL 9:ca2e6010d9e2 1678 /// active object.
QL 9:ca2e6010d9e2 1679 ///
QL 9:ca2e6010d9e2 1680 /// This function is part of the Publish-Subscribe event delivery
QL 9:ca2e6010d9e2 1681 /// mechanism available in QF. Un-subscribing from an event means that
QL 9:ca2e6010d9e2 1682 /// the framework will stop posting published events with a given signal
QL 9:ca2e6010d9e2 1683 /// \a sig to the event queue of the active object.
QL 9:ca2e6010d9e2 1684 ///
QL 9:ca2e6010d9e2 1685 /// \note Due to the latency of event queues, an active object should NOT
QL 9:ca2e6010d9e2 1686 /// assume that a given signal \a sig will never be dispatched to the
QL 9:ca2e6010d9e2 1687 /// state machine of the active object after un-subscribing from that
QL 9:ca2e6010d9e2 1688 /// signal. The event might be already in the queue, or just about to be
QL 9:ca2e6010d9e2 1689 /// posted and the un-subscribe operation will not flush such events.
QL 9:ca2e6010d9e2 1690 ///
QL 9:ca2e6010d9e2 1691 /// \note Un-subscribing from a signal that has never been subscribed in
QL 9:ca2e6010d9e2 1692 /// the first place is considered an error and QF will rise an assertion.
QL 9:ca2e6010d9e2 1693 ///
QL 9:ca2e6010d9e2 1694 /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribeAll()
QL 9:ca2e6010d9e2 1695 void unsubscribe(enum_t const sig) const;
QL 9:ca2e6010d9e2 1696
QL 9:ca2e6010d9e2 1697 /// \brief Defer an event to a given separate event queue.
QL 9:ca2e6010d9e2 1698 ///
QL 9:ca2e6010d9e2 1699 /// This function is part of the event deferral support. An active object
QL 9:ca2e6010d9e2 1700 /// uses this function to defer an event \a e to the QF-supported native
QL 9:ca2e6010d9e2 1701 /// event queue \a eq. QF correctly accounts for another outstanding
QL 9:ca2e6010d9e2 1702 /// reference to the event and will not recycle the event at the end of
QL 9:ca2e6010d9e2 1703 /// the RTC step. Later, the active object might recall one event at a
QL 9:ca2e6010d9e2 1704 /// time from the event queue.
QL 9:ca2e6010d9e2 1705 ///
QL 9:ca2e6010d9e2 1706 /// An active object can use multiple event queues to defer events of
QL 9:ca2e6010d9e2 1707 /// different kinds.
QL 9:ca2e6010d9e2 1708 ///
QL 9:ca2e6010d9e2 1709 /// \sa QActive::recall(), QEQueue
QL 9:ca2e6010d9e2 1710 void defer(QEQueue * const eq, QEvt const * const e) const;
QL 9:ca2e6010d9e2 1711
QL 9:ca2e6010d9e2 1712 /// \brief Recall a deferred event from a given event queue.
QL 9:ca2e6010d9e2 1713 ///
QL 9:ca2e6010d9e2 1714 /// This function is part of the event deferral support. An active object
QL 9:ca2e6010d9e2 1715 /// uses this function to recall a deferred event from a given QF
QL 9:ca2e6010d9e2 1716 /// event queue. Recalling an event means that it is removed from the
QL 9:ca2e6010d9e2 1717 /// deferred event queue \a eq and posted (LIFO) to the event queue of
QL 9:ca2e6010d9e2 1718 /// the active object.
QL 9:ca2e6010d9e2 1719 ///
QL 9:ca2e6010d9e2 1720 /// QActive::recall() returns true if an event has been recalled.
QL 9:ca2e6010d9e2 1721 /// Otherwise the function returns false.
QL 9:ca2e6010d9e2 1722 ///
QL 9:ca2e6010d9e2 1723 /// An active object can use multiple event queues to defer events of
QL 9:ca2e6010d9e2 1724 /// different kinds.
QL 9:ca2e6010d9e2 1725 ///
QL 9:ca2e6010d9e2 1726 /// \sa QActive::defer(), QEQueue, QActive::postLIFO()
QL 9:ca2e6010d9e2 1727 bool recall(QEQueue * const eq);
QL 9:ca2e6010d9e2 1728
QL 9:ca2e6010d9e2 1729 private:
QL 9:ca2e6010d9e2 1730
QL 9:ca2e6010d9e2 1731 /// \brief Get an event from the event queue of an active object.
QL 9:ca2e6010d9e2 1732 ///
QL 9:ca2e6010d9e2 1733 /// This function is used internally by a QF port to extract events from
QL 9:ca2e6010d9e2 1734 /// the event queue of an active object. This function depends on the
QL 9:ca2e6010d9e2 1735 /// event queue implementation and is sometimes implemented in the QF port
QL 9:ca2e6010d9e2 1736 /// (qf_port.cpp file). Depending on the underlying OS or kernel, the
QL 9:ca2e6010d9e2 1737 /// function might block the calling thread when no events are available.
QL 9:ca2e6010d9e2 1738 ///
QL 9:ca2e6010d9e2 1739 /// \note QActive::get_() is public because it often needs to be called
QL 9:ca2e6010d9e2 1740 /// from thread-run routines with difficult to foresee signature (so
QL 9:ca2e6010d9e2 1741 /// declaring friendship with such function(s) is not possible.)
QL 9:ca2e6010d9e2 1742 ///
QL 9:ca2e6010d9e2 1743 /// \sa QActive::postFIFO(), QActive::postLIFO()
QL 9:ca2e6010d9e2 1744 QEvt const *get_(void);
QL 9:ca2e6010d9e2 1745
QL 9:ca2e6010d9e2 1746 friend class QF;
QL 9:ca2e6010d9e2 1747 friend class QTimeEvt;
QL 9:ca2e6010d9e2 1748
QL 9:ca2e6010d9e2 1749 #ifdef QK_PREEMPTIVE // is this QK port?
QL 9:ca2e6010d9e2 1750 friend void ::QK_schedExt_(uint8_t p);
QL 9:ca2e6010d9e2 1751 friend void ::QK_sched_(uint8_t p);
QL 9:ca2e6010d9e2 1752 #endif
QL 9:ca2e6010d9e2 1753
QL 9:ca2e6010d9e2 1754 };
QL 9:ca2e6010d9e2 1755
QL 9:ca2e6010d9e2 1756 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1757 /// \brief Time Event class
QL 9:ca2e6010d9e2 1758 ///
QL 9:ca2e6010d9e2 1759 /// Time events are special QF events equipped with the notion of time
QL 9:ca2e6010d9e2 1760 /// passage. The basic usage model of the time events is as follows. An
QL 9:ca2e6010d9e2 1761 /// active object allocates one or more QTimeEvt objects (provides the
QL 9:ca2e6010d9e2 1762 /// storage for them). When the active object needs to arrange for a timeout,
QL 9:ca2e6010d9e2 1763 /// it arms one of its time events to fire either just once (one-shot) or
QL 9:ca2e6010d9e2 1764 /// periodically. Each time event times out independently from the others,
QL 9:ca2e6010d9e2 1765 /// so a QF application can make multiple parallel timeout requests (from the
QL 9:ca2e6010d9e2 1766 /// same or different active objects). When QF detects that the appropriate
QL 9:ca2e6010d9e2 1767 /// moment has arrived, it inserts the time event directly into the
QL 9:ca2e6010d9e2 1768 /// recipient's event queue. The recipient then processes the time event just
QL 9:ca2e6010d9e2 1769 /// like any other event.
QL 9:ca2e6010d9e2 1770 ///
QL 9:ca2e6010d9e2 1771 /// Time events, as any other QF events derive from the ::QEvt base
QL 9:ca2e6010d9e2 1772 /// class. Typically, you will use a time event as-is, but you can also
QL 9:ca2e6010d9e2 1773 /// further derive more specialized time events from it by adding some more
QL 9:ca2e6010d9e2 1774 /// data members and/or specialized functions that operate on the specialized
QL 9:ca2e6010d9e2 1775 /// time events.
QL 9:ca2e6010d9e2 1776 ///
QL 9:ca2e6010d9e2 1777 /// Internally, the armed time events are organized into a bi-directional
QL 9:ca2e6010d9e2 1778 /// linked list. This linked list is scanned in every invocation of the
QL 9:ca2e6010d9e2 1779 /// QF::tick() function. Only armed (timing out) time events are in the list,
QL 9:ca2e6010d9e2 1780 /// so only armed time events consume CPU cycles.
QL 9:ca2e6010d9e2 1781 ///
QL 9:ca2e6010d9e2 1782 /// \note QF manages the time events in the function QF::tick(), which
QL 9:ca2e6010d9e2 1783 /// must be called periodically, preferably from the clock tick ISR.
QL 9:ca2e6010d9e2 1784 /// \note In this version of QF QTimeEvt objects should be allocated
QL 9:ca2e6010d9e2 1785 /// statically rather than dynamically from event pools. Currently, QF will
QL 9:ca2e6010d9e2 1786 /// not correctly recycle the dynamically allocated Time Events.
QL 9:ca2e6010d9e2 1787 class QTimeEvt : public QEvt {
QL 9:ca2e6010d9e2 1788 private:
QL 9:ca2e6010d9e2 1789
QL 9:ca2e6010d9e2 1790 /// link to the next time event in the list
QL 9:ca2e6010d9e2 1791 QTimeEvt *m_next;
QL 9:ca2e6010d9e2 1792
QL 9:ca2e6010d9e2 1793 /// the active object that receives the time events.
QL 9:ca2e6010d9e2 1794 QActive *m_act;
QL 9:ca2e6010d9e2 1795
QL 9:ca2e6010d9e2 1796 /// the internal down-counter of the time event. The down-counter
QL 9:ca2e6010d9e2 1797 /// is decremented by 1 in every QF_tick() invocation. The time event
QL 9:ca2e6010d9e2 1798 /// fires (gets posted or published) when the down-counter reaches zero.
QL 9:ca2e6010d9e2 1799 QTimeEvtCtr m_ctr;
QL 9:ca2e6010d9e2 1800
QL 9:ca2e6010d9e2 1801 /// the interval for the periodic time event (zero for the one-shot
QL 9:ca2e6010d9e2 1802 /// time event). The value of the interval is re-loaded to the internal
QL 9:ca2e6010d9e2 1803 /// down-counter when the time event expires, so that the time event
QL 9:ca2e6010d9e2 1804 /// keeps timing out periodically.
QL 9:ca2e6010d9e2 1805 QTimeEvtCtr m_interval;
QL 9:ca2e6010d9e2 1806
QL 9:ca2e6010d9e2 1807 public:
QL 9:ca2e6010d9e2 1808
QL 9:ca2e6010d9e2 1809 /// \brief The Time Event constructor.
QL 9:ca2e6010d9e2 1810 ///
QL 9:ca2e6010d9e2 1811 /// The most important initialization performed in the constructor is
QL 9:ca2e6010d9e2 1812 /// assigning a signal to the Time Event. You can reuse the Time Event
QL 9:ca2e6010d9e2 1813 /// any number of times, but you cannot change the signal.
QL 9:ca2e6010d9e2 1814 /// This is because pointers to Time Events might still be held in event
QL 9:ca2e6010d9e2 1815 /// queues and changing signal could to hard-to-detect errors.
QL 9:ca2e6010d9e2 1816 ///
QL 9:ca2e6010d9e2 1817 /// The following example shows the use of QTimeEvt::QTimeEvt()
QL 9:ca2e6010d9e2 1818 /// constructor in the constructor initializer list of the Philosopher
QL 9:ca2e6010d9e2 1819 /// active object constructor that owns the time event
QL 9:ca2e6010d9e2 1820 /// \include qf_ctor.cpp
QL 9:ca2e6010d9e2 1821 QTimeEvt(enum_t const s);
QL 9:ca2e6010d9e2 1822
QL 9:ca2e6010d9e2 1823 /// \brief Arm a one-shot time event for direct event posting.
QL 9:ca2e6010d9e2 1824 ///
QL 9:ca2e6010d9e2 1825 /// Arms a time event to fire in \a nTicks clock ticks (one-shot time
QL 9:ca2e6010d9e2 1826 /// event). The time event gets directly posted (using the FIFO policy)
QL 9:ca2e6010d9e2 1827 /// into the event queue of the active object \a act.
QL 9:ca2e6010d9e2 1828 ///
QL 9:ca2e6010d9e2 1829 /// After posting, the time event gets automatically disarmed and can be
QL 9:ca2e6010d9e2 1830 /// reused for a one-shot or periodic timeout requests.
QL 9:ca2e6010d9e2 1831 ///
QL 9:ca2e6010d9e2 1832 /// A one-shot time event can be disarmed at any time by calling the
QL 9:ca2e6010d9e2 1833 /// QTimeEvt::disarm() function. Also, a one-shot time event can be
QL 9:ca2e6010d9e2 1834 /// re-armed to fire in a different number of clock ticks by calling the
QL 9:ca2e6010d9e2 1835 /// QTimeEvt::rearm() function.
QL 9:ca2e6010d9e2 1836 ///
QL 9:ca2e6010d9e2 1837 /// The following example shows how to arm a one-shot time event from a
QL 9:ca2e6010d9e2 1838 /// state machine of an active object:
QL 9:ca2e6010d9e2 1839 /// \include qf_state.cpp
QL 9:ca2e6010d9e2 1840 void postIn(QActive * const act, QTimeEvtCtr const nTicks) {
QL 9:ca2e6010d9e2 1841 m_interval = static_cast<QTimeEvtCtr>(0);
QL 9:ca2e6010d9e2 1842 arm_(act, nTicks);
QL 9:ca2e6010d9e2 1843 }
QL 9:ca2e6010d9e2 1844
QL 9:ca2e6010d9e2 1845 /// \brief Arm a periodic time event for direct event posting.
QL 9:ca2e6010d9e2 1846 ///
QL 9:ca2e6010d9e2 1847 /// Arms a time event to fire every \a nTicks clock ticks (periodic time
QL 9:ca2e6010d9e2 1848 /// event). The time event gets directly posted (using the FIFO policy)
QL 9:ca2e6010d9e2 1849 /// into the event queue of the active object \a act.
QL 9:ca2e6010d9e2 1850 ///
QL 9:ca2e6010d9e2 1851 /// After posting, the time event gets automatically re-armed to fire
QL 9:ca2e6010d9e2 1852 /// again in the specified \a nTicks clock ticks.
QL 9:ca2e6010d9e2 1853 ///
QL 9:ca2e6010d9e2 1854 /// A periodic time event can be disarmed only by calling the
QL 9:ca2e6010d9e2 1855 /// QTimeEvt::disarm() function. After disarming, the time event can be
QL 9:ca2e6010d9e2 1856 /// reused for a one-shot or periodic timeout requests.
QL 9:ca2e6010d9e2 1857 ///
QL 9:ca2e6010d9e2 1858 /// \note An attempt to reuse (arm again) a running periodic time event
QL 9:ca2e6010d9e2 1859 /// raises an assertion.
QL 9:ca2e6010d9e2 1860 ///
QL 9:ca2e6010d9e2 1861 /// Also, a periodic time event can be re-armed to shorten or extend the
QL 9:ca2e6010d9e2 1862 /// current period by calling the QTimeEvt_rearm() function. After
QL 9:ca2e6010d9e2 1863 /// adjusting the current period, the periodic time event goes back
QL 9:ca2e6010d9e2 1864 /// timing out at the original rate.
QL 9:ca2e6010d9e2 1865 void postEvery(QActive * const act, QTimeEvtCtr const nTicks) {
QL 9:ca2e6010d9e2 1866 m_interval = nTicks;
QL 9:ca2e6010d9e2 1867 arm_(act, nTicks);
QL 9:ca2e6010d9e2 1868 }
QL 9:ca2e6010d9e2 1869
QL 9:ca2e6010d9e2 1870 /// \brief Disarm a time event.
QL 9:ca2e6010d9e2 1871 ///
QL 9:ca2e6010d9e2 1872 /// The time event gets disarmed and can be reused. The function
QL 9:ca2e6010d9e2 1873 /// returns true if the time event was truly disarmed, that is, it
QL 9:ca2e6010d9e2 1874 /// was running. The return of false means that the time event was
QL 9:ca2e6010d9e2 1875 /// not truly disarmed because it was not running. The 'false' return is
QL 9:ca2e6010d9e2 1876 /// only possible for one-shot time events that have been automatically
QL 9:ca2e6010d9e2 1877 /// disarmed upon expiration. In this case the 'false' return means that
QL 9:ca2e6010d9e2 1878 /// the time event has already been posted or published and should be
QL 9:ca2e6010d9e2 1879 /// expected in the active object's state machine.
QL 9:ca2e6010d9e2 1880 bool disarm(void);
QL 9:ca2e6010d9e2 1881
QL 9:ca2e6010d9e2 1882 /// \brief Rearm a time event.
QL 9:ca2e6010d9e2 1883 ///
QL 9:ca2e6010d9e2 1884 /// The time event gets rearmed with a new number of clock ticks
QL 9:ca2e6010d9e2 1885 /// \a nTicks. This facility can be used to prevent a one-shot time event
QL 9:ca2e6010d9e2 1886 /// from expiring (e.g., a watchdog time event), or to adjusts the
QL 9:ca2e6010d9e2 1887 /// current period of a periodic time event. Rearming a periodic timer
QL 9:ca2e6010d9e2 1888 /// leaves the interval unchanged and is a convenient method to adjust
QL 9:ca2e6010d9e2 1889 /// the phasing of the periodic time event.
QL 9:ca2e6010d9e2 1890 ///
QL 9:ca2e6010d9e2 1891 /// The function returns true if the time event was running as it
QL 9:ca2e6010d9e2 1892 /// was re-armed. The return of false means that the time event was
QL 9:ca2e6010d9e2 1893 /// not truly rearmed because it was not running. The 'false' return is
QL 9:ca2e6010d9e2 1894 /// only possible for one-shot time events that have been automatically
QL 9:ca2e6010d9e2 1895 /// disarmed upon expiration. In this case the 'false' return means that
QL 9:ca2e6010d9e2 1896 /// the time event has already been posted or published and should be
QL 9:ca2e6010d9e2 1897 /// expected in the active object's state machine.
QL 9:ca2e6010d9e2 1898 bool rearm(QTimeEvtCtr const nTicks);
QL 9:ca2e6010d9e2 1899
QL 9:ca2e6010d9e2 1900 /// \brief Get the current value of the down-counter of a time event.
QL 9:ca2e6010d9e2 1901 ///
QL 9:ca2e6010d9e2 1902 /// If the time event is armed, the function returns the current value of
QL 9:ca2e6010d9e2 1903 /// the down-counter of the given time event. If the time event is not
QL 9:ca2e6010d9e2 1904 /// armed, the function returns 0.
QL 9:ca2e6010d9e2 1905 ///
QL 9:ca2e6010d9e2 1906 /// /note The function is thread-safe.
QL 9:ca2e6010d9e2 1907 QTimeEvtCtr ctr(void) const;
QL 9:ca2e6010d9e2 1908
QL 9:ca2e6010d9e2 1909 private:
QL 9:ca2e6010d9e2 1910
QL 9:ca2e6010d9e2 1911 /// \brief Arm a time event (internal function to be used through macros
QL 9:ca2e6010d9e2 1912 /// only).
QL 9:ca2e6010d9e2 1913 ///
QL 9:ca2e6010d9e2 1914 /// \sa QTimeEvt::postIn(), QTimeEvt::postEvery(),
QL 9:ca2e6010d9e2 1915 /// \sa QTimeEvt::publishIn(), QTimeEvt::publishEvery()
QL 9:ca2e6010d9e2 1916 void arm_(QActive * const act, QTimeEvtCtr const nTicks);
QL 9:ca2e6010d9e2 1917
QL 9:ca2e6010d9e2 1918 friend class QF;
QL 9:ca2e6010d9e2 1919 };
QL 9:ca2e6010d9e2 1920
QL 9:ca2e6010d9e2 1921
QL 9:ca2e6010d9e2 1922 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1923 /// \brief The size of the Subscriber list bit array
QL 9:ca2e6010d9e2 1924 ///
QL 9:ca2e6010d9e2 1925 /// The size is determined of the maximum number of active objects in the
QL 9:ca2e6010d9e2 1926 /// application configured by the #QF_MAX_ACTIVE macro.
QL 9:ca2e6010d9e2 1927 uint8_t const QF_SUBSCR_LIST_SIZE =
QL 9:ca2e6010d9e2 1928 static_cast<uint8_t>(((QF_MAX_ACTIVE - 1) / 8) + 1);
QL 9:ca2e6010d9e2 1929
QL 9:ca2e6010d9e2 1930 /// \brief Subscriber List class
QL 9:ca2e6010d9e2 1931 ///
QL 9:ca2e6010d9e2 1932 /// This data type represents a set of active objects that subscribe to
QL 9:ca2e6010d9e2 1933 /// a given signal. The set is represented as an array of bits, where each
QL 9:ca2e6010d9e2 1934 /// bit corresponds to the unique priority of an active object.
QL 9:ca2e6010d9e2 1935 class QSubscrList {
QL 9:ca2e6010d9e2 1936 private:
QL 9:ca2e6010d9e2 1937
QL 9:ca2e6010d9e2 1938 /// An array of bits representing subscriber active objects. Each bit
QL 9:ca2e6010d9e2 1939 /// in the array corresponds to the unique priority of the active object.
QL 9:ca2e6010d9e2 1940 /// The size of the array is determined of the maximum number of active
QL 9:ca2e6010d9e2 1941 /// objects in the application configured by the #QF_MAX_ACTIVE macro.
QL 9:ca2e6010d9e2 1942 /// For example, an active object of priority p is a subscriber if the
QL 9:ca2e6010d9e2 1943 /// following is true: ((m_bits[QF_div8Lkup[p]] & QF_pwr2Lkup[p]) != 0)
QL 9:ca2e6010d9e2 1944 ///
QL 9:ca2e6010d9e2 1945 /// \sa QF::psInit(), QF_div8Lkup, QF_pwr2Lkup, #QF_MAX_ACTIVE
QL 9:ca2e6010d9e2 1946 uint8_t m_bits[QF_SUBSCR_LIST_SIZE];
QL 9:ca2e6010d9e2 1947
QL 9:ca2e6010d9e2 1948 friend class QF;
QL 9:ca2e6010d9e2 1949 friend class QActive;
QL 9:ca2e6010d9e2 1950 };
QL 9:ca2e6010d9e2 1951
QL 9:ca2e6010d9e2 1952 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 1953 /// \brief QF services.
QL 9:ca2e6010d9e2 1954 ///
QL 9:ca2e6010d9e2 1955 /// This class groups together QF services. It has only static members and
QL 9:ca2e6010d9e2 1956 /// should not be instantiated.
QL 9:ca2e6010d9e2 1957 class QF {
QL 9:ca2e6010d9e2 1958 public:
QL 9:ca2e6010d9e2 1959
QL 9:ca2e6010d9e2 1960 /// \brief QF initialization.
QL 9:ca2e6010d9e2 1961 ///
QL 9:ca2e6010d9e2 1962 /// This function initializes QF and must be called exactly once before
QL 9:ca2e6010d9e2 1963 /// any other QF function.
QL 9:ca2e6010d9e2 1964 static void init(void);
QL 9:ca2e6010d9e2 1965
QL 9:ca2e6010d9e2 1966 /// \brief Publish-subscribe initialization.
QL 9:ca2e6010d9e2 1967 ///
QL 9:ca2e6010d9e2 1968 /// This function initializes the publish-subscribe facilities of QF and
QL 9:ca2e6010d9e2 1969 /// must be called exactly once before any subscriptions/publications
QL 9:ca2e6010d9e2 1970 /// occur in the application. The arguments are as follows: \a subscrSto
QL 9:ca2e6010d9e2 1971 /// is a pointer to the array of subscriber-lists. \a maxSignal is the
QL 9:ca2e6010d9e2 1972 /// dimension of this array and at the same time the maximum signal that
QL 9:ca2e6010d9e2 1973 /// can be published or subscribed.
QL 9:ca2e6010d9e2 1974 ///
QL 9:ca2e6010d9e2 1975 /// The array of subscriber-lists is indexed by signals and provides
QL 9:ca2e6010d9e2 1976 /// mapping between the signals and subscirber-lists. The subscriber-
QL 9:ca2e6010d9e2 1977 /// lists are bitmasks of type ::QSubscrList, each bit in the bitmask
QL 9:ca2e6010d9e2 1978 /// corresponding to the unique priority of an active object. The size
QL 9:ca2e6010d9e2 1979 /// of the ::QSubscrList bitmask depends on the value of the
QL 9:ca2e6010d9e2 1980 /// #QF_MAX_ACTIVE macro.
QL 9:ca2e6010d9e2 1981 ///
QL 9:ca2e6010d9e2 1982 /// \note The publish-subscribe facilities are optional, meaning that
QL 9:ca2e6010d9e2 1983 /// you might choose not to use publish-subscribe. In that case calling
QL 9:ca2e6010d9e2 1984 /// QF::psInit() and using up memory for the subscriber-lists is
QL 9:ca2e6010d9e2 1985 /// unnecessary.
QL 9:ca2e6010d9e2 1986 ///
QL 9:ca2e6010d9e2 1987 /// \sa ::QSubscrList
QL 9:ca2e6010d9e2 1988 ///
QL 9:ca2e6010d9e2 1989 /// The following example shows the typical initialization sequence of
QL 9:ca2e6010d9e2 1990 /// QF: \include qf_main.cpp
QL 9:ca2e6010d9e2 1991 static void psInit(QSubscrList * const subscrSto,
QL 9:ca2e6010d9e2 1992 uint32_t const maxSignal);
QL 9:ca2e6010d9e2 1993
QL 9:ca2e6010d9e2 1994 /// \brief Event pool initialization for dynamic allocation of events.
QL 9:ca2e6010d9e2 1995 ///
QL 9:ca2e6010d9e2 1996 /// This function initializes one event pool at a time and must be called
QL 9:ca2e6010d9e2 1997 /// exactly once for each event pool before the pool can be used.
QL 9:ca2e6010d9e2 1998 /// The arguments are as follows: \a poolSto is a pointer to the memory
QL 9:ca2e6010d9e2 1999 /// block for the events. \a poolSize is the size of the memory block in
QL 9:ca2e6010d9e2 2000 /// bytes. \a evtSize is the block-size of the pool in bytes, which
QL 9:ca2e6010d9e2 2001 /// determines the maximum size of events that can be allocated from the
QL 9:ca2e6010d9e2 2002 /// pool.
QL 9:ca2e6010d9e2 2003 ///
QL 9:ca2e6010d9e2 2004 /// You might initialize one, two, and up to three event pools by making
QL 9:ca2e6010d9e2 2005 /// one, two, or three calls to the QF_poolInit() function. However,
QL 9:ca2e6010d9e2 2006 /// for the simplicity of the internal implementation, you must initialize
QL 9:ca2e6010d9e2 2007 /// event pools in the ascending order of the event size.
QL 9:ca2e6010d9e2 2008 ///
QL 9:ca2e6010d9e2 2009 /// Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that
QL 9:ca2e6010d9e2 2010 /// can be used for QF event pools. In case such support is missing, QF
QL 9:ca2e6010d9e2 2011 /// provides a native QF event pool implementation. The macro
QL 9:ca2e6010d9e2 2012 /// #QF_EPOOL_TYPE_ determines the type of event pool used by a
QL 9:ca2e6010d9e2 2013 /// particular QF port. See class ::QMPool for more information.
QL 9:ca2e6010d9e2 2014 ///
QL 9:ca2e6010d9e2 2015 /// \note The actual number of events available in the pool might be
QL 9:ca2e6010d9e2 2016 /// actually less than (\a poolSize / \a evtSize) due to the internal
QL 9:ca2e6010d9e2 2017 /// alignment of the blocks that the pool might perform. You can always
QL 9:ca2e6010d9e2 2018 /// check the capacity of the pool by calling QF::getPoolMargin().
QL 9:ca2e6010d9e2 2019 ///
QL 9:ca2e6010d9e2 2020 /// \note The dynamic allocation of events is optional, meaning that you
QL 9:ca2e6010d9e2 2021 /// might choose not to use dynamic events. In that case calling
QL 9:ca2e6010d9e2 2022 /// QF::poolInit() and using up memory for the memory blocks is
QL 9:ca2e6010d9e2 2023 /// unnecessary.
QL 9:ca2e6010d9e2 2024 ///
QL 9:ca2e6010d9e2 2025 /// \sa QF initialization example for QF::init()
QL 9:ca2e6010d9e2 2026 static void poolInit(void * const poolSto, uint32_t const poolSize,
QL 9:ca2e6010d9e2 2027 uint32_t const evtSize);
QL 9:ca2e6010d9e2 2028
QL 9:ca2e6010d9e2 2029 /// \brief Transfers control to QF to run the application.
QL 9:ca2e6010d9e2 2030 ///
QL 9:ca2e6010d9e2 2031 /// QF::run() is typically called from your startup code after you
QL 9:ca2e6010d9e2 2032 /// initialize the QF and start at least one active object with
QL 9:ca2e6010d9e2 2033 /// QActive::start(). Also, QF::start() call must precede the transfer
QL 9:ca2e6010d9e2 2034 /// of control to QF::run(), but some QF ports might call QF::start()
QL 9:ca2e6010d9e2 2035 /// from QF::run(). QF::run() typically never returns to the caller,
QL 9:ca2e6010d9e2 2036 /// but when it does, it returns the error code (0 for success)
QL 9:ca2e6010d9e2 2037 ///
QL 9:ca2e6010d9e2 2038 /// \note This function is strongly platform-dependent and is not
QL 9:ca2e6010d9e2 2039 /// implemented in the QF, but either in the QF port or in the
QL 9:ca2e6010d9e2 2040 /// Board Support Package (BSP) for the given application. All QF ports
QL 9:ca2e6010d9e2 2041 /// must implement QF::run().
QL 9:ca2e6010d9e2 2042 ///
QL 9:ca2e6010d9e2 2043 /// \note When the Quantum Kernel (QK) is used as the underlying real-time
QL 9:ca2e6010d9e2 2044 /// kernel for the QF, all platfrom dependencies are handled in the QK, so
QL 9:ca2e6010d9e2 2045 /// no porting of QF is necessary. In other words, you only need to
QL 9:ca2e6010d9e2 2046 /// recompile the QF platform-independent code with the compiler for your
QL 9:ca2e6010d9e2 2047 /// platform, but you don't need to provide any platform-specific
QL 9:ca2e6010d9e2 2048 /// implementation (so, no qf_port.cpp file is necessary). Moreover, QK
QL 9:ca2e6010d9e2 2049 /// implements the function QF::run() in a platform-independent way,
QL 9:ca2e6010d9e2 2050 /// in the modile qk.cpp.
QL 9:ca2e6010d9e2 2051 static int16_t run(void);
QL 9:ca2e6010d9e2 2052
QL 9:ca2e6010d9e2 2053 /// \brief Startup QF callback.
QL 9:ca2e6010d9e2 2054 ///
QL 9:ca2e6010d9e2 2055 /// The timeline for calling QF::onStartup() depends on the particular
QL 9:ca2e6010d9e2 2056 /// QF port. In most cases, QF::onStartup() is called from QF::run(),
QL 9:ca2e6010d9e2 2057 /// right before starting any multitasking kernel or the background loop.
QL 9:ca2e6010d9e2 2058 static void onStartup(void);
QL 9:ca2e6010d9e2 2059
QL 9:ca2e6010d9e2 2060 /// \brief Cleanup QF callback.
QL 9:ca2e6010d9e2 2061 ///
QL 9:ca2e6010d9e2 2062 /// QF::onCleanup() is called in some QF ports before QF returns to the
QL 9:ca2e6010d9e2 2063 /// underlying operating system or RTOS.
QL 9:ca2e6010d9e2 2064 ///
QL 9:ca2e6010d9e2 2065 /// This function is strongly platform-specific and is not implemented in
QL 9:ca2e6010d9e2 2066 /// the QF but either in the QF port or in the Board Support Package (BSP)
QL 9:ca2e6010d9e2 2067 /// for the given application. Some QF ports might not require
QL 9:ca2e6010d9e2 2068 /// implementing QF::onCleanup() at all, because many embedded
QL 9:ca2e6010d9e2 2069 /// applications don't have anything to exit to.
QL 9:ca2e6010d9e2 2070 ///
QL 9:ca2e6010d9e2 2071 /// \sa QF::init() and QF::stop()
QL 9:ca2e6010d9e2 2072 static void onCleanup(void);
QL 9:ca2e6010d9e2 2073
QL 9:ca2e6010d9e2 2074 /// \brief QF idle callback (customized in BSPs for QF)
QL 9:ca2e6010d9e2 2075 ///
QL 9:ca2e6010d9e2 2076 /// QF::onIdle() is called by the non-preemptive "Vanilla" scheduler built
QL 9:ca2e6010d9e2 2077 /// into QF when the framework detects that no events are available for
QL 9:ca2e6010d9e2 2078 /// active objects (the idle condition). This callback gives the
QL 9:ca2e6010d9e2 2079 /// application an opportunity to enter a power-saving CPU mode, or
QL 9:ca2e6010d9e2 2080 /// perform some other idle processing (such as Q-Spy output).
QL 9:ca2e6010d9e2 2081 ///
QL 9:ca2e6010d9e2 2082 /// \note QF_onIdle() is invoked with interrupts DISABLED because the idle
QL 9:ca2e6010d9e2 2083 /// condition can be asynchronously changed at any time by an interrupt.
QL 9:ca2e6010d9e2 2084 /// QF_onIdle() MUST enable the interrupts internally, but not before
QL 9:ca2e6010d9e2 2085 /// putting the CPU into the low-power mode. (Ideally, enabling interrupts
QL 9:ca2e6010d9e2 2086 /// and low-power mode should happen atomically). At the very least, the
QL 9:ca2e6010d9e2 2087 /// function MUST enable interrupts, otherwise interrups will remain
QL 9:ca2e6010d9e2 2088 /// disabled permanently.
QL 9:ca2e6010d9e2 2089 ///
QL 9:ca2e6010d9e2 2090 /// \note QF::onIdle() is only used by the non-preemptive "Vanilla"
QL 9:ca2e6010d9e2 2091 /// scheduler in the "bare metal" QF port, and is NOT used in any other
QL 9:ca2e6010d9e2 2092 /// QF ports. When QF is combined with QK, the QK idle loop calls a
QL 9:ca2e6010d9e2 2093 /// different function QK::onIdle(), with different semantics than
QL 9:ca2e6010d9e2 2094 /// QF::onIdle(). When QF is combined with a 3rd-party RTOS or kernel, the
QL 9:ca2e6010d9e2 2095 /// idle processing mechanism of the RTOS or kernal is used instead of
QL 9:ca2e6010d9e2 2096 /// QF::onIdle().
QL 9:ca2e6010d9e2 2097 ///
QL 9:ca2e6010d9e2 2098 static void onIdle(void);
QL 9:ca2e6010d9e2 2099
QL 9:ca2e6010d9e2 2100 /// \brief Function invoked by the application layer to stop the QF
QL 9:ca2e6010d9e2 2101 /// application and return control to the OS/Kernel.
QL 9:ca2e6010d9e2 2102 ///
QL 9:ca2e6010d9e2 2103 /// This function stops the QF application. After calling this function,
QL 9:ca2e6010d9e2 2104 /// QF attempts to gracefully stop the application. This graceful
QL 9:ca2e6010d9e2 2105 /// shutdown might take some time to complete. The typical use of this
QL 9:ca2e6010d9e2 2106 /// funcition is for terminating the QF application to return back to the
QL 9:ca2e6010d9e2 2107 /// operating system or for handling fatal errors that require shutting
QL 9:ca2e6010d9e2 2108 /// down (and possibly re-setting) the system.
QL 9:ca2e6010d9e2 2109 ///
QL 9:ca2e6010d9e2 2110 /// This function is strongly platform-specific and is not implemented in
QL 9:ca2e6010d9e2 2111 /// the QF but either in the QF port or in the Board Support Package (BSP)
QL 9:ca2e6010d9e2 2112 /// for the given application. Some QF ports might not require
QL 9:ca2e6010d9e2 2113 /// implementing QF::stop() at all, because many embedded application
QL 9:ca2e6010d9e2 2114 /// don't have anything to exit to.
QL 9:ca2e6010d9e2 2115 ///
QL 9:ca2e6010d9e2 2116 /// \sa QF::stop() and QF::onCleanup()
QL 9:ca2e6010d9e2 2117 static void stop(void);
QL 9:ca2e6010d9e2 2118
QL 9:ca2e6010d9e2 2119 /// \brief Publish event to the framework.
QL 9:ca2e6010d9e2 2120 ///
QL 9:ca2e6010d9e2 2121 /// This function posts (using the FIFO policy) the event \a e it to ALL
QL 9:ca2e6010d9e2 2122 /// active object that have subscribed to the signal \a e->sig.
QL 9:ca2e6010d9e2 2123 /// This function is designed to be callable from any part of the system,
QL 9:ca2e6010d9e2 2124 /// including ISRs, device drivers, and active objects.
QL 9:ca2e6010d9e2 2125 ///
QL 9:ca2e6010d9e2 2126 /// In the general case, event publishing requires multi-casting the
QL 9:ca2e6010d9e2 2127 /// event to multiple subscribers. This happens in the caller's thread
QL 9:ca2e6010d9e2 2128 /// with the scheduler locked to prevent preemptions during the multi-
QL 9:ca2e6010d9e2 2129 /// casting process. (Please note that the interrupts are not locked.)
QL 9:ca2e6010d9e2 2130 #ifndef Q_SPY
QL 9:ca2e6010d9e2 2131 static void publish(QEvt const *e);
QL 9:ca2e6010d9e2 2132 #else
QL 9:ca2e6010d9e2 2133 static void publish(QEvt const *e, void const *sender);
QL 9:ca2e6010d9e2 2134 #endif
QL 9:ca2e6010d9e2 2135
QL 9:ca2e6010d9e2 2136 /// \brief Processes all armed time events at every clock tick.
QL 9:ca2e6010d9e2 2137 ///
QL 9:ca2e6010d9e2 2138 /// This function must be called periodically from a time-tick ISR or from
QL 9:ca2e6010d9e2 2139 /// the highest-priority task so that QF can manage the timeout events.
QL 9:ca2e6010d9e2 2140 ///
QL 9:ca2e6010d9e2 2141 /// \note The QF::tick() function is not reentrant meaning that it must
QL 9:ca2e6010d9e2 2142 /// run to completion before it is called again. Also, QF::tick() assumes
QL 9:ca2e6010d9e2 2143 /// that it never will get preempted by a task, which is always the case
QL 9:ca2e6010d9e2 2144 /// when it is called from an ISR or the highest-priority task.
QL 9:ca2e6010d9e2 2145 ///
QL 9:ca2e6010d9e2 2146 /// \sa ::QTimeEvt.
QL 9:ca2e6010d9e2 2147 ///
QL 9:ca2e6010d9e2 2148 /// The following example illustrates the call to QF::tick():
QL 9:ca2e6010d9e2 2149 /// \include qf_tick.cpp
QL 9:ca2e6010d9e2 2150 #ifndef Q_SPY
QL 9:ca2e6010d9e2 2151 static void tick(void);
QL 9:ca2e6010d9e2 2152 #else
QL 9:ca2e6010d9e2 2153 static void tick(void const * const sender);
QL 9:ca2e6010d9e2 2154 #endif
QL 9:ca2e6010d9e2 2155
QL 9:ca2e6010d9e2 2156 /// \brief Returns true if all time events are inactive and false
QL 9:ca2e6010d9e2 2157 /// any time event is active.
QL 9:ca2e6010d9e2 2158 ///
QL 9:ca2e6010d9e2 2159 /// \note This function should be called in critical section.
QL 9:ca2e6010d9e2 2160 static bool noTimeEvtsActive(void);
QL 9:ca2e6010d9e2 2161
QL 9:ca2e6010d9e2 2162 /// \brief Returns the QF version.
QL 9:ca2e6010d9e2 2163 ///
QL 9:ca2e6010d9e2 2164 /// This function returns constant version string in the format x.y.zz,
QL 9:ca2e6010d9e2 2165 /// where x (one digit) is the major version, y (one digit) is the minor
QL 9:ca2e6010d9e2 2166 /// version, and zz (two digits) is the maintenance release version.
QL 9:ca2e6010d9e2 2167 /// An example of the version string is "3.1.03".
QL 9:ca2e6010d9e2 2168 ///
QL 9:ca2e6010d9e2 2169 /// The following example illustrates the usage of this function:
QL 9:ca2e6010d9e2 2170 /// \include qf_version.cpp
QL 9:ca2e6010d9e2 2171 static char_t const Q_ROM * Q_ROM_VAR getVersion(void);
QL 9:ca2e6010d9e2 2172
QL 9:ca2e6010d9e2 2173 /// \brief This function returns the margin of the given event pool.
QL 9:ca2e6010d9e2 2174 ///
QL 9:ca2e6010d9e2 2175 /// This function returns the margin of the given event pool \a poolId,
QL 9:ca2e6010d9e2 2176 /// where poolId is the ID of the pool initialized by the call to
QL 9:ca2e6010d9e2 2177 /// QF::poolInit(). The poolId of the first initialized pool is 1, the
QL 9:ca2e6010d9e2 2178 /// second 2, and so on.
QL 9:ca2e6010d9e2 2179 ///
QL 9:ca2e6010d9e2 2180 /// The returned pool margin is the minimal number of free blocks
QL 9:ca2e6010d9e2 2181 /// encountered in the given pool since system startup.
QL 9:ca2e6010d9e2 2182 ///
QL 9:ca2e6010d9e2 2183 /// \note Requesting the margin of an un-initialized pool raises an
QL 9:ca2e6010d9e2 2184 /// assertion in the QF.
QL 9:ca2e6010d9e2 2185 static uint32_t getPoolMargin(uint8_t const poolId);
QL 9:ca2e6010d9e2 2186
QL 9:ca2e6010d9e2 2187 /// \brief This function returns the margin of the given event queue.
QL 9:ca2e6010d9e2 2188 ///
QL 9:ca2e6010d9e2 2189 /// This function returns the margin of the given event queue of an active
QL 9:ca2e6010d9e2 2190 /// object with priority \a prio. (QF priorities start with 1 and go up to
QL 9:ca2e6010d9e2 2191 /// #QF_MAX_ACTIVE.) The margin is the minimal number of free events
QL 9:ca2e6010d9e2 2192 /// encountered in the given queue since system startup.
QL 9:ca2e6010d9e2 2193 ///
QL 9:ca2e6010d9e2 2194 /// \note QF::getQueueMargin() is available only when the native QF event
QL 9:ca2e6010d9e2 2195 /// queue implementation is used. Requesting the queue margin of an unused
QL 9:ca2e6010d9e2 2196 /// priority level raises an assertion in the QF. (A priority level
QL 9:ca2e6010d9e2 2197 /// becomes used in QF after the call to the QF::add_() function.)
QL 9:ca2e6010d9e2 2198 static uint32_t getQueueMargin(uint8_t const prio);
QL 9:ca2e6010d9e2 2199
QL 9:ca2e6010d9e2 2200 /// \brief Internal QF implementation of the dynamic event allocator.
QL 9:ca2e6010d9e2 2201 ///
QL 9:ca2e6010d9e2 2202 /// \note The application code should not call this function directly.
QL 9:ca2e6010d9e2 2203 /// Please use the macro #Q_NEW.
QL 9:ca2e6010d9e2 2204 static QEvt *new_(QEvtSize const evtSize, enum_t const sig);
QL 9:ca2e6010d9e2 2205
QL 9:ca2e6010d9e2 2206 /// \brief Recycle a dynamic event.
QL 9:ca2e6010d9e2 2207 ///
QL 9:ca2e6010d9e2 2208 /// This function implements a simple garbage collector for the dynamic
QL 9:ca2e6010d9e2 2209 /// events. Only dynamic events are candidates for recycling. (A dynamic
QL 9:ca2e6010d9e2 2210 /// event is one that is allocated from an event pool, which is
QL 9:ca2e6010d9e2 2211 /// determined as non-zero e->attrQF__ attribute.) Next, the function
QL 9:ca2e6010d9e2 2212 /// decrements the reference counter of the event, and recycles the event
QL 9:ca2e6010d9e2 2213 /// only if the counter drops to zero (meaning that no more references
QL 9:ca2e6010d9e2 2214 /// are outstanding for this event). The dynamic event is recycled by
QL 9:ca2e6010d9e2 2215 /// returning it to the pool from which it was originally allocated.
QL 9:ca2e6010d9e2 2216 /// The pool-of-origin information is stored in the upper 2-MSBs of the
QL 9:ca2e6010d9e2 2217 /// e->attrQF__ attribute.)
QL 9:ca2e6010d9e2 2218 ///
QL 9:ca2e6010d9e2 2219 /// \note QF invokes the garbage collector at all appropriate contexts,
QL 9:ca2e6010d9e2 2220 /// when an event can become garbage (automatic garbage collection),
QL 9:ca2e6010d9e2 2221 /// so the application code should have NO need to call QF::gc() directly.
QL 9:ca2e6010d9e2 2222 /// The QF::gc() function is exposed only for special cases when your
QL 9:ca2e6010d9e2 2223 /// application sends dynamic events to the "raw" thread-safe queues
QL 9:ca2e6010d9e2 2224 /// (see ::QEQueue). Such queues are processed outside of QF and the
QL 9:ca2e6010d9e2 2225 /// automatic garbage collection CANNOT be performed for these events.
QL 9:ca2e6010d9e2 2226 /// In this case you need to call QF::gc() explicitly.
QL 9:ca2e6010d9e2 2227 static void gc(QEvt const *e);
QL 9:ca2e6010d9e2 2228
QL 9:ca2e6010d9e2 2229 private: // functions to be used in QF ports only
QL 9:ca2e6010d9e2 2230
QL 9:ca2e6010d9e2 2231 /// \brief Register an active object to be managed by the framework
QL 9:ca2e6010d9e2 2232 ///
QL 9:ca2e6010d9e2 2233 /// This function should not be called by the application directly, only
QL 9:ca2e6010d9e2 2234 /// through the function QActive::start(). The priority of the active
QL 9:ca2e6010d9e2 2235 /// object \a a should be set before calling this function.
QL 9:ca2e6010d9e2 2236 ///
QL 9:ca2e6010d9e2 2237 /// \note This function raises an assertion if the priority of the active
QL 9:ca2e6010d9e2 2238 /// object exceeds the maximum value #QF_MAX_ACTIVE. Also, this function
QL 9:ca2e6010d9e2 2239 /// raises an assertion if the priority of the active object is already in
QL 9:ca2e6010d9e2 2240 /// use. (QF requires each active object to have a UNIQUE priority.)
QL 9:ca2e6010d9e2 2241 static void add_(QActive * const a);
QL 9:ca2e6010d9e2 2242
QL 9:ca2e6010d9e2 2243 public:
QL 9:ca2e6010d9e2 2244 /// \brief Remove the active object from the framework.
QL 9:ca2e6010d9e2 2245 ///
QL 9:ca2e6010d9e2 2246 /// This function should not be called by the application directly, only
QL 9:ca2e6010d9e2 2247 /// inside the QF port. The priority level occupied by the active object
QL 9:ca2e6010d9e2 2248 /// is freed-up and can be reused for another active object.
QL 9:ca2e6010d9e2 2249 ///
QL 9:ca2e6010d9e2 2250 /// The active object that is removed from the framework can no longer
QL 9:ca2e6010d9e2 2251 /// participate in the publish-subscribe event exchange.
QL 9:ca2e6010d9e2 2252 ///
QL 9:ca2e6010d9e2 2253 /// \note This function raises an assertion if the priority of the active
QL 9:ca2e6010d9e2 2254 /// object exceeds the maximum value #QF_MAX_ACTIVE or is not used.
QL 9:ca2e6010d9e2 2255 static void remove_(QActive const * const a);
QL 9:ca2e6010d9e2 2256
QL 9:ca2e6010d9e2 2257 /// \brief array of registered active objects
QL 9:ca2e6010d9e2 2258 ///
QL 9:ca2e6010d9e2 2259 /// \note Not to be used by Clients directly, only in ports of QF
QL 9:ca2e6010d9e2 2260 static QActive *active_[];
QL 9:ca2e6010d9e2 2261
QL 9:ca2e6010d9e2 2262 /// \brief Thread routine for executing an active object \a act.
QL 9:ca2e6010d9e2 2263 ///
QL 9:ca2e6010d9e2 2264 /// This function is actually implemented internally by certain QF ports
QL 9:ca2e6010d9e2 2265 /// to be called by the active object thread routine.
QL 9:ca2e6010d9e2 2266 static void thread_(QActive *act);
QL 9:ca2e6010d9e2 2267
QL 9:ca2e6010d9e2 2268 friend class QActive;
QL 9:ca2e6010d9e2 2269 };
QL 9:ca2e6010d9e2 2270
QL 9:ca2e6010d9e2 2271 QP_END_
QL 9:ca2e6010d9e2 2272
QL 9:ca2e6010d9e2 2273 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2274 #ifdef Q_EVT_CTOR // Provide the constructor for the QEvt class?
QL 9:ca2e6010d9e2 2275
QL 9:ca2e6010d9e2 2276 /// \brief Allocate a dynamic event.
QL 9:ca2e6010d9e2 2277 ///
QL 9:ca2e6010d9e2 2278 /// This macro returns an event pointer cast to the type \a evtT_. The
QL 9:ca2e6010d9e2 2279 /// event is initialized with the signal \a sig. Internally, the macro
QL 9:ca2e6010d9e2 2280 /// calls the internal QF function QF::new_(), which always returns a
QL 9:ca2e6010d9e2 2281 /// valid event pointer.
QL 9:ca2e6010d9e2 2282 ///
QL 9:ca2e6010d9e2 2283 /// \note The internal QF function QF::new_() raises an assertion when
QL 9:ca2e6010d9e2 2284 /// the allocation of the event turns out to be impossible due to
QL 9:ca2e6010d9e2 2285 /// event pool depletion, or incorrect (too big) size of the requested
QL 9:ca2e6010d9e2 2286 /// event.
QL 9:ca2e6010d9e2 2287 ///
QL 9:ca2e6010d9e2 2288 /// The following example illustrates dynamic allocation of an event:
QL 9:ca2e6010d9e2 2289 /// \include qf_post.cpp
QL 9:ca2e6010d9e2 2290 #define Q_NEW(evtT_, sig_, ...) \
QL 9:ca2e6010d9e2 2291 (new(QP_ QF::new_( \
QL 9:ca2e6010d9e2 2292 static_cast<QP_ QEvtSize>(sizeof(evtT_)), (sig_))) \
QL 9:ca2e6010d9e2 2293 evtT_((sig_), ##__VA_ARGS__))
QL 9:ca2e6010d9e2 2294 #else // QEvt is a POD (Plain Old Datatype)
QL 9:ca2e6010d9e2 2295
QL 9:ca2e6010d9e2 2296 #define Q_NEW(evtT_, sig_) \
QL 9:ca2e6010d9e2 2297 (static_cast<evtT_ *>( \
QL 9:ca2e6010d9e2 2298 QP_ QF::new_(static_cast<QP_ QEvtSize>(sizeof(evtT_)), (sig_))))
QL 9:ca2e6010d9e2 2299 #endif
QL 9:ca2e6010d9e2 2300
QL 9:ca2e6010d9e2 2301 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2302 // QS software tracing integration, only if enabled
QL 9:ca2e6010d9e2 2303 #ifdef Q_SPY // QS software tracing enabled?
QL 9:ca2e6010d9e2 2304
QL 9:ca2e6010d9e2 2305 /// \brief Invoke the system clock tick processing QF::tick(). This macro
QL 9:ca2e6010d9e2 2306 /// is the recommended way of invoking clock tick processing, because it
QL 9:ca2e6010d9e2 2307 /// provides the vital information for software tracing and avoids any
QL 9:ca2e6010d9e2 2308 /// overhead when the tracing is disabled.
QL 9:ca2e6010d9e2 2309 ///
QL 9:ca2e6010d9e2 2310 /// This macro takes the argument \a sender_, which is a pointer to the
QL 9:ca2e6010d9e2 2311 /// sender object. This argument is actually only used when QS software
QL 9:ca2e6010d9e2 2312 /// tracing is enabled (macro #Q_SPY is defined). When QS software
QL 9:ca2e6010d9e2 2313 /// tracing is disabled, the macro calls QF::tick() without any
QL 9:ca2e6010d9e2 2314 /// arguments, so the overhead of passing this extra argument is
QL 9:ca2e6010d9e2 2315 /// entirely avoided.
QL 9:ca2e6010d9e2 2316 ///
QL 9:ca2e6010d9e2 2317 /// \note the pointer to the sender object is not necessarily a poiner
QL 9:ca2e6010d9e2 2318 /// to an active object. In fact, typically QF::TICK() will be called from
QL 9:ca2e6010d9e2 2319 /// an interrupt, in which case you would create a unique object just to
QL 9:ca2e6010d9e2 2320 /// unambiguously identify the ISR as the sender of the time events.
QL 9:ca2e6010d9e2 2321 ///
QL 9:ca2e6010d9e2 2322 /// \sa QF::tick()
QL 9:ca2e6010d9e2 2323 #define TICK(sender_) tick(sender_)
QL 9:ca2e6010d9e2 2324
QL 9:ca2e6010d9e2 2325 /// \brief Invoke the event publishing facility QF::publish(). This macro
QL 9:ca2e6010d9e2 2326 /// is the recommended way of publishing events, because it provides the
QL 9:ca2e6010d9e2 2327 /// vital information for software tracing and avoids any overhead when
QL 9:ca2e6010d9e2 2328 /// the tracing is disabled.
QL 9:ca2e6010d9e2 2329 ///
QL 9:ca2e6010d9e2 2330 ///
QL 9:ca2e6010d9e2 2331 /// This macro takes the last argument \a sender_, which is a pointer to
QL 9:ca2e6010d9e2 2332 /// the sender object. This argument is actually only used when QS
QL 9:ca2e6010d9e2 2333 /// tracing is enabled (macro #Q_SPY is defined). When QS software
QL 9:ca2e6010d9e2 2334 /// tracing is disabled, the macro calls QF::publish() without the
QL 9:ca2e6010d9e2 2335 /// \a sender_ argument, so the overhead of passing this extra argument
QL 9:ca2e6010d9e2 2336 /// is entirely avoided.
QL 9:ca2e6010d9e2 2337 ///
QL 9:ca2e6010d9e2 2338 /// \note the pointer to the sender object is not necessarily a poiner
QL 9:ca2e6010d9e2 2339 /// to an active object. In fact, if QF::PUBLISH() is called from an
QL 9:ca2e6010d9e2 2340 /// interrupt or other context, you can create a unique object just to
QL 9:ca2e6010d9e2 2341 /// unambiguously identify the publisher of the event.
QL 9:ca2e6010d9e2 2342 ///
QL 9:ca2e6010d9e2 2343 /// \sa QF::publish()
QL 9:ca2e6010d9e2 2344 #define PUBLISH(e_, sender_) publish((e_), (sender_))
QL 9:ca2e6010d9e2 2345
QL 9:ca2e6010d9e2 2346 /// \brief Invoke the direct event posting facility QActive::postFIFO().
QL 9:ca2e6010d9e2 2347 /// This macro is the recommended way of posting events, because it
QL 9:ca2e6010d9e2 2348 /// provides the vital information for software tracing and avoids any
QL 9:ca2e6010d9e2 2349 /// overhead when the tracing is disabled.
QL 9:ca2e6010d9e2 2350 ///
QL 9:ca2e6010d9e2 2351 ///
QL 9:ca2e6010d9e2 2352 /// This macro takes the last argument \a sender_, which is a pointer to
QL 9:ca2e6010d9e2 2353 /// the sender object. This argument is actually only used when QS
QL 9:ca2e6010d9e2 2354 /// tracing is disabled (macro #Q_SPY is defined). When QS software
QL 9:ca2e6010d9e2 2355 /// tracing is not enabled, the macro calls QF_publish() without the
QL 9:ca2e6010d9e2 2356 /// \a sender_ argument, so the overhead of passing this extra argument
QL 9:ca2e6010d9e2 2357 /// is entirely avoided.
QL 9:ca2e6010d9e2 2358 ///
QL 9:ca2e6010d9e2 2359 /// \note the pointer to the sender object is not necessarily a poiner
QL 9:ca2e6010d9e2 2360 /// to an active object. In fact, if ao->POST() is called from an
QL 9:ca2e6010d9e2 2361 /// interrupt or other context, you can create a unique object just to
QL 9:ca2e6010d9e2 2362 /// unambiguously identify the publisher of the event.
QL 9:ca2e6010d9e2 2363 ///
QL 9:ca2e6010d9e2 2364 /// \sa QActive::postFIFO()
QL 9:ca2e6010d9e2 2365 #define POST(e_, sender_) postFIFO((e_), (sender_))
QL 9:ca2e6010d9e2 2366
QL 9:ca2e6010d9e2 2367 #else
QL 9:ca2e6010d9e2 2368
QL 9:ca2e6010d9e2 2369 #define TICK(dummy_) tick()
QL 9:ca2e6010d9e2 2370 #define PUBLISH(e_, dummy_) publish(e_)
QL 9:ca2e6010d9e2 2371 #define POST(e_, dummy_) postFIFO(e_)
QL 9:ca2e6010d9e2 2372
QL 9:ca2e6010d9e2 2373 #endif // Q_SPY
QL 9:ca2e6010d9e2 2374
QL 9:ca2e6010d9e2 2375 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2376 // QS software tracing
QL 9:ca2e6010d9e2 2377 #ifdef Q_SPY
QL 9:ca2e6010d9e2 2378
QL 9:ca2e6010d9e2 2379 // qs.h ======================================================================
QL 9:ca2e6010d9e2 2380 /// \brief QS/C++ platform-independent public interface.
QL 9:ca2e6010d9e2 2381 /// This header file must be included directly or indirectly
QL 9:ca2e6010d9e2 2382 /// in all modules (*.cpp files) that use QS/C++.
QL 9:ca2e6010d9e2 2383
QL 9:ca2e6010d9e2 2384 #ifndef Q_SPY
QL 9:ca2e6010d9e2 2385 #error "Q_SPY must be defined to include qs.h"
QL 9:ca2e6010d9e2 2386 #endif
QL 9:ca2e6010d9e2 2387
QL 9:ca2e6010d9e2 2388 #ifndef Q_ROM // provide the default if Q_ROM NOT defined
QL 9:ca2e6010d9e2 2389 #define Q_ROM
QL 9:ca2e6010d9e2 2390 #endif
QL 9:ca2e6010d9e2 2391 #ifndef Q_ROM_VAR // provide the default if Q_ROM_VAR NOT defined
QL 9:ca2e6010d9e2 2392 #define Q_ROM_VAR
QL 9:ca2e6010d9e2 2393 #endif
QL 9:ca2e6010d9e2 2394 #ifndef Q_ROM_BYTE // provide the default if Q_ROM_BYTE NOT defined
QL 9:ca2e6010d9e2 2395 #define Q_ROM_BYTE(rom_var_) (rom_var_)
QL 9:ca2e6010d9e2 2396 #endif
QL 9:ca2e6010d9e2 2397
QL 9:ca2e6010d9e2 2398 #ifndef QS_TIME_SIZE
QL 9:ca2e6010d9e2 2399
QL 9:ca2e6010d9e2 2400 /// \brief The size (in bytes) of the QS time stamp. Valid values: 1, 2,
QL 9:ca2e6010d9e2 2401 /// or 4; default 4.
QL 9:ca2e6010d9e2 2402 ///
QL 9:ca2e6010d9e2 2403 /// This macro can be defined in the QS port file (qs_port.h) to
QL 9:ca2e6010d9e2 2404 /// configure the ::QSTimeCtr type. Here the macro is not defined so the
QL 9:ca2e6010d9e2 2405 /// default of 4 byte is chosen.
QL 9:ca2e6010d9e2 2406 #define QS_TIME_SIZE 4
QL 9:ca2e6010d9e2 2407 #endif
QL 9:ca2e6010d9e2 2408
QL 9:ca2e6010d9e2 2409 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2410 QP_BEGIN_
QL 9:ca2e6010d9e2 2411
QL 9:ca2e6010d9e2 2412 /// \brief Quantum Spy record types.
QL 9:ca2e6010d9e2 2413 ///
QL 9:ca2e6010d9e2 2414 /// The following constants specify the QS record types used in QP components.
QL 9:ca2e6010d9e2 2415 /// You can specify your own record types starting from the ::QS_USER offset.
QL 9:ca2e6010d9e2 2416 /// Currently, the maximum of all records cannot exceed 256.
QL 9:ca2e6010d9e2 2417 /// \sa QS::filterOn()/#QS_FILTER_ON and QS::filterOff()/#QS_FILTER_OFF
QL 9:ca2e6010d9e2 2418
QL 9:ca2e6010d9e2 2419 enum QSpyRecords {
QL 9:ca2e6010d9e2 2420 QS_QP_RESET, ///< reset the QP (start of a new QS session)
QL 9:ca2e6010d9e2 2421
QL 9:ca2e6010d9e2 2422 // QEP records
QL 9:ca2e6010d9e2 2423 QS_QEP_STATE_ENTRY, ///< a state was entered
QL 9:ca2e6010d9e2 2424 QS_QEP_STATE_EXIT, ///< a state was exited
QL 9:ca2e6010d9e2 2425 QS_QEP_STATE_INIT, ///< an intial transition was taken in a state
QL 9:ca2e6010d9e2 2426 QS_QEP_INIT_TRAN, ///< the top-most initial transition was taken
QL 9:ca2e6010d9e2 2427 QS_QEP_INTERN_TRAN, ///< an internal transition was taken
QL 9:ca2e6010d9e2 2428 QS_QEP_TRAN, ///< a regular transition was taken
QL 9:ca2e6010d9e2 2429 QS_QEP_IGNORED, ///< an event was ignored (silently discarded)
QL 9:ca2e6010d9e2 2430 QS_QEP_DISPATCH, ///< an event was dispatched (begin of RTC step)
QL 9:ca2e6010d9e2 2431 QS_QEP_UNHANDLED, ///< an event was unhandled due to a guard
QL 9:ca2e6010d9e2 2432
QL 9:ca2e6010d9e2 2433 // QF records
QL 9:ca2e6010d9e2 2434 QS_QF_ACTIVE_ADD, ///< an AO has been added to QF (started)
QL 9:ca2e6010d9e2 2435 QS_QF_ACTIVE_REMOVE, ///< an AO has been removed from QF (stopped)
QL 9:ca2e6010d9e2 2436 QS_QF_ACTIVE_SUBSCRIBE, ///< an AO subscribed to an event
QL 9:ca2e6010d9e2 2437 QS_QF_ACTIVE_UNSUBSCRIBE, ///< an AO unsubscribed to an event
QL 9:ca2e6010d9e2 2438 QS_QF_ACTIVE_POST_FIFO, ///< an event was posted (FIFO) directly to an AO
QL 9:ca2e6010d9e2 2439 QS_QF_ACTIVE_POST_LIFO, ///< an event was posted (LIFO) directly to an AO
QL 9:ca2e6010d9e2 2440 QS_QF_ACTIVE_GET, ///< an AO got an event and its queue is still not empty
QL 9:ca2e6010d9e2 2441 QS_QF_ACTIVE_GET_LAST, ///< an AO got an event and its queue is empty
QL 9:ca2e6010d9e2 2442 QS_QF_EQUEUE_INIT, ///< an event queue was initialized
QL 9:ca2e6010d9e2 2443 QS_QF_EQUEUE_POST_FIFO, ///< an event was posted (FIFO) to a raw queue
QL 9:ca2e6010d9e2 2444 QS_QF_EQUEUE_POST_LIFO, ///< an event was posted (LIFO) to a raw queue
QL 9:ca2e6010d9e2 2445 QS_QF_EQUEUE_GET, ///< get an event and queue still not empty
QL 9:ca2e6010d9e2 2446 QS_QF_EQUEUE_GET_LAST, ///< get the last event from the queue
QL 9:ca2e6010d9e2 2447 QS_QF_MPOOL_INIT, ///< a memory pool was initialized
QL 9:ca2e6010d9e2 2448 QS_QF_MPOOL_GET, ///< a memory block was removed from a memory pool
QL 9:ca2e6010d9e2 2449 QS_QF_MPOOL_PUT, ///< a memory block was returned to a memory pool
QL 9:ca2e6010d9e2 2450 QS_QF_PUBLISH, ///< an event was truly published to some subscribers
QL 9:ca2e6010d9e2 2451 QS_QF_RESERVED8,
QL 9:ca2e6010d9e2 2452 QS_QF_NEW, ///< new event creation
QL 9:ca2e6010d9e2 2453 QS_QF_GC_ATTEMPT, ///< garbage collection attempt
QL 9:ca2e6010d9e2 2454 QS_QF_GC, ///< garbage collection
QL 9:ca2e6010d9e2 2455 QS_QF_TICK, ///< QF::tick() was called
QL 9:ca2e6010d9e2 2456 QS_QF_TIMEEVT_ARM, ///< a time event was armed
QL 9:ca2e6010d9e2 2457 QS_QF_TIMEEVT_AUTO_DISARM, ///< a time event expired and was disarmed
QL 9:ca2e6010d9e2 2458 QS_QF_TIMEEVT_DISARM_ATTEMPT,///< an attempt to disarmed a disarmed tevent
QL 9:ca2e6010d9e2 2459 QS_QF_TIMEEVT_DISARM, ///< true disarming of an armed time event
QL 9:ca2e6010d9e2 2460 QS_QF_TIMEEVT_REARM, ///< rearming of a time event
QL 9:ca2e6010d9e2 2461 QS_QF_TIMEEVT_POST, ///< a time event posted itself directly to an AO
QL 9:ca2e6010d9e2 2462 QS_QF_TIMEEVT_CTR, ///< a time event counter was requested
QL 9:ca2e6010d9e2 2463 QS_QF_CRIT_ENTRY, ///< critical section was entered
QL 9:ca2e6010d9e2 2464 QS_QF_CRIT_EXIT, ///< critical section was exited
QL 9:ca2e6010d9e2 2465 QS_QF_ISR_ENTRY, ///< an ISR was entered
QL 9:ca2e6010d9e2 2466 QS_QF_ISR_EXIT, ///< an ISR was exited
QL 9:ca2e6010d9e2 2467 QS_QF_INT_DISABLE, ///< interrupts were disabled
QL 9:ca2e6010d9e2 2468 QS_QF_INT_ENABLE, ///< interrupts were enabled
QL 9:ca2e6010d9e2 2469 QS_QF_RESERVED4,
QL 9:ca2e6010d9e2 2470 QS_QF_RESERVED3,
QL 9:ca2e6010d9e2 2471 QS_QF_RESERVED2,
QL 9:ca2e6010d9e2 2472 QS_QF_RESERVED1,
QL 9:ca2e6010d9e2 2473 QS_QF_RESERVED0,
QL 9:ca2e6010d9e2 2474
QL 9:ca2e6010d9e2 2475 // QK records
QL 9:ca2e6010d9e2 2476 QS_QK_MUTEX_LOCK, ///< the QK mutex was locked
QL 9:ca2e6010d9e2 2477 QS_QK_MUTEX_UNLOCK, ///< the QK mutex was unlocked
QL 9:ca2e6010d9e2 2478 QS_QK_SCHEDULE, ///< the QK scheduler scheduled a new task to execute
QL 9:ca2e6010d9e2 2479 QS_QK_RESERVED6,
QL 9:ca2e6010d9e2 2480 QS_QK_RESERVED5,
QL 9:ca2e6010d9e2 2481 QS_QK_RESERVED4,
QL 9:ca2e6010d9e2 2482 QS_QK_RESERVED3,
QL 9:ca2e6010d9e2 2483 QS_QK_RESERVED2,
QL 9:ca2e6010d9e2 2484 QS_QK_RESERVED1,
QL 9:ca2e6010d9e2 2485 QS_QK_RESERVED0,
QL 9:ca2e6010d9e2 2486
QL 9:ca2e6010d9e2 2487 // Miscellaneous QS records
QL 9:ca2e6010d9e2 2488 QS_SIG_DIC, ///< signal dictionary entry
QL 9:ca2e6010d9e2 2489 QS_OBJ_DIC, ///< object dictionary entry
QL 9:ca2e6010d9e2 2490 QS_FUN_DIC, ///< function dictionary entry
QL 9:ca2e6010d9e2 2491 QS_USR_DIC, ///< user QS record dictionary entry
QL 9:ca2e6010d9e2 2492 QS_RESERVED4,
QL 9:ca2e6010d9e2 2493 QS_RESERVED3,
QL 9:ca2e6010d9e2 2494 QS_RESERVED2,
QL 9:ca2e6010d9e2 2495 QS_RESERVED1,
QL 9:ca2e6010d9e2 2496 QS_RESERVED0,
QL 9:ca2e6010d9e2 2497 QS_ASSERT, ///< assertion fired in the code
QL 9:ca2e6010d9e2 2498
QL 9:ca2e6010d9e2 2499 // User records
QL 9:ca2e6010d9e2 2500 QS_USER ///< the first record available for user QS records
QL 9:ca2e6010d9e2 2501 };
QL 9:ca2e6010d9e2 2502
QL 9:ca2e6010d9e2 2503 /// \brief Specification of all QS records for the QS::filterOn() and
QL 9:ca2e6010d9e2 2504 /// QS::filterOff()
QL 9:ca2e6010d9e2 2505 uint8_t const QS_ALL_RECORDS = static_cast<uint8_t>(0xFF);
QL 9:ca2e6010d9e2 2506
QL 9:ca2e6010d9e2 2507 /// \brief Constant representing End-Of-Data condition returned from the
QL 9:ca2e6010d9e2 2508 /// QS::getByte() function.
QL 9:ca2e6010d9e2 2509 uint16_t const QS_EOD = static_cast<uint16_t>(0xFFFF);
QL 9:ca2e6010d9e2 2510
QL 9:ca2e6010d9e2 2511
QL 9:ca2e6010d9e2 2512 #if (QS_TIME_SIZE == 1)
QL 9:ca2e6010d9e2 2513 typedef uint8_t QSTimeCtr;
QL 9:ca2e6010d9e2 2514 #define QS_TIME_() (QP_ QS::u8_(QP_ QS::onGetTime()))
QL 9:ca2e6010d9e2 2515 #elif (QS_TIME_SIZE == 2)
QL 9:ca2e6010d9e2 2516 typedef uint16_t QSTimeCtr;
QL 9:ca2e6010d9e2 2517 #define QS_TIME_() (QP_ QS::u16_(QP_ QS::onGetTime()))
QL 9:ca2e6010d9e2 2518 #elif (QS_TIME_SIZE == 4)
QL 9:ca2e6010d9e2 2519
QL 9:ca2e6010d9e2 2520 /// \brief The type of the QS time stamp
QL 9:ca2e6010d9e2 2521 ///
QL 9:ca2e6010d9e2 2522 /// This type determines the dynamic range of QS time stamps
QL 9:ca2e6010d9e2 2523 typedef uint32_t QSTimeCtr;
QL 9:ca2e6010d9e2 2524
QL 9:ca2e6010d9e2 2525 /// \brief Internal macro to output time stamp to the QS record
QL 9:ca2e6010d9e2 2526 #define QS_TIME_() (QP_ QS::u32_(QP_ QS::onGetTime()))
QL 9:ca2e6010d9e2 2527 #else
QL 9:ca2e6010d9e2 2528 #error "QS_TIME_SIZE defined incorrectly, expected 1, 2, or 4"
QL 9:ca2e6010d9e2 2529 #endif
QL 9:ca2e6010d9e2 2530
QL 9:ca2e6010d9e2 2531 /// \brief Quantum Spy logging facilities
QL 9:ca2e6010d9e2 2532 ///
QL 9:ca2e6010d9e2 2533 /// This class groups together QS services. It has only static members and
QL 9:ca2e6010d9e2 2534 /// should not be instantiated.
QL 9:ca2e6010d9e2 2535 class QS {
QL 9:ca2e6010d9e2 2536 public:
QL 9:ca2e6010d9e2 2537
QL 9:ca2e6010d9e2 2538 /// \brief Get the current version of QS
QL 9:ca2e6010d9e2 2539 ///
QL 9:ca2e6010d9e2 2540 /// \return version of the QS as a constant 6-character string of the form
QL 9:ca2e6010d9e2 2541 /// x.y.zz, where x is a 1-digit major version number, y is a 1-digit
QL 9:ca2e6010d9e2 2542 /// minor version number, and zz is a 2-digit release number.
QL 9:ca2e6010d9e2 2543 static char_t const Q_ROM * Q_ROM_VAR getVersion(void);
QL 9:ca2e6010d9e2 2544
QL 9:ca2e6010d9e2 2545 /// \brief Initialize the QS data buffer.
QL 9:ca2e6010d9e2 2546 ///
QL 9:ca2e6010d9e2 2547 /// This function should be called from QS_init() to provide QS with the
QL 9:ca2e6010d9e2 2548 /// data buffer. The first argument \a sto[] is the address of the memory
QL 9:ca2e6010d9e2 2549 /// block, and the second argument \a stoSize is the size of this block
QL 9:ca2e6010d9e2 2550 /// in bytes. Currently the size of the QS buffer cannot exceed 64KB.
QL 9:ca2e6010d9e2 2551 ///
QL 9:ca2e6010d9e2 2552 /// QS can work with quite small data buffers, but you will start losing
QL 9:ca2e6010d9e2 2553 /// data if the buffer is too small for the bursts of logging activity.
QL 9:ca2e6010d9e2 2554 /// The right size of the buffer depends on the data production rate and
QL 9:ca2e6010d9e2 2555 /// the data output rate. QS offers flexible filtering to reduce the data
QL 9:ca2e6010d9e2 2556 /// production rate.
QL 9:ca2e6010d9e2 2557 ///
QL 9:ca2e6010d9e2 2558 /// \note If the data output rate cannot keep up with the production rate,
QL 9:ca2e6010d9e2 2559 /// QS will start overwriting the older data with newer data. This is
QL 9:ca2e6010d9e2 2560 /// consistent with the "last-is-best" QS policy. The record sequence
QL 9:ca2e6010d9e2 2561 /// counters and checksums on each record allow to easily detect data
QL 9:ca2e6010d9e2 2562 /// loss.
QL 9:ca2e6010d9e2 2563 static void initBuf(uint8_t sto[], uint32_t const stoSize);
QL 9:ca2e6010d9e2 2564
QL 9:ca2e6010d9e2 2565 /// \brief Turn the global Filter on for a given record type \a rec.
QL 9:ca2e6010d9e2 2566 ///
QL 9:ca2e6010d9e2 2567 /// This function sets up the QS filter to enable the record type \a rec.
QL 9:ca2e6010d9e2 2568 /// The argument #QS_ALL_RECORDS specifies to filter-on all records.
QL 9:ca2e6010d9e2 2569 /// This function should be called indirectly through the macro
QL 9:ca2e6010d9e2 2570 /// #QS_FILTER_ON.
QL 9:ca2e6010d9e2 2571 ///
QL 9:ca2e6010d9e2 2572 /// \note Filtering based on the record-type is only the first layer of
QL 9:ca2e6010d9e2 2573 /// filtering. The second layer is based on the object-type. Both filter
QL 9:ca2e6010d9e2 2574 /// layers must be enabled for the QS record to be inserted into the QS
QL 9:ca2e6010d9e2 2575 /// buffer.
QL 9:ca2e6010d9e2 2576 /// \sa QS_filterOff(), #QS_FILTER_SM_OBJ, #QS_FILTER_AO_OBJ,
QL 9:ca2e6010d9e2 2577 /// #QS_FILTER_MP_OBJ, #QS_FILTER_EQ_OBJ, and #QS_FILTER_TE_OBJ.
QL 9:ca2e6010d9e2 2578 static void filterOn(uint8_t const rec);
QL 9:ca2e6010d9e2 2579
QL 9:ca2e6010d9e2 2580 /// \brief Turn the global Filter off for a given record type \a rec.
QL 9:ca2e6010d9e2 2581 ///
QL 9:ca2e6010d9e2 2582 /// This function sets up the QS filter to disable the record type \a rec.
QL 9:ca2e6010d9e2 2583 /// The argument #QS_ALL_RECORDS specifies to suppress all records.
QL 9:ca2e6010d9e2 2584 /// This function should be called indirectly through the macro
QL 9:ca2e6010d9e2 2585 /// #QS_FILTER_OFF.
QL 9:ca2e6010d9e2 2586 ///
QL 9:ca2e6010d9e2 2587 /// \note Filtering records based on the record-type is only the first
QL 9:ca2e6010d9e2 2588 /// layer of filtering. The second layer is based on the object-type.
QL 9:ca2e6010d9e2 2589 /// Both filter layers must be enabled for the QS record to be inserted
QL 9:ca2e6010d9e2 2590 /// into the QS buffer.
QL 9:ca2e6010d9e2 2591 /// \sa
QL 9:ca2e6010d9e2 2592 static void filterOff(uint8_t const rec);
QL 9:ca2e6010d9e2 2593
QL 9:ca2e6010d9e2 2594 /// \brief Mark the begin of a QS record \a rec
QL 9:ca2e6010d9e2 2595 ///
QL 9:ca2e6010d9e2 2596 /// This function must be called at the beginning of each QS record.
QL 9:ca2e6010d9e2 2597 /// This function should be called indirectly through the macro #QS_BEGIN,
QL 9:ca2e6010d9e2 2598 /// or #QS_BEGIN_NOCRIT, depending if it's called in a normal code or from
QL 9:ca2e6010d9e2 2599 /// a critical section.
QL 9:ca2e6010d9e2 2600 static void begin(uint8_t const rec);
QL 9:ca2e6010d9e2 2601
QL 9:ca2e6010d9e2 2602 /// \brief Mark the end of a QS record \a rec
QL 9:ca2e6010d9e2 2603 ///
QL 9:ca2e6010d9e2 2604 /// This function must be called at the end of each QS record.
QL 9:ca2e6010d9e2 2605 /// This function should be called indirectly through the macro #QS_END,
QL 9:ca2e6010d9e2 2606 /// or #QS_END_NOCRIT, depending if it's called in a normal code or from
QL 9:ca2e6010d9e2 2607 /// a critical section.
QL 9:ca2e6010d9e2 2608 static void end(void);
QL 9:ca2e6010d9e2 2609
QL 9:ca2e6010d9e2 2610 // unformatted data elements output ......................................
QL 9:ca2e6010d9e2 2611
QL 9:ca2e6010d9e2 2612 /// \brief output uint8_t data element without format information
QL 9:ca2e6010d9e2 2613 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2614 /// client code directly.
QL 9:ca2e6010d9e2 2615 static void u8_(uint8_t const d);
QL 9:ca2e6010d9e2 2616
QL 9:ca2e6010d9e2 2617 /// \brief Output uint16_t data element without format information
QL 9:ca2e6010d9e2 2618 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2619 /// client code directly.
QL 9:ca2e6010d9e2 2620 static void u16_(uint16_t d);
QL 9:ca2e6010d9e2 2621
QL 9:ca2e6010d9e2 2622 /// \brief Output uint32_t data element without format information
QL 9:ca2e6010d9e2 2623 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2624 /// client code directly.
QL 9:ca2e6010d9e2 2625 static void u32_(uint32_t d);
QL 9:ca2e6010d9e2 2626
QL 9:ca2e6010d9e2 2627 /// \brief Output zero-terminated ASCII string element without format
QL 9:ca2e6010d9e2 2628 /// information
QL 9:ca2e6010d9e2 2629 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2630 /// client code directly.
QL 9:ca2e6010d9e2 2631 static void str_(char_t const *s);
QL 9:ca2e6010d9e2 2632
QL 9:ca2e6010d9e2 2633 /// \brief Output zero-terminated ASCII string element allocated in ROM
QL 9:ca2e6010d9e2 2634 /// without format information
QL 9:ca2e6010d9e2 2635 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2636 /// client code directly.
QL 9:ca2e6010d9e2 2637 static void str_ROM_(char_t const Q_ROM * Q_ROM_VAR s);
QL 9:ca2e6010d9e2 2638
QL 9:ca2e6010d9e2 2639 // formatted data elements output ........................................
QL 9:ca2e6010d9e2 2640
QL 9:ca2e6010d9e2 2641 /// \brief Output uint8_t data element with format information
QL 9:ca2e6010d9e2 2642 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2643 /// client code directly.
QL 9:ca2e6010d9e2 2644 static void u8(uint8_t const format, uint8_t const d);
QL 9:ca2e6010d9e2 2645
QL 9:ca2e6010d9e2 2646 /// \brief output uint16_t data element with format information
QL 9:ca2e6010d9e2 2647 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2648 /// client code directly.
QL 9:ca2e6010d9e2 2649 static void u16(uint8_t const format, uint16_t d);
QL 9:ca2e6010d9e2 2650
QL 9:ca2e6010d9e2 2651 /// \brief Output uint32_t data element with format information
QL 9:ca2e6010d9e2 2652 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2653 /// client code directly.
QL 9:ca2e6010d9e2 2654 static void u32(uint8_t const format, uint32_t d);
QL 9:ca2e6010d9e2 2655
QL 9:ca2e6010d9e2 2656 /// \brief Output 32-bit floating point data element with format
QL 9:ca2e6010d9e2 2657 /// information
QL 9:ca2e6010d9e2 2658 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2659 /// client code directly.
QL 9:ca2e6010d9e2 2660 static void f32(uint8_t const format, float32_t const d);
QL 9:ca2e6010d9e2 2661
QL 9:ca2e6010d9e2 2662 /// \brief Output 64-bit floating point data element with format
QL 9:ca2e6010d9e2 2663 /// information
QL 9:ca2e6010d9e2 2664 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2665 /// client code directly.
QL 9:ca2e6010d9e2 2666 static void f64(uint8_t const format, float64_t const d);
QL 9:ca2e6010d9e2 2667
QL 9:ca2e6010d9e2 2668 /// \brief Output zero-terminated ASCII string element with format
QL 9:ca2e6010d9e2 2669 /// information
QL 9:ca2e6010d9e2 2670 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2671 /// client code directly.
QL 9:ca2e6010d9e2 2672 static void str(char_t const *s);
QL 9:ca2e6010d9e2 2673
QL 9:ca2e6010d9e2 2674 /// \brief Output zero-terminated ASCII string element allocated in ROM
QL 9:ca2e6010d9e2 2675 /// with format information
QL 9:ca2e6010d9e2 2676 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2677 /// client code directly.
QL 9:ca2e6010d9e2 2678 static void str_ROM(char_t const Q_ROM * Q_ROM_VAR s);
QL 9:ca2e6010d9e2 2679
QL 9:ca2e6010d9e2 2680 /// \brief Output memory block of up to 255-bytes with format information
QL 9:ca2e6010d9e2 2681 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2682 /// client code directly.
QL 9:ca2e6010d9e2 2683 static void mem(uint8_t const *blk, uint8_t size);
QL 9:ca2e6010d9e2 2684
QL 9:ca2e6010d9e2 2685 #if (QS_OBJ_PTR_SIZE == 8) || (QS_FUN_PTR_SIZE == 8)
QL 9:ca2e6010d9e2 2686 /// \brief Output uint64_t data element without format information
QL 9:ca2e6010d9e2 2687 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2688 /// client code directly.
QL 9:ca2e6010d9e2 2689 static void u64_(uint64_t d);
QL 9:ca2e6010d9e2 2690
QL 9:ca2e6010d9e2 2691 /// \brief Output uint64_t data element with format information
QL 9:ca2e6010d9e2 2692 /// \note This function is only to be used through macros, never in the
QL 9:ca2e6010d9e2 2693 /// client code directly.
QL 9:ca2e6010d9e2 2694 static void u64(uint8_t format, uint64_t d);
QL 9:ca2e6010d9e2 2695 #endif
QL 9:ca2e6010d9e2 2696
QL 9:ca2e6010d9e2 2697 // QS buffer access ......................................................
QL 9:ca2e6010d9e2 2698
QL 9:ca2e6010d9e2 2699 /// \brief Byte-oriented interface to the QS data buffer.
QL 9:ca2e6010d9e2 2700 ///
QL 9:ca2e6010d9e2 2701 /// This function delivers one byte at a time from the QS data buffer.
QL 9:ca2e6010d9e2 2702 /// The function returns the byte in the least-significant 8-bits of the
QL 9:ca2e6010d9e2 2703 /// 16-bit return value if the byte is available. If no more data is
QL 9:ca2e6010d9e2 2704 /// available at the time, the function returns QS_EOD (End-Of-Data).
QL 9:ca2e6010d9e2 2705 ///
QL 9:ca2e6010d9e2 2706 /// \note QS::getByte() is NOT protected with a critical section.
QL 9:ca2e6010d9e2 2707 static uint16_t getByte(void);
QL 9:ca2e6010d9e2 2708
QL 9:ca2e6010d9e2 2709 /// \brief Block-oriented interface to the QS data buffer.
QL 9:ca2e6010d9e2 2710 ///
QL 9:ca2e6010d9e2 2711 /// This function delivers a contiguous block of data from the QS data
QL 9:ca2e6010d9e2 2712 /// buffer. The function returns the pointer to the beginning of the
QL 9:ca2e6010d9e2 2713 /// block, and writes the number of bytes in the block to the location
QL 9:ca2e6010d9e2 2714 /// pointed to by \a pNbytes. The argument \a pNbytes is also used as
QL 9:ca2e6010d9e2 2715 /// input to provide the maximum size of the data block that the caller
QL 9:ca2e6010d9e2 2716 /// can accept.
QL 9:ca2e6010d9e2 2717 ///
QL 9:ca2e6010d9e2 2718 /// If no bytes are available in the QS buffer when the function is
QL 9:ca2e6010d9e2 2719 /// called, the function returns a NULL pointer and sets the value
QL 9:ca2e6010d9e2 2720 /// pointed to by \a pNbytes to zero.
QL 9:ca2e6010d9e2 2721 ///
QL 9:ca2e6010d9e2 2722 /// \note Only the NULL return from QS::getBlock() indicates that the QS
QL 9:ca2e6010d9e2 2723 /// buffer is empty at the time of the call. The non-NULL return often
QL 9:ca2e6010d9e2 2724 /// means that the block is at the end of the buffer and you need to call
QL 9:ca2e6010d9e2 2725 /// QS::getBlock() again to obtain the rest of the data that "wrapped
QL 9:ca2e6010d9e2 2726 /// around" to the beginning of the QS data buffer.
QL 9:ca2e6010d9e2 2727 ///
QL 9:ca2e6010d9e2 2728 /// \note QS::getBlock() is NOT protected with a critical section.
QL 9:ca2e6010d9e2 2729 static uint8_t const *getBlock(uint16_t * const pNbytes);
QL 9:ca2e6010d9e2 2730
QL 9:ca2e6010d9e2 2731 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2732 // platform-dependent callback functions to be implemented by clients
QL 9:ca2e6010d9e2 2733
QL 9:ca2e6010d9e2 2734 // platform-specific callback functions, need to be implemented by clients
QL 9:ca2e6010d9e2 2735 /// \brief Callback to startup the QS facility
QL 9:ca2e6010d9e2 2736 ///
QL 9:ca2e6010d9e2 2737 /// This is a platform-dependent "callback" function invoked through the
QL 9:ca2e6010d9e2 2738 /// macro #QS_INIT. You need to implement this function in your
QL 9:ca2e6010d9e2 2739 /// application. At a minimum, the function must configure the QS buffer
QL 9:ca2e6010d9e2 2740 /// by calling QS::initBuf(). Typically, you will also want to open/
QL 9:ca2e6010d9e2 2741 /// configure the QS output channel, such as a serial port, or a file.
QL 9:ca2e6010d9e2 2742 /// The void* argument \a arg can be used to pass parameter(s) needed to
QL 9:ca2e6010d9e2 2743 /// configure the output channel.
QL 9:ca2e6010d9e2 2744 ///
QL 9:ca2e6010d9e2 2745 /// The function returns true if the QS initialization was successful,
QL 9:ca2e6010d9e2 2746 /// or false if it failed.
QL 9:ca2e6010d9e2 2747 ///
QL 9:ca2e6010d9e2 2748 /// The following example illustrates an implementation of QS_onStartup():
QL 9:ca2e6010d9e2 2749 /// \include qs_startup.cpp
QL 9:ca2e6010d9e2 2750 static bool onStartup(void const *arg);
QL 9:ca2e6010d9e2 2751
QL 9:ca2e6010d9e2 2752 /// \brief Callback to cleanup the QS facility
QL 9:ca2e6010d9e2 2753 ///
QL 9:ca2e6010d9e2 2754 /// This is a platform-dependent "callback" function invoked through the
QL 9:ca2e6010d9e2 2755 /// macro #QS_EXIT. You need to implement this function in your
QL 9:ca2e6010d9e2 2756 /// application. The main purpose of this function is to close the QS
QL 9:ca2e6010d9e2 2757 /// output channel, if necessary.
QL 9:ca2e6010d9e2 2758 static void onCleanup(void);
QL 9:ca2e6010d9e2 2759
QL 9:ca2e6010d9e2 2760 /// \brief Callback to flush the QS trace data to the host
QL 9:ca2e6010d9e2 2761 ///
QL 9:ca2e6010d9e2 2762 /// This is a platform-dependent "callback" function to flush the QS
QL 9:ca2e6010d9e2 2763 /// trace buffer to the host. The function typically busy-waits until all
QL 9:ca2e6010d9e2 2764 /// the data in the buffer is sent to the host. This is acceptable only
QL 9:ca2e6010d9e2 2765 /// in the initial transient.
QL 9:ca2e6010d9e2 2766 static void onFlush(void);
QL 9:ca2e6010d9e2 2767
QL 9:ca2e6010d9e2 2768 /// \brief Callback to obtain a timestamp for a QS record.
QL 9:ca2e6010d9e2 2769 ///
QL 9:ca2e6010d9e2 2770 /// This is a platform-dependent "callback" function invoked from the
QL 9:ca2e6010d9e2 2771 /// macro #QS_TIME_ to add the time stamp to the QS record.
QL 9:ca2e6010d9e2 2772 ///
QL 9:ca2e6010d9e2 2773 /// \note Some of the pre-defined QS records from QP do not output the
QL 9:ca2e6010d9e2 2774 /// time stamp. However, ALL user records do output the time stamp.
QL 9:ca2e6010d9e2 2775 /// \note QS::onGetTime() is called in a critical section and should not
QL 9:ca2e6010d9e2 2776 /// exit critical section.
QL 9:ca2e6010d9e2 2777 ///
QL 9:ca2e6010d9e2 2778 /// The following example shows using a system call to implement QS
QL 9:ca2e6010d9e2 2779 /// time stamping:
QL 9:ca2e6010d9e2 2780 /// \include qs_onGetTime.cpp
QL 9:ca2e6010d9e2 2781 static QSTimeCtr onGetTime(void);
QL 9:ca2e6010d9e2 2782
QL 9:ca2e6010d9e2 2783 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2784 // Global and Local QS filters
QL 9:ca2e6010d9e2 2785 static uint8_t glbFilter_[32]; ///< global on/off QS filter
QL 9:ca2e6010d9e2 2786 static void const *smObj_; ///< state machine for QEP local filter
QL 9:ca2e6010d9e2 2787 static void const *aoObj_; ///< active object for QF/QK local filter
QL 9:ca2e6010d9e2 2788 static void const *mpObj_; ///< event pool for QF local filter
QL 9:ca2e6010d9e2 2789 static void const *eqObj_; ///< raw queue for QF local filter
QL 9:ca2e6010d9e2 2790 static void const *teObj_; ///< time event for QF local filter
QL 9:ca2e6010d9e2 2791 static void const *apObj_;///< generic object Application QF local filter
QL 9:ca2e6010d9e2 2792
QL 9:ca2e6010d9e2 2793 //////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2794 // Miscallaneous
QL 9:ca2e6010d9e2 2795 /// tick counter for the QS_QF_TICK record
QL 9:ca2e6010d9e2 2796 static QSTimeCtr tickCtr_;
QL 9:ca2e6010d9e2 2797 };
QL 9:ca2e6010d9e2 2798
QL 9:ca2e6010d9e2 2799 /// \brief Enumerates data formats recognized by QS
QL 9:ca2e6010d9e2 2800 ///
QL 9:ca2e6010d9e2 2801 /// QS uses this enumeration is used only internally for the formatted user
QL 9:ca2e6010d9e2 2802 /// data elements.
QL 9:ca2e6010d9e2 2803 enum QSType {
QL 9:ca2e6010d9e2 2804 QS_I8_T, ///< signed 8-bit integer format
QL 9:ca2e6010d9e2 2805 QS_U8_T, ///< unsigned 8-bit integer format
QL 9:ca2e6010d9e2 2806 QS_I16_T, ///< signed 16-bit integer format
QL 9:ca2e6010d9e2 2807 QS_U16_T, ///< unsigned 16-bit integer format
QL 9:ca2e6010d9e2 2808 QS_I32_T, ///< signed 32-bit integer format
QL 9:ca2e6010d9e2 2809 QS_U32_T, ///< unsigned 32-bit integer format
QL 9:ca2e6010d9e2 2810 QS_F32_T, ///< 32-bit floating point format
QL 9:ca2e6010d9e2 2811 QS_F64_T, ///< 64-bit floating point format
QL 9:ca2e6010d9e2 2812 QS_STR_T, ///< zero-terminated ASCII string format
QL 9:ca2e6010d9e2 2813 QS_MEM_T, ///< up to 255-bytes memory block format
QL 9:ca2e6010d9e2 2814 QS_SIG_T, ///< event signal format
QL 9:ca2e6010d9e2 2815 QS_OBJ_T, ///< object pointer format
QL 9:ca2e6010d9e2 2816 QS_FUN_T, ///< function pointer format
QL 9:ca2e6010d9e2 2817 QS_I64_T, ///< signed 64-bit integer format
QL 9:ca2e6010d9e2 2818 QS_U64_T, ///< unsigned 64-bit integer format
QL 9:ca2e6010d9e2 2819 QS_U32_HEX_T ///< unsigned 32-bit integer in hex format
QL 9:ca2e6010d9e2 2820 };
QL 9:ca2e6010d9e2 2821
QL 9:ca2e6010d9e2 2822 /// \brief critical section nesting level
QL 9:ca2e6010d9e2 2823 ///
QL 9:ca2e6010d9e2 2824 /// \note Not to be used by Clients directly, only in ports of QF
QL 9:ca2e6010d9e2 2825 extern uint8_t QF_critNest_;
QL 9:ca2e6010d9e2 2826
QL 9:ca2e6010d9e2 2827 QP_END_
QL 9:ca2e6010d9e2 2828
QL 9:ca2e6010d9e2 2829
QL 9:ca2e6010d9e2 2830 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2831 // Macros for adding QS instrumentation to the client code
QL 9:ca2e6010d9e2 2832
QL 9:ca2e6010d9e2 2833 /// \brief Initialize the QS facility.
QL 9:ca2e6010d9e2 2834 ///
QL 9:ca2e6010d9e2 2835 /// This macro provides an indirection layer to invoke the QS initialization
QL 9:ca2e6010d9e2 2836 /// routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
QL 9:ca2e6010d9e2 2837 /// \sa QS::onStartup(), example of setting up a QS filter in #QS_FILTER_IN
QL 9:ca2e6010d9e2 2838 #define QS_INIT(arg_) (QP_ QS::onStartup(arg_))
QL 9:ca2e6010d9e2 2839
QL 9:ca2e6010d9e2 2840 /// \brief Cleanup the QS facility.
QL 9:ca2e6010d9e2 2841 ///
QL 9:ca2e6010d9e2 2842 /// This macro provides an indirection layer to invoke the QS cleanup
QL 9:ca2e6010d9e2 2843 /// routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
QL 9:ca2e6010d9e2 2844 /// \sa QS::onCleanup()
QL 9:ca2e6010d9e2 2845 #define QS_EXIT() (QP_ QS::onCleanup())
QL 9:ca2e6010d9e2 2846
QL 9:ca2e6010d9e2 2847 /// \brief Global Filter ON for a given record type \a rec.
QL 9:ca2e6010d9e2 2848 ///
QL 9:ca2e6010d9e2 2849 /// This macro provides an indirection layer to call QS::filterOn() if #Q_SPY
QL 9:ca2e6010d9e2 2850 /// is defined, or do nothing if #Q_SPY is not defined.
QL 9:ca2e6010d9e2 2851 ///
QL 9:ca2e6010d9e2 2852 /// The following example shows how to use QS filters:
QL 9:ca2e6010d9e2 2853 /// \include qs_filter.cpp
QL 9:ca2e6010d9e2 2854 #define QS_FILTER_ON(rec_) (QP_ QS::filterOn(static_cast<uint8_t>(rec_)))
QL 9:ca2e6010d9e2 2855
QL 9:ca2e6010d9e2 2856 /// \brief Global filter OFF for a given record type \a rec.
QL 9:ca2e6010d9e2 2857 ///
QL 9:ca2e6010d9e2 2858 /// This macro provides an indirection layer to call QS::filterOff() if #Q_SPY
QL 9:ca2e6010d9e2 2859 /// is defined, or do nothing if #Q_SPY is not defined.
QL 9:ca2e6010d9e2 2860 ///
QL 9:ca2e6010d9e2 2861 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 9:ca2e6010d9e2 2862 #define QS_FILTER_OFF(rec_) (QP_ QS::filterOff(static_cast<uint8_t>(rec_)))
QL 9:ca2e6010d9e2 2863
QL 9:ca2e6010d9e2 2864 /// \brief Local Filter for a given state machine object \a obj_.
QL 9:ca2e6010d9e2 2865 ///
QL 9:ca2e6010d9e2 2866 /// This macro sets up the state machine object local filter if #Q_SPY is
QL 9:ca2e6010d9e2 2867 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 9:ca2e6010d9e2 2868 /// is the pointer to the state machine object that you want to monitor.
QL 9:ca2e6010d9e2 2869 ///
QL 9:ca2e6010d9e2 2870 /// The state machine object filter allows you to filter QS records pertaining
QL 9:ca2e6010d9e2 2871 /// only to a given state machine object. With this filter disabled, QS will
QL 9:ca2e6010d9e2 2872 /// output records from all state machines in your application. The object
QL 9:ca2e6010d9e2 2873 /// filter is disabled by setting the state machine pointer to NULL.
QL 9:ca2e6010d9e2 2874 ///
QL 9:ca2e6010d9e2 2875 /// The state machine filter affects the following QS records:
QL 9:ca2e6010d9e2 2876 /// ::QS_QEP_STATE_ENTRY, ::QS_QEP_STATE_EXIT, ::QS_QEP_STATE_INIT,
QL 9:ca2e6010d9e2 2877 /// ::QS_QEP_INIT_TRAN, ::QS_QEP_INTERN_TRAN, ::QS_QEP_TRAN,
QL 9:ca2e6010d9e2 2878 /// and ::QS_QEP_IGNORED.
QL 9:ca2e6010d9e2 2879 ///
QL 9:ca2e6010d9e2 2880 /// \note Because active objects are state machines at the same time,
QL 9:ca2e6010d9e2 2881 /// the state machine filter (#QS_FILTER_SM_OBJ) pertains to active
QL 9:ca2e6010d9e2 2882 /// objects as well. However, the state machine filter is more general,
QL 9:ca2e6010d9e2 2883 /// because it can be used only for state machines that are not active
QL 9:ca2e6010d9e2 2884 /// objects, such as "Orthogonal Components".
QL 9:ca2e6010d9e2 2885 ///
QL 9:ca2e6010d9e2 2886 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 9:ca2e6010d9e2 2887 #define QS_FILTER_SM_OBJ(obj_) (QP_ QS::smObj_ = (obj_))
QL 9:ca2e6010d9e2 2888
QL 9:ca2e6010d9e2 2889 /// \brief Local Filter for a given active object \a obj_.
QL 9:ca2e6010d9e2 2890 ///
QL 9:ca2e6010d9e2 2891 /// This macro sets up the active object local filter if #Q_SPY is defined,
QL 9:ca2e6010d9e2 2892 /// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
QL 9:ca2e6010d9e2 2893 /// pointer to the active object that you want to monitor.
QL 9:ca2e6010d9e2 2894 ///
QL 9:ca2e6010d9e2 2895 /// The active object filter allows you to filter QS records pertaining
QL 9:ca2e6010d9e2 2896 /// only to a given active object. With this filter disabled, QS will
QL 9:ca2e6010d9e2 2897 /// output records from all active objects in your application. The object
QL 9:ca2e6010d9e2 2898 /// filter is disabled by setting the active object pointer \a obj_ to NULL.
QL 9:ca2e6010d9e2 2899 ///
QL 9:ca2e6010d9e2 2900 /// The active object filter affects the following QS records:
QL 9:ca2e6010d9e2 2901 /// ::QS_QF_ACTIVE_ADD, ::QS_QF_ACTIVE_REMOVE, ::QS_QF_ACTIVE_SUBSCRIBE,
QL 9:ca2e6010d9e2 2902 /// ::QS_QF_ACTIVE_UNSUBSCRIBE, ::QS_QF_ACTIVE_POST_FIFO,
QL 9:ca2e6010d9e2 2903 /// ::QS_QF_ACTIVE_POST_LIFO, ::QS_QF_ACTIVE_GET, and ::QS_QF_ACTIVE_GET_LAST.
QL 9:ca2e6010d9e2 2904 ///
QL 9:ca2e6010d9e2 2905 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 9:ca2e6010d9e2 2906 #define QS_FILTER_AO_OBJ(obj_) (QP_ QS::aoObj_ = (obj_))
QL 9:ca2e6010d9e2 2907
QL 9:ca2e6010d9e2 2908 /// \brief Local Filter for a given memory pool object \a obj_.
QL 9:ca2e6010d9e2 2909 ///
QL 9:ca2e6010d9e2 2910 /// This macro sets up the memory pool object local filter if #Q_SPY is
QL 9:ca2e6010d9e2 2911 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 9:ca2e6010d9e2 2912 /// is the pointer to the memory buffer used during the initialization of the
QL 9:ca2e6010d9e2 2913 /// event pool with QF::poolInit().
QL 9:ca2e6010d9e2 2914 ///
QL 9:ca2e6010d9e2 2915 /// The memory pool filter allows you to filter QS records pertaining
QL 9:ca2e6010d9e2 2916 /// only to a given memory pool. With this filter disabled, QS will
QL 9:ca2e6010d9e2 2917 /// output records from all memory pools in your application. The object
QL 9:ca2e6010d9e2 2918 /// filter is disabled by setting the memory pool pointer \a obj_ to NULL.
QL 9:ca2e6010d9e2 2919 ///
QL 9:ca2e6010d9e2 2920 /// The memory pool filter affects the following QS records:
QL 9:ca2e6010d9e2 2921 /// ::QS_QF_MPOOL_INIT, ::QS_QF_MPOOL_GET, and ::QS_QF_MPOOL_PUT.
QL 9:ca2e6010d9e2 2922 ///
QL 9:ca2e6010d9e2 2923 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 9:ca2e6010d9e2 2924 #define QS_FILTER_MP_OBJ(obj_) (QP_ QS::mpObj_ = (obj_))
QL 9:ca2e6010d9e2 2925
QL 9:ca2e6010d9e2 2926 /// \brief Filter for a given event queue object \a obj_.
QL 9:ca2e6010d9e2 2927 ///
QL 9:ca2e6010d9e2 2928 /// This macro sets up the event queue object filter if #Q_SPY is defined,
QL 9:ca2e6010d9e2 2929 /// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
QL 9:ca2e6010d9e2 2930 /// pointer to the "raw" thread-safe queue object you want to monitor.
QL 9:ca2e6010d9e2 2931 ///
QL 9:ca2e6010d9e2 2932 /// The event queue filter allows you to filter QS records pertaining
QL 9:ca2e6010d9e2 2933 /// only to a given event queue. With this filter disabled, QS will
QL 9:ca2e6010d9e2 2934 /// output records from all event queues in your application. The object
QL 9:ca2e6010d9e2 2935 /// filter is disabled by setting the event queue pointer \a obj_ to NULL.
QL 9:ca2e6010d9e2 2936 ///
QL 9:ca2e6010d9e2 2937 /// The event queue filter affects the following QS records:
QL 9:ca2e6010d9e2 2938 /// ::QS_QF_EQUEUE_INIT, ::QS_QF_EQUEUE_POST_FIFO, ::QS_QF_EQUEUE_POST_LIFO,
QL 9:ca2e6010d9e2 2939 /// ::QS_QF_EQUEUE_GET, and ::QS_QF_EQUEUE_GET_LAST.
QL 9:ca2e6010d9e2 2940 ///
QL 9:ca2e6010d9e2 2941 /// \sa Example of using QS filters in #QS_FILTER_IN documentation
QL 9:ca2e6010d9e2 2942 #define QS_FILTER_EQ_OBJ(obj_) (QP_ QS::eqObj_ = (obj_))
QL 9:ca2e6010d9e2 2943
QL 9:ca2e6010d9e2 2944 /// \brief Local Filter for a given time event object \a obj_.
QL 9:ca2e6010d9e2 2945 ///
QL 9:ca2e6010d9e2 2946 /// This macro sets up the time event object local filter if #Q_SPY is
QL 9:ca2e6010d9e2 2947 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 9:ca2e6010d9e2 2948 /// is the pointer to the time event object you want to monitor.
QL 9:ca2e6010d9e2 2949 ///
QL 9:ca2e6010d9e2 2950 /// The time event filter allows you to filter QS records pertaining
QL 9:ca2e6010d9e2 2951 /// only to a given time event. With this filter disabled, QS will
QL 9:ca2e6010d9e2 2952 /// output records from all time events in your application. The object
QL 9:ca2e6010d9e2 2953 /// filter is disabled by setting the time event pointer \a obj_ to NULL.
QL 9:ca2e6010d9e2 2954 ///
QL 9:ca2e6010d9e2 2955 /// The time event filter affects the following QS records:
QL 9:ca2e6010d9e2 2956 /// ::QS_QF_TIMEEVT_ARM, ::QS_QF_TIMEEVT_AUTO_DISARM,
QL 9:ca2e6010d9e2 2957 /// ::QS_QF_TIMEEVT_DISARM_ATTEMPT, ::QS_QF_TIMEEVT_DISARM,
QL 9:ca2e6010d9e2 2958 /// ::QS_QF_TIMEEVT_REARM, ::QS_QF_TIMEEVT_POST, and ::QS_QF_TIMEEVT_PUBLISH.
QL 9:ca2e6010d9e2 2959 ///
QL 9:ca2e6010d9e2 2960 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 9:ca2e6010d9e2 2961 #define QS_FILTER_TE_OBJ(obj_) (QP_ QS::teObj_ = (obj_))
QL 9:ca2e6010d9e2 2962
QL 9:ca2e6010d9e2 2963 /// \brief Local Filter for a generic application object \a obj_.
QL 9:ca2e6010d9e2 2964 ///
QL 9:ca2e6010d9e2 2965 /// This macro sets up the local application object filter if #Q_SPY is
QL 9:ca2e6010d9e2 2966 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 9:ca2e6010d9e2 2967 /// is the pointer to the application object you want to monitor.
QL 9:ca2e6010d9e2 2968 ///
QL 9:ca2e6010d9e2 2969 /// The application object filter allows you to filter QS records pertaining
QL 9:ca2e6010d9e2 2970 /// only to a given application object. With this filter disabled, QS will
QL 9:ca2e6010d9e2 2971 /// output records from all application-records enabled by the global filter.
QL 9:ca2e6010d9e2 2972 /// The local filter is disabled by setting the time event pointer \a obj_
QL 9:ca2e6010d9e2 2973 /// to NULL.
QL 9:ca2e6010d9e2 2974 ///
QL 9:ca2e6010d9e2 2975 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 9:ca2e6010d9e2 2976 #define QS_FILTER_AP_OBJ(obj_) (QP_ QS::apObj_ = (obj_))
QL 9:ca2e6010d9e2 2977
QL 9:ca2e6010d9e2 2978
QL 9:ca2e6010d9e2 2979 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 2980 // Macros to generate user QS records
QL 9:ca2e6010d9e2 2981
QL 9:ca2e6010d9e2 2982 #define QS_GLB_FILTER_(rec_) \
QL 9:ca2e6010d9e2 2983 ((QP_ QS::glbFilter_[static_cast<uint8_t>(rec_) >> 3] \
QL 9:ca2e6010d9e2 2984 & (static_cast<uint8_t>(1U << (static_cast<uint8_t>(rec_) \
QL 9:ca2e6010d9e2 2985 & static_cast<uint8_t>(7))))) \
QL 9:ca2e6010d9e2 2986 != static_cast<uint8_t>(0))
QL 9:ca2e6010d9e2 2987
QL 9:ca2e6010d9e2 2988 /// \brief Begin a QS user record without entering critical section.
QL 9:ca2e6010d9e2 2989 #define QS_BEGIN_NOCRIT(rec_, obj_) \
QL 9:ca2e6010d9e2 2990 if (QS_GLB_FILTER_(rec_) \
QL 9:ca2e6010d9e2 2991 && ((QP_ QS::apObj_ == static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 2992 || (QP_ QS::apObj_ == (obj_)))) \
QL 9:ca2e6010d9e2 2993 { \
QL 9:ca2e6010d9e2 2994 QP_ QS::begin(static_cast<uint8_t>(rec_)); \
QL 9:ca2e6010d9e2 2995 QS_TIME_();
QL 9:ca2e6010d9e2 2996
QL 9:ca2e6010d9e2 2997 /// \brief End a QS user record without exiting critical section.
QL 9:ca2e6010d9e2 2998 #define QS_END_NOCRIT() \
QL 9:ca2e6010d9e2 2999 QS_END_NOCRIT_()
QL 9:ca2e6010d9e2 3000
QL 9:ca2e6010d9e2 3001 // QS-specific critical section
QL 9:ca2e6010d9e2 3002 #ifndef QF_CRIT_STAT_TYPE
QL 9:ca2e6010d9e2 3003 /// \brief This is an internal macro for defining the critical section
QL 9:ca2e6010d9e2 3004 /// status type.
QL 9:ca2e6010d9e2 3005 ///
QL 9:ca2e6010d9e2 3006 /// The purpose of this macro is to enable writing the same code for the
QL 9:ca2e6010d9e2 3007 /// case when critical sectgion status type is defined and when it is not.
QL 9:ca2e6010d9e2 3008 /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
QL 9:ca2e6010d9e2 3009 /// provides the definition of the critical section status variable.
QL 9:ca2e6010d9e2 3010 /// Otherwise this macro is empty.
QL 9:ca2e6010d9e2 3011 /// \sa #QF_CRIT_STAT_TYPE
QL 9:ca2e6010d9e2 3012 ///
QL 9:ca2e6010d9e2 3013 #define QS_CRIT_STAT_
QL 9:ca2e6010d9e2 3014
QL 9:ca2e6010d9e2 3015 /// \brief This is an internal macro for entering a critical section.
QL 9:ca2e6010d9e2 3016 ///
QL 9:ca2e6010d9e2 3017 /// The purpose of this macro is to enable writing the same code for the
QL 9:ca2e6010d9e2 3018 /// case when critical sectgion status type is defined and when it is not.
QL 9:ca2e6010d9e2 3019 /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
QL 9:ca2e6010d9e2 3020 /// invokes #QF_CRIT_ENTRY passing the key variable as the parameter.
QL 9:ca2e6010d9e2 3021 /// Otherwise #QF_CRIT_ENTRY is invoked with a dummy parameter.
QL 9:ca2e6010d9e2 3022 /// \sa #QF_CRIT_ENTRY
QL 9:ca2e6010d9e2 3023 ///
QL 9:ca2e6010d9e2 3024 #define QS_CRIT_ENTRY_() QF_CRIT_ENTRY(dummy)
QL 9:ca2e6010d9e2 3025
QL 9:ca2e6010d9e2 3026 /// \brief This is an internal macro for exiting a cricial section.
QL 9:ca2e6010d9e2 3027 ///
QL 9:ca2e6010d9e2 3028 /// The purpose of this macro is to enable writing the same code for the
QL 9:ca2e6010d9e2 3029 /// case when critical sectgion status type is defined and when it is not.
QL 9:ca2e6010d9e2 3030 /// If the macro #QF_CRIT_STAT_TYPE is defined, this internal macro
QL 9:ca2e6010d9e2 3031 /// invokes #QF_CRIT_EXIT passing the key variable as the parameter.
QL 9:ca2e6010d9e2 3032 /// Otherwise #QF_CRIT_EXIT is invoked with a dummy parameter.
QL 9:ca2e6010d9e2 3033 /// \sa #QF_CRIT_EXIT
QL 9:ca2e6010d9e2 3034 ///
QL 9:ca2e6010d9e2 3035 #define QS_CRIT_EXIT_() QF_CRIT_EXIT(dummy)
QL 9:ca2e6010d9e2 3036
QL 9:ca2e6010d9e2 3037 #else
QL 9:ca2e6010d9e2 3038 #define QS_CRIT_STAT_ QF_CRIT_STAT_TYPE critStat_;
QL 9:ca2e6010d9e2 3039 #define QS_CRIT_ENTRY_() QF_CRIT_ENTRY(critStat_)
QL 9:ca2e6010d9e2 3040 #define QS_CRIT_EXIT_() QF_CRIT_EXIT(critStat_)
QL 9:ca2e6010d9e2 3041 #endif
QL 9:ca2e6010d9e2 3042
QL 9:ca2e6010d9e2 3043 /// \brief Begin a user QS record with entering critical section.
QL 9:ca2e6010d9e2 3044 ///
QL 9:ca2e6010d9e2 3045 /// The following example shows how to build a user QS record using the
QL 9:ca2e6010d9e2 3046 /// macros #QS_BEGIN, #QS_END, and the formatted output macros: #QS_U8 and
QL 9:ca2e6010d9e2 3047 /// #QS_STR.
QL 9:ca2e6010d9e2 3048 /// \include qs_user.cpp
QL 9:ca2e6010d9e2 3049 /// \note Must always be used in pair with #QS_END
QL 9:ca2e6010d9e2 3050 #define QS_BEGIN(rec_, obj_) \
QL 9:ca2e6010d9e2 3051 if (QS_GLB_FILTER_(rec_) \
QL 9:ca2e6010d9e2 3052 && ((QP_ QS::apObj_ == static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3053 || (QP_ QS::apObj_ == (obj_)))) \
QL 9:ca2e6010d9e2 3054 { \
QL 9:ca2e6010d9e2 3055 QS_CRIT_STAT_ \
QL 9:ca2e6010d9e2 3056 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3057 QP_ QS::begin(static_cast<uint8_t>(rec_)); \
QL 9:ca2e6010d9e2 3058 QS_TIME_();
QL 9:ca2e6010d9e2 3059
QL 9:ca2e6010d9e2 3060 /// \brief End a QS record with exiting critical section.
QL 9:ca2e6010d9e2 3061 /// \sa example for #QS_BEGIN
QL 9:ca2e6010d9e2 3062 /// \note Must always be used in pair with #QS_BEGIN
QL 9:ca2e6010d9e2 3063 #define QS_END() \
QL 9:ca2e6010d9e2 3064 QS_END_()
QL 9:ca2e6010d9e2 3065
QL 9:ca2e6010d9e2 3066
QL 9:ca2e6010d9e2 3067 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 3068 // Macros for use inside other macros or internally in the QP code
QL 9:ca2e6010d9e2 3069
QL 9:ca2e6010d9e2 3070 /// \brief Internal QS macro to begin a QS record with entering critical
QL 9:ca2e6010d9e2 3071 /// section.
QL 9:ca2e6010d9e2 3072 /// \note This macro is intended to use only inside QP components and NOT
QL 9:ca2e6010d9e2 3073 /// at the application level. \sa #QS_BEGIN
QL 9:ca2e6010d9e2 3074 #define QS_BEGIN_(rec_, objFilter_, obj_) \
QL 9:ca2e6010d9e2 3075 if (QS_GLB_FILTER_(rec_) \
QL 9:ca2e6010d9e2 3076 && (((objFilter_) == static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3077 || ((objFilter_) == (obj_)))) \
QL 9:ca2e6010d9e2 3078 { \
QL 9:ca2e6010d9e2 3079 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3080 QP_ QS::begin(static_cast<uint8_t>(rec_));
QL 9:ca2e6010d9e2 3081
QL 9:ca2e6010d9e2 3082 /// \brief Internal QS macro to end a QS record with exiting critical
QL 9:ca2e6010d9e2 3083 /// section.
QL 9:ca2e6010d9e2 3084 /// \note This macro is intended to use only inside QP components and NOT
QL 9:ca2e6010d9e2 3085 /// at the application level. \sa #QS_END
QL 9:ca2e6010d9e2 3086 #define QS_END_() \
QL 9:ca2e6010d9e2 3087 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3088 QS_CRIT_EXIT_(); \
QL 9:ca2e6010d9e2 3089 }
QL 9:ca2e6010d9e2 3090
QL 9:ca2e6010d9e2 3091 /// \brief Internal QS macro to begin a QS record without entering critical
QL 9:ca2e6010d9e2 3092 /// section.
QL 9:ca2e6010d9e2 3093 /// \note This macro is intended to use only inside QP components and NOT
QL 9:ca2e6010d9e2 3094 /// at the application level. \sa #QS_BEGIN_NOCRIT
QL 9:ca2e6010d9e2 3095 #define QS_BEGIN_NOCRIT_(rec_, objFilter_, obj_) \
QL 9:ca2e6010d9e2 3096 if (QS_GLB_FILTER_(rec_) \
QL 9:ca2e6010d9e2 3097 && (((objFilter_) == static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3098 || ((objFilter_) == (obj_)))) \
QL 9:ca2e6010d9e2 3099 { \
QL 9:ca2e6010d9e2 3100 QP_ QS::begin(static_cast<uint8_t>(rec_));
QL 9:ca2e6010d9e2 3101
QL 9:ca2e6010d9e2 3102 /// \brief Internal QS macro to end a QS record without exiting critical
QL 9:ca2e6010d9e2 3103 /// section.
QL 9:ca2e6010d9e2 3104 /// \note This macro is intended to use only inside QP components and NOT
QL 9:ca2e6010d9e2 3105 /// at the application level. \sa #QS_END_NOCRIT
QL 9:ca2e6010d9e2 3106 #define QS_END_NOCRIT_() \
QL 9:ca2e6010d9e2 3107 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3108 }
QL 9:ca2e6010d9e2 3109
QL 9:ca2e6010d9e2 3110 #if (Q_SIGNAL_SIZE == 1)
QL 9:ca2e6010d9e2 3111 /// \brief Internal QS macro to output an unformatted event signal
QL 9:ca2e6010d9e2 3112 /// data element
QL 9:ca2e6010d9e2 3113 /// \note the size of the pointer depends on the macro #Q_SIGNAL_SIZE.
QL 9:ca2e6010d9e2 3114 #define QS_SIG_(sig_) (QP_ QS::u8_(static_cast<uint8_t>(sig_))))
QL 9:ca2e6010d9e2 3115 #elif (Q_SIGNAL_SIZE == 2)
QL 9:ca2e6010d9e2 3116 #define QS_SIG_(sig_) (QP_ QS::u16_(static_cast<uint16_t>(sig_)))
QL 9:ca2e6010d9e2 3117 #elif (Q_SIGNAL_SIZE == 4)
QL 9:ca2e6010d9e2 3118 #define QS_SIG_(sig_) (QP_ QS::u32_(static_cast<uint32_t>(sig_)))
QL 9:ca2e6010d9e2 3119 #endif
QL 9:ca2e6010d9e2 3120
QL 9:ca2e6010d9e2 3121 /// \brief Internal QS macro to output an unformatted uint8_t data element
QL 9:ca2e6010d9e2 3122 #define QS_U8_(data_) (QP_ QS::u8_(data_))
QL 9:ca2e6010d9e2 3123
QL 9:ca2e6010d9e2 3124 /// \brief Internal QS macro to output an unformatted uint16_t data element
QL 9:ca2e6010d9e2 3125 #define QS_U16_(data_) (QP_ QS::u16_(data_))
QL 9:ca2e6010d9e2 3126
QL 9:ca2e6010d9e2 3127 /// \brief Internal QS macro to output an unformatted uint32_t data element
QL 9:ca2e6010d9e2 3128 #define QS_U32_(data_) (QP_ QS::u32_(data_))
QL 9:ca2e6010d9e2 3129
QL 9:ca2e6010d9e2 3130
QL 9:ca2e6010d9e2 3131 #if (QS_OBJ_PTR_SIZE == 1)
QL 9:ca2e6010d9e2 3132 #define QS_OBJ_(obj_) (QP_ QS::u8_(reinterpret_cast<uint8_t>(obj_)))
QL 9:ca2e6010d9e2 3133 #elif (QS_OBJ_PTR_SIZE == 2)
QL 9:ca2e6010d9e2 3134 #define QS_OBJ_(obj_) (QP_ QS::u16_(reinterpret_cast<uint16_t>(obj_)))
QL 9:ca2e6010d9e2 3135 #elif (QS_OBJ_PTR_SIZE == 4)
QL 9:ca2e6010d9e2 3136 #define QS_OBJ_(obj_) (QP_ QS::u32_(reinterpret_cast<uint32_t>(obj_)))
QL 9:ca2e6010d9e2 3137 #elif (QS_OBJ_PTR_SIZE == 8)
QL 9:ca2e6010d9e2 3138 #define QS_OBJ_(obj_) (QP_ QS::u64_(reinterpret_cast<uint64_t>(obj_)))
QL 9:ca2e6010d9e2 3139 #else
QL 9:ca2e6010d9e2 3140
QL 9:ca2e6010d9e2 3141 /// \brief Internal QS macro to output an unformatted object pointer
QL 9:ca2e6010d9e2 3142 /// data element
QL 9:ca2e6010d9e2 3143 /// \note the size of the pointer depends on the macro #QS_OBJ_PTR_SIZE.
QL 9:ca2e6010d9e2 3144 /// If the size is not defined the size of pointer is assumed 4-bytes.
QL 9:ca2e6010d9e2 3145 #define QS_OBJ_(obj_) (QP_ QS::u32_(reinterpret_cast<uint32_t>(obj_)))
QL 9:ca2e6010d9e2 3146 #endif
QL 9:ca2e6010d9e2 3147
QL 9:ca2e6010d9e2 3148
QL 9:ca2e6010d9e2 3149 #if (QS_FUN_PTR_SIZE == 1)
QL 9:ca2e6010d9e2 3150 #define QS_FUN_(fun_) (QP_ QS::u8_(reinterpret_cast<uint8_t>(fun_)))
QL 9:ca2e6010d9e2 3151 #elif (QS_FUN_PTR_SIZE == 2)
QL 9:ca2e6010d9e2 3152 #define QS_FUN_(fun_) (QP_ QS::u16_(reinterpret_cast<uint16_t>(fun_)))
QL 9:ca2e6010d9e2 3153 #elif (QS_FUN_PTR_SIZE == 4)
QL 9:ca2e6010d9e2 3154 #define QS_FUN_(fun_) (QP_ QS::u32_(reinterpret_cast<uint32_t>(fun_)))
QL 9:ca2e6010d9e2 3155 #elif (QS_FUN_PTR_SIZE == 8)
QL 9:ca2e6010d9e2 3156 #define QS_FUN_(fun_) (QP_ QS::u64_(reinterpret_cast<uint64_t>(fun_)))
QL 9:ca2e6010d9e2 3157 #else
QL 9:ca2e6010d9e2 3158
QL 9:ca2e6010d9e2 3159 /// \brief Internal QS macro to output an unformatted function pointer
QL 9:ca2e6010d9e2 3160 /// data element
QL 9:ca2e6010d9e2 3161 /// \note the size of the pointer depends on the macro #QS_FUN_PTR_SIZE.
QL 9:ca2e6010d9e2 3162 /// If the size is not defined the size of pointer is assumed 4-bytes.
QL 9:ca2e6010d9e2 3163 #define QS_FUN_(fun_) (QP_ QS::u32_(reinterpret_cast<uint32_t>(fun_)))
QL 9:ca2e6010d9e2 3164 #endif
QL 9:ca2e6010d9e2 3165
QL 9:ca2e6010d9e2 3166 /// \brief Internal QS macro to output a zero-terminated ASCII string
QL 9:ca2e6010d9e2 3167 /// data element
QL 9:ca2e6010d9e2 3168 #define QS_STR_(msg_) (QP_ QS::str_(msg_))
QL 9:ca2e6010d9e2 3169
QL 9:ca2e6010d9e2 3170 /// \brief Internal QS macro to output a zero-terminated ASCII string
QL 9:ca2e6010d9e2 3171 /// allocated in ROM data element
QL 9:ca2e6010d9e2 3172 #define QS_STR_ROM_(msg_) (QP_ QS::str_ROM_(msg_))
QL 9:ca2e6010d9e2 3173
QL 9:ca2e6010d9e2 3174 //////////////////////////////////////////////////////////////////////////////
QL 9:ca2e6010d9e2 3175 // Macros for use in the client code
QL 9:ca2e6010d9e2 3176
QL 9:ca2e6010d9e2 3177 /// \brief Output formatted int8_t to the QS record
QL 9:ca2e6010d9e2 3178 #define QS_I8(width_, data_) \
QL 9:ca2e6010d9e2 3179 (QP_ QS::u8(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3180 | static_cast<uint8_t>(QP_ QS_I8_T)), (data_)))
QL 9:ca2e6010d9e2 3181
QL 9:ca2e6010d9e2 3182 /// \brief Output formatted uint8_t to the QS record
QL 9:ca2e6010d9e2 3183 #define QS_U8(width_, data_) \
QL 9:ca2e6010d9e2 3184 (QP_ QS::u8(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3185 | static_cast<uint8_t>(QP_ QS_U8_T)), (data_)))
QL 9:ca2e6010d9e2 3186
QL 9:ca2e6010d9e2 3187 /// \brief Output formatted int16_t to the QS record
QL 9:ca2e6010d9e2 3188 #define QS_I16(width_, data_) \
QL 9:ca2e6010d9e2 3189 (QP_ QS::u16(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3190 | static_cast<uint8_t>(QP_ QS_I16_T)), (data_)))
QL 9:ca2e6010d9e2 3191
QL 9:ca2e6010d9e2 3192 /// \brief Output formatted uint16_t to the QS record
QL 9:ca2e6010d9e2 3193 #define QS_U16(width_, data_) \
QL 9:ca2e6010d9e2 3194 (QP_ QS::u16(static_cast<uint8_t>((((width_) << 4)) \
QL 9:ca2e6010d9e2 3195 | static_cast<uint8_t>(QP_ QS_U16_T)), (data_)))
QL 9:ca2e6010d9e2 3196
QL 9:ca2e6010d9e2 3197 /// \brief Output formatted int32_t to the QS record
QL 9:ca2e6010d9e2 3198 #define QS_I32(width_, data_) \
QL 9:ca2e6010d9e2 3199 (QP_ QS::u32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3200 | static_cast<uint8_t>(QP_ QS_I32_T)), (data_)))
QL 9:ca2e6010d9e2 3201
QL 9:ca2e6010d9e2 3202 /// \brief Output formatted uint32_t to the QS record
QL 9:ca2e6010d9e2 3203 #define QS_U32(width_, data_) \
QL 9:ca2e6010d9e2 3204 (QP_ QS::u32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3205 | static_cast<uint8_t>(QP_ QS_U32_T)), (data_)))
QL 9:ca2e6010d9e2 3206
QL 9:ca2e6010d9e2 3207 /// \brief Output formatted 32-bit floating point number to the QS record
QL 9:ca2e6010d9e2 3208 #define QS_F32(width_, data_) \
QL 9:ca2e6010d9e2 3209 QP_ QS::f32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3210 | static_cast<uint8_t>(QP_ QS_F32_T)), (data_)))
QL 9:ca2e6010d9e2 3211
QL 9:ca2e6010d9e2 3212 /// \brief Output formatted 64-bit floating point number to the QS record
QL 9:ca2e6010d9e2 3213 #define QS_F64(width_, data_) \
QL 9:ca2e6010d9e2 3214 (QP_ QS::f64(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3215 | static_cast<uint8_t>(QP_ QS_F64_T)), (data_)))
QL 9:ca2e6010d9e2 3216
QL 9:ca2e6010d9e2 3217 /// \brief Output formatted int64_t to the QS record
QL 9:ca2e6010d9e2 3218 #define QS_I64(width_, data_) \
QL 9:ca2e6010d9e2 3219 (QP_ QS::u64(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3220 | static_cast<uint8_t>(QP_ QS_I64_T)), (data_)))
QL 9:ca2e6010d9e2 3221
QL 9:ca2e6010d9e2 3222 /// \brief Output formatted uint64_t to the QS record
QL 9:ca2e6010d9e2 3223 #define QS_U64(width_, data_) \
QL 9:ca2e6010d9e2 3224 (QP_ QS::u64(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3225 | static_cast<uint8_t>(QP_ QS_U64_T)), (data_)))
QL 9:ca2e6010d9e2 3226
QL 9:ca2e6010d9e2 3227 /// \brief Output formatted uint32_t to the QS record
QL 9:ca2e6010d9e2 3228 #define QS_U32_HEX(width_, data_) \
QL 9:ca2e6010d9e2 3229 (QP_ QS::u32(static_cast<uint8_t>((static_cast<uint8_t>((width_) << 4)) \
QL 9:ca2e6010d9e2 3230 | static_cast<uint8_t>(QP_ QS_U32_HEX_T)), (data_)))
QL 9:ca2e6010d9e2 3231
QL 9:ca2e6010d9e2 3232 /// \brief Output formatted zero-terminated ASCII string to the QS record
QL 9:ca2e6010d9e2 3233 #define QS_STR(str_) (QP_ QS::str(str_))
QL 9:ca2e6010d9e2 3234
QL 9:ca2e6010d9e2 3235 /// \brief Output formatted zero-terminated ASCII string from ROM
QL 9:ca2e6010d9e2 3236 /// to the QS record
QL 9:ca2e6010d9e2 3237 #define QS_STR_ROM(str_) (QP_ QS::str_ROM(str_))
QL 9:ca2e6010d9e2 3238
QL 9:ca2e6010d9e2 3239 /// \brief Output formatted memory block of up to 255 bytes to the QS
QL 9:ca2e6010d9e2 3240 /// record
QL 9:ca2e6010d9e2 3241 #define QS_MEM(mem_, size_) (QP_ QS::mem((mem_), (size_)))
QL 9:ca2e6010d9e2 3242
QL 9:ca2e6010d9e2 3243
QL 9:ca2e6010d9e2 3244 #if (QS_OBJ_PTR_SIZE == 1)
QL 9:ca2e6010d9e2 3245 #define QS_OBJ(obj_) (QP_ QS::u8(QS_OBJ_T, (uint8_t)(obj_)))
QL 9:ca2e6010d9e2 3246 #elif (QS_OBJ_PTR_SIZE == 2)
QL 9:ca2e6010d9e2 3247 #define QS_OBJ(obj_) (QP_ QS::u16(QS_OBJ_T, (uint16_t)(obj_)))
QL 9:ca2e6010d9e2 3248 #elif (QS_OBJ_PTR_SIZE == 4)
QL 9:ca2e6010d9e2 3249 #define QS_OBJ(obj_) (QP_ QS::u32(QS_OBJ_T, (uint32_t)(obj_)))
QL 9:ca2e6010d9e2 3250 #elif (QS_OBJ_PTR_SIZE == 8)
QL 9:ca2e6010d9e2 3251 #define QS_OBJ(obj_) (QP_ QS::u64(QS_OBJ_T, (uint64_t)(obj_)))
QL 9:ca2e6010d9e2 3252 #else
QL 9:ca2e6010d9e2 3253 /// \brief Output formatted object pointer to the QS record
QL 9:ca2e6010d9e2 3254 #define QS_OBJ(obj_) (QP_ QS::u32(QS_OBJ_T, (uint32_t)(obj_)))
QL 9:ca2e6010d9e2 3255 #endif
QL 9:ca2e6010d9e2 3256
QL 9:ca2e6010d9e2 3257
QL 9:ca2e6010d9e2 3258 #if (QS_FUN_PTR_SIZE == 1)
QL 9:ca2e6010d9e2 3259 #define QS_FUN(fun_) (QP_ QS::u8(QS_FUN_T, (uint8_t)(fun_)))
QL 9:ca2e6010d9e2 3260 #elif (QS_FUN_PTR_SIZE == 2)
QL 9:ca2e6010d9e2 3261 #define QS_FUN(fun_) (QP_ QS::u16(QS_FUN_T, (uint16_t)(fun_)))
QL 9:ca2e6010d9e2 3262 #elif (QS_FUN_PTR_SIZE == 4)
QL 9:ca2e6010d9e2 3263 #define QS_FUN(fun_) (QP_ QS::u32(QS_FUN_T, (uint32_t)(fun_)))
QL 9:ca2e6010d9e2 3264 #elif (QS_FUN_PTR_SIZE == 8)
QL 9:ca2e6010d9e2 3265 #define QS_FUN(fun_) (QP_ QS::u64(QS_FUN_T, (uint64_t)(fun_)))
QL 9:ca2e6010d9e2 3266 #else
QL 9:ca2e6010d9e2 3267 /// \brief Output formatted function pointer to the QS record
QL 9:ca2e6010d9e2 3268 #define QS_FUN(fun_) (QP_ QS::u32(QS_FUN_T, (uint32_t)(fun_)))
QL 9:ca2e6010d9e2 3269 #endif
QL 9:ca2e6010d9e2 3270
QL 9:ca2e6010d9e2 3271
QL 9:ca2e6010d9e2 3272 /// \brief Reset the QS session.
QL 9:ca2e6010d9e2 3273 ///
QL 9:ca2e6010d9e2 3274 /// This trace record should be generated at the beginning of the QS session.
QL 9:ca2e6010d9e2 3275 /// It informs the QSPY host application that the new session has been started.
QL 9:ca2e6010d9e2 3276 #define QS_RESET() do { \
QL 9:ca2e6010d9e2 3277 if (QS_GLB_FILTER_(QP_ QS_QP_RESET)) { \
QL 9:ca2e6010d9e2 3278 QS_CRIT_STAT_ \
QL 9:ca2e6010d9e2 3279 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3280 QP_ QS::begin(static_cast<uint8_t>(QP_ QS_QP_RESET)); \
QL 9:ca2e6010d9e2 3281 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3282 QS_CRIT_EXIT_(); \
QL 9:ca2e6010d9e2 3283 QP_ QS::onFlush(); \
QL 9:ca2e6010d9e2 3284 } \
QL 9:ca2e6010d9e2 3285 } while (false)
QL 9:ca2e6010d9e2 3286
QL 9:ca2e6010d9e2 3287 /// \brief Output signal dictionary record
QL 9:ca2e6010d9e2 3288 ///
QL 9:ca2e6010d9e2 3289 /// A signal dictionary record associates the numerical value of the signal
QL 9:ca2e6010d9e2 3290 /// and the binary address of the state machine that consumes that signal
QL 9:ca2e6010d9e2 3291 /// with the human-readable name of the signal.
QL 9:ca2e6010d9e2 3292 ///
QL 9:ca2e6010d9e2 3293 /// Providing a signal dictionary QS record can vastly improve readability of
QL 9:ca2e6010d9e2 3294 /// the QS log, because instead of dealing with cryptic machine addresses the
QL 9:ca2e6010d9e2 3295 /// QSpy host utility can display human-readable names.
QL 9:ca2e6010d9e2 3296 ///
QL 9:ca2e6010d9e2 3297 /// A signal dictionary entry is associated with both the signal value \a sig_
QL 9:ca2e6010d9e2 3298 /// and the state machine \a obj_, because signals are required to be unique
QL 9:ca2e6010d9e2 3299 /// only within a given state machine and therefore the same numerical values
QL 9:ca2e6010d9e2 3300 /// can represent different signals in different state machines.
QL 9:ca2e6010d9e2 3301 ///
QL 9:ca2e6010d9e2 3302 /// For the "global" signals that have the same meaning in all state machines
QL 9:ca2e6010d9e2 3303 /// (such as globally published signals), you can specify a signal dictionary
QL 9:ca2e6010d9e2 3304 /// entry with the \a obj_ parameter set to NULL.
QL 9:ca2e6010d9e2 3305 ///
QL 9:ca2e6010d9e2 3306 /// The following example shows the definition of signal dictionary entries
QL 9:ca2e6010d9e2 3307 /// in the initial transition of the Table active object. Please note that
QL 9:ca2e6010d9e2 3308 /// signals HUNGRY_SIG and DONE_SIG are associated with the Table state
QL 9:ca2e6010d9e2 3309 /// machine only ("me" \a obj_ pointer). The EAT_SIG signal, on the other
QL 9:ca2e6010d9e2 3310 /// hand, is global (0 \a obj_ pointer):
QL 9:ca2e6010d9e2 3311 /// \include qs_sigDic.cpp
QL 9:ca2e6010d9e2 3312 ///
QL 9:ca2e6010d9e2 3313 /// \note The QSpy log utility must capture the signal dictionary record
QL 9:ca2e6010d9e2 3314 /// in order to use the human-readable information. You need to connect to
QL 9:ca2e6010d9e2 3315 /// the target before the dictionary entries have been transmitted.
QL 9:ca2e6010d9e2 3316 ///
QL 9:ca2e6010d9e2 3317 /// The following QSpy log example shows the signal dictionary records
QL 9:ca2e6010d9e2 3318 /// generated from the Table initial transition and subsequent records that
QL 9:ca2e6010d9e2 3319 /// show human-readable names of the signals:
QL 9:ca2e6010d9e2 3320 /// \include qs_sigLog.txt
QL 9:ca2e6010d9e2 3321 ///
QL 9:ca2e6010d9e2 3322 /// The following QSpy log example shows the same sequence of records, but
QL 9:ca2e6010d9e2 3323 /// with dictionary records removed. The human-readable signal names are not
QL 9:ca2e6010d9e2 3324 /// available.
QL 9:ca2e6010d9e2 3325 /// \include qs_sigLog0.txt
QL 9:ca2e6010d9e2 3326 #define QS_SIG_DICTIONARY(sig_, obj_) do { \
QL 9:ca2e6010d9e2 3327 if (QS_GLB_FILTER_(QP_ QS_SIG_DIC)) { \
QL 9:ca2e6010d9e2 3328 static char_t const Q_ROM Q_ROM_VAR sig_name_[] = #sig_; \
QL 9:ca2e6010d9e2 3329 QS_CRIT_STAT_ \
QL 9:ca2e6010d9e2 3330 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3331 QP_ QS::begin(static_cast<uint8_t>(QP_ QS_SIG_DIC)); \
QL 9:ca2e6010d9e2 3332 QS_SIG_(sig_); \
QL 9:ca2e6010d9e2 3333 QS_OBJ_(obj_); \
QL 9:ca2e6010d9e2 3334 QS_STR_ROM_(&sig_name_[0]); \
QL 9:ca2e6010d9e2 3335 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3336 QS_CRIT_EXIT_(); \
QL 9:ca2e6010d9e2 3337 QP_ QS::onFlush(); \
QL 9:ca2e6010d9e2 3338 } \
QL 9:ca2e6010d9e2 3339 } while (false)
QL 9:ca2e6010d9e2 3340
QL 9:ca2e6010d9e2 3341 /// \brief Output object dictionary record
QL 9:ca2e6010d9e2 3342 ///
QL 9:ca2e6010d9e2 3343 /// An object dictionary record associates the binary address of an object
QL 9:ca2e6010d9e2 3344 /// in the target's memory with the human-readable name of the object.
QL 9:ca2e6010d9e2 3345 ///
QL 9:ca2e6010d9e2 3346 /// Providing an object dictionary QS record can vastly improve readability of
QL 9:ca2e6010d9e2 3347 /// the QS log, because instead of dealing with cryptic machine addresses the
QL 9:ca2e6010d9e2 3348 /// QSpy host utility can display human-readable object names.
QL 9:ca2e6010d9e2 3349 ///
QL 9:ca2e6010d9e2 3350 /// The following example shows the definition of object dictionary entry
QL 9:ca2e6010d9e2 3351 /// for the Table active object:
QL 9:ca2e6010d9e2 3352 /// \include qs_objDic.cpp
QL 9:ca2e6010d9e2 3353 #define QS_OBJ_DICTIONARY(obj_) do { \
QL 9:ca2e6010d9e2 3354 if (QS_GLB_FILTER_(QP_ QS_OBJ_DIC)) { \
QL 9:ca2e6010d9e2 3355 static char_t const Q_ROM Q_ROM_VAR obj_name_[] = #obj_; \
QL 9:ca2e6010d9e2 3356 QS_CRIT_STAT_ \
QL 9:ca2e6010d9e2 3357 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3358 QP_ QS::begin(static_cast<uint8_t>(QP_ QS_OBJ_DIC)); \
QL 9:ca2e6010d9e2 3359 QS_OBJ_(obj_); \
QL 9:ca2e6010d9e2 3360 QS_STR_ROM_(&obj_name_[0]); \
QL 9:ca2e6010d9e2 3361 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3362 QS_CRIT_EXIT_(); \
QL 9:ca2e6010d9e2 3363 QP_ QS::onFlush(); \
QL 9:ca2e6010d9e2 3364 } \
QL 9:ca2e6010d9e2 3365 } while (false)
QL 9:ca2e6010d9e2 3366
QL 9:ca2e6010d9e2 3367 /// \brief Output function dictionary record
QL 9:ca2e6010d9e2 3368 ///
QL 9:ca2e6010d9e2 3369 /// A function dictionary record associates the binary address of a function
QL 9:ca2e6010d9e2 3370 /// in the target's memory with the human-readable name of the function.
QL 9:ca2e6010d9e2 3371 ///
QL 9:ca2e6010d9e2 3372 /// Providing a function dictionary QS record can vastly improve readability
QL 9:ca2e6010d9e2 3373 /// of the QS log, because instead of dealing with cryptic machine addresses
QL 9:ca2e6010d9e2 3374 /// the QSpy host utility can display human-readable function names.
QL 9:ca2e6010d9e2 3375 ///
QL 9:ca2e6010d9e2 3376 /// The example from #QS_SIG_DICTIONARY shows the definition of a function
QL 9:ca2e6010d9e2 3377 /// dictionary.
QL 9:ca2e6010d9e2 3378 #define QS_FUN_DICTIONARY(fun_) do { \
QL 9:ca2e6010d9e2 3379 if (QS_GLB_FILTER_(QP_ QS_FUN_DIC)) { \
QL 9:ca2e6010d9e2 3380 static char_t const Q_ROM Q_ROM_VAR fun_name_[] = #fun_; \
QL 9:ca2e6010d9e2 3381 QS_CRIT_STAT_ \
QL 9:ca2e6010d9e2 3382 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3383 QP_ QS::begin(static_cast<uint8_t>(QP_ QS_FUN_DIC)); \
QL 9:ca2e6010d9e2 3384 QS_FUN_(fun_); \
QL 9:ca2e6010d9e2 3385 QS_STR_ROM_(&fun_name_[0]); \
QL 9:ca2e6010d9e2 3386 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3387 QS_CRIT_EXIT_(); \
QL 9:ca2e6010d9e2 3388 QP_ QS::onFlush(); \
QL 9:ca2e6010d9e2 3389 } \
QL 9:ca2e6010d9e2 3390 } while (false)
QL 9:ca2e6010d9e2 3391
QL 9:ca2e6010d9e2 3392 /// \brief Output user QS rectord dictionary record
QL 9:ca2e6010d9e2 3393 ///
QL 9:ca2e6010d9e2 3394 /// A user QS record dictionary record associates the numerical value of a
QL 9:ca2e6010d9e2 3395 /// user record with the human-readable identifier.
QL 9:ca2e6010d9e2 3396 #define QS_USR_DICTIONARY(rec_) do { \
QL 9:ca2e6010d9e2 3397 if (QS_GLB_FILTER_(QP_ QS_USR_DIC)) { \
QL 9:ca2e6010d9e2 3398 static char_t const Q_ROM Q_ROM_VAR usr_name_[] = #rec_; \
QL 9:ca2e6010d9e2 3399 QS_CRIT_STAT_ \
QL 9:ca2e6010d9e2 3400 QS_CRIT_ENTRY_(); \
QL 9:ca2e6010d9e2 3401 QP_ QS::begin(static_cast<uint8_t>(QP_ QS_USR_DIC)); \
QL 9:ca2e6010d9e2 3402 QS_U8_(static_cast<uint8_t>(rec_)); \
QL 9:ca2e6010d9e2 3403 QS_STR_ROM_(&usr_name_[0]); \
QL 9:ca2e6010d9e2 3404 QP_ QS::end(); \
QL 9:ca2e6010d9e2 3405 QS_CRIT_EXIT_(); \
QL 9:ca2e6010d9e2 3406 QP_ QS::onFlush(); \
QL 9:ca2e6010d9e2 3407 } \
QL 9:ca2e6010d9e2 3408 } while (false)
QL 9:ca2e6010d9e2 3409
QL 9:ca2e6010d9e2 3410 /// \brief Output the assertion violation
QL 9:ca2e6010d9e2 3411 #define QS_ASSERTION(module_, loc_) do { \
QL 9:ca2e6010d9e2 3412 QS_BEGIN_NOCRIT_(QP_ QS_ASSERT, \
QL 9:ca2e6010d9e2 3413 static_cast<void *>(0), static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3414 QS_TIME_(); \
QL 9:ca2e6010d9e2 3415 QS_U16_(static_cast<uint16_t>(loc_)); \
QL 9:ca2e6010d9e2 3416 QS_STR_ROM_(module_); \
QL 9:ca2e6010d9e2 3417 QS_END_NOCRIT_() \
QL 9:ca2e6010d9e2 3418 QP_ QS::onFlush(); \
QL 9:ca2e6010d9e2 3419 } while (false)
QL 9:ca2e6010d9e2 3420
QL 9:ca2e6010d9e2 3421 /// \brief Flush the QS trace data to the host
QL 9:ca2e6010d9e2 3422 ///
QL 9:ca2e6010d9e2 3423 /// This macro invokes the QS::flush() platform-dependent callback function
QL 9:ca2e6010d9e2 3424 /// to flush the QS trace buffer to the host. The function typically
QL 9:ca2e6010d9e2 3425 /// busy-waits until all the data in the buffer is sent to the host.
QL 9:ca2e6010d9e2 3426 /// This is acceptable only in the initial transient.
QL 9:ca2e6010d9e2 3427 #define QS_FLUSH() (QP_ QS::onFlush())
QL 9:ca2e6010d9e2 3428
QL 9:ca2e6010d9e2 3429 /// \brief Output the critical section entry record
QL 9:ca2e6010d9e2 3430 #define QF_QS_CRIT_ENTRY() \
QL 9:ca2e6010d9e2 3431 QS_BEGIN_NOCRIT_(QP_ QS_QF_CRIT_ENTRY, \
QL 9:ca2e6010d9e2 3432 static_cast<void *>(0), static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3433 QS_TIME_(); \
QL 9:ca2e6010d9e2 3434 QS_U8_((uint8_t)(++QF_critNest_)); \
QL 9:ca2e6010d9e2 3435 QS_END_NOCRIT_()
QL 9:ca2e6010d9e2 3436
QL 9:ca2e6010d9e2 3437 /// \brief Output the critical section exit record
QL 9:ca2e6010d9e2 3438 #define QF_QS_CRIT_EXIT() \
QL 9:ca2e6010d9e2 3439 QS_BEGIN_NOCRIT_(QP_ QS_QF_CRIT_EXIT, \
QL 9:ca2e6010d9e2 3440 static_cast<void *>(0), static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3441 QS_TIME_(); \
QL 9:ca2e6010d9e2 3442 QS_U8_((uint8_t)(QF_critNest_--)); \
QL 9:ca2e6010d9e2 3443 QS_END_NOCRIT_()
QL 9:ca2e6010d9e2 3444
QL 9:ca2e6010d9e2 3445 /// \brief Output the interrupt entry record
QL 9:ca2e6010d9e2 3446 #define QF_QS_ISR_ENTRY(isrnest_, prio_) \
QL 9:ca2e6010d9e2 3447 QS_BEGIN_NOCRIT_(QP_ QS_QF_ISR_ENTRY, \
QL 9:ca2e6010d9e2 3448 static_cast<void *>(0), static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3449 QS_TIME_(); \
QL 9:ca2e6010d9e2 3450 QS_U8_(isrnest_); \
QL 9:ca2e6010d9e2 3451 QS_U8_(prio_); \
QL 9:ca2e6010d9e2 3452 QS_END_NOCRIT_()
QL 9:ca2e6010d9e2 3453
QL 9:ca2e6010d9e2 3454 /// \brief Output the interrupt exit record
QL 9:ca2e6010d9e2 3455 #define QF_QS_ISR_EXIT(isrnest_, prio_) \
QL 9:ca2e6010d9e2 3456 QS_BEGIN_NOCRIT_(QP_ QS_QF_ISR_EXIT, \
QL 9:ca2e6010d9e2 3457 static_cast<void *>(0), static_cast<void *>(0)) \
QL 9:ca2e6010d9e2 3458 QS_TIME_(); \
QL 9:ca2e6010d9e2 3459 QS_U8_(isrnest_); \
QL 9:ca2e6010d9e2 3460 QS_U8_(prio_); \
QL 9:ca2e6010d9e2 3461 QS_END_NOCRIT_()
QL 9:ca2e6010d9e2 3462
QL 9:ca2e6010d9e2 3463 /// \brief Execute an action that is only necessary for QS output
QL 9:ca2e6010d9e2 3464 #define QF_QS_ACTION(act_) (act_)
QL 9:ca2e6010d9e2 3465
QL 9:ca2e6010d9e2 3466 #else // Q_SPY
QL 9:ca2e6010d9e2 3467
QL 9:ca2e6010d9e2 3468 // qs_dummy.h ================================================================
QL 9:ca2e6010d9e2 3469 /// \brief Dummy definitions of the QS macros that avoid code generation from
QL 9:ca2e6010d9e2 3470 /// the QS instrumentation.
QL 9:ca2e6010d9e2 3471
QL 9:ca2e6010d9e2 3472 #define QS_INIT(arg_) (true)
QL 9:ca2e6010d9e2 3473 #define QS_EXIT() ((void)0)
QL 9:ca2e6010d9e2 3474 #define QS_DUMP() ((void)0)
QL 9:ca2e6010d9e2 3475 #define QS_RESET() ((void)0)
QL 9:ca2e6010d9e2 3476 #define QS_FILTER_ON(rec_) ((void)0)
QL 9:ca2e6010d9e2 3477 #define QS_FILTER_OFF(rec_) ((void)0)
QL 9:ca2e6010d9e2 3478 #define QS_FILTER_SM_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3479 #define QS_FILTER_AO_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3480 #define QS_FILTER_MP_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3481 #define QS_FILTER_EQ_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3482 #define QS_FILTER_TE_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3483 #define QS_FILTER_AP_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3484
QL 9:ca2e6010d9e2 3485 #define QS_GET_BYTE(pByte_) (static_cast<uint16_t>(0xFFFFU))
QL 9:ca2e6010d9e2 3486 #define QS_GET_BLOCK(pSize_) (static_cast<uint8_t *>(0))
QL 9:ca2e6010d9e2 3487
QL 9:ca2e6010d9e2 3488 #define QS_BEGIN(rec_, obj_) if (false) {
QL 9:ca2e6010d9e2 3489 #define QS_END() }
QL 9:ca2e6010d9e2 3490 #define QS_BEGIN_NOCRIT(rec_, obj_) if (false) {
QL 9:ca2e6010d9e2 3491 #define QS_END_NOCRIT() }
QL 9:ca2e6010d9e2 3492
QL 9:ca2e6010d9e2 3493 #define QS_I8(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3494 #define QS_U8(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3495 #define QS_I16(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3496 #define QS_U16(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3497 #define QS_I32(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3498 #define QS_U32(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3499 #define QS_F32(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3500 #define QS_F64(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3501 #define QS_U64(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3502 #define QS_STR(str_) ((void)0)
QL 9:ca2e6010d9e2 3503 #define QS_U32_HEX(width_, data_) ((void)0)
QL 9:ca2e6010d9e2 3504 #define QS_STR_ROM(str_) ((void)0)
QL 9:ca2e6010d9e2 3505 #define QS_MEM(mem_, size_) ((void)0)
QL 9:ca2e6010d9e2 3506 #define QS_SIG(sig_, obj_) ((void)0)
QL 9:ca2e6010d9e2 3507 #define QS_OBJ(obj_) ((void)0)
QL 9:ca2e6010d9e2 3508 #define QS_FUN(fun_) ((void)0)
QL 9:ca2e6010d9e2 3509
QL 9:ca2e6010d9e2 3510 #define QS_SIG_DICTIONARY(sig_, obj_) ((void)0)
QL 9:ca2e6010d9e2 3511 #define QS_OBJ_DICTIONARY(obj_) ((void)0)
QL 9:ca2e6010d9e2 3512 #define QS_FUN_DICTIONARY(fun_) ((void)0)
QL 9:ca2e6010d9e2 3513 #define QS_USR_DICTIONARY(rec_) ((void)0)
QL 9:ca2e6010d9e2 3514 #define QS_ASSERTION(module_, loc_) ((void)0)
QL 9:ca2e6010d9e2 3515 #define QS_FLUSH() ((void)0)
QL 9:ca2e6010d9e2 3516
QL 9:ca2e6010d9e2 3517 // internal QS macros used only in the QP components .........................
QL 9:ca2e6010d9e2 3518 #define QS_CRIT_STAT_
QL 9:ca2e6010d9e2 3519 #define QS_BEGIN_(rec_, refObj_, obj_) if (false) {
QL 9:ca2e6010d9e2 3520 #define QS_END_() }
QL 9:ca2e6010d9e2 3521 #define QS_BEGIN_NOCRIT_(rec_, refObj_, obj_) if (false) {
QL 9:ca2e6010d9e2 3522 #define QS_END_NOCRIT_() }
QL 9:ca2e6010d9e2 3523 #define QS_U8_(data_) ((void)0)
QL 9:ca2e6010d9e2 3524 #define QS_U16_(data_) ((void)0)
QL 9:ca2e6010d9e2 3525 #define QS_U32_(data_) ((void)0)
QL 9:ca2e6010d9e2 3526 #define QS_U64_(data_) ((void)0)
QL 9:ca2e6010d9e2 3527 #define QS_TIME_() ((void)0)
QL 9:ca2e6010d9e2 3528 #define QS_SIG_(sig_) ((void)0)
QL 9:ca2e6010d9e2 3529 #define QS_EVS_(size_) ((void)0)
QL 9:ca2e6010d9e2 3530 #define QS_OBJ_(obj_) ((void)0)
QL 9:ca2e6010d9e2 3531 #define QS_FUN_(fun_) ((void)0)
QL 9:ca2e6010d9e2 3532 #define QS_EQC_(ctr_) ((void)0)
QL 9:ca2e6010d9e2 3533 #define QS_MPC_(ctr_) ((void)0)
QL 9:ca2e6010d9e2 3534 #define QS_MPS_(size_) ((void)0)
QL 9:ca2e6010d9e2 3535 #define QS_TEC_(ctr_) ((void)0)
QL 9:ca2e6010d9e2 3536
QL 9:ca2e6010d9e2 3537 #define QF_QS_CRIT_ENTRY() ((void)0)
QL 9:ca2e6010d9e2 3538 #define QF_QS_CRIT_EXIT() ((void)0)
QL 9:ca2e6010d9e2 3539 #define QF_QS_ISR_ENTRY(isrnest_, prio_) ((void)0)
QL 9:ca2e6010d9e2 3540 #define QF_QS_ISR_EXIT(isrnest_, prio_) ((void)0)
QL 9:ca2e6010d9e2 3541 #define QF_QS_ACTION(act_) ((void)0)
QL 9:ca2e6010d9e2 3542
QL 9:ca2e6010d9e2 3543 #endif // Q_SPY
QL 9:ca2e6010d9e2 3544
QL 9:ca2e6010d9e2 3545 // qassert.h =================================================================
QL 9:ca2e6010d9e2 3546 /* \brief Customizable QP assertions.
QL 9:ca2e6010d9e2 3547 *
QL 9:ca2e6010d9e2 3548 * Defines customizable and memory-efficient assertions applicable to
QL 9:ca2e6010d9e2 3549 * embedded systems. This header file can be used in C, C++, and mixed C/C++
QL 9:ca2e6010d9e2 3550 * programs.
QL 9:ca2e6010d9e2 3551 *
QL 9:ca2e6010d9e2 3552 * \note The preprocessor switch Q_NASSERT disables checking assertions.
QL 9:ca2e6010d9e2 3553 * In particular macros #Q_ASSERT, #Q_REQUIRE, #Q_ENSURE, #Q_INVARIANT,
QL 9:ca2e6010d9e2 3554 * #Q_ERROR as well as #Q_ASSERT_ID, #Q_REQUIRE_ID, #Q_ENSURE_ID,
QL 9:ca2e6010d9e2 3555 * #Q_INVARIANT_ID, and #Q_ERROR_ID do NOT evaluate the test condition
QL 9:ca2e6010d9e2 3556 * passed as the argument to these macros. One notable exception is the
QL 9:ca2e6010d9e2 3557 * macro #Q_ALLEGE, that still evaluates the test condition, but does
QL 9:ca2e6010d9e2 3558 * not report assertion failures when the switch Q_NASSERT is defined.
QL 9:ca2e6010d9e2 3559 */
QL 9:ca2e6010d9e2 3560 #ifdef Q_NASSERT /* Q_NASSERT defined--assertion checking disabled */
QL 9:ca2e6010d9e2 3561
QL 9:ca2e6010d9e2 3562 #define Q_DEFINE_THIS_FILE
QL 9:ca2e6010d9e2 3563 #define Q_DEFINE_THIS_MODULE(name_)
QL 9:ca2e6010d9e2 3564 #define Q_ASSERT(test_) ((void)0)
QL 9:ca2e6010d9e2 3565 #define Q_ASSERT_ID(id_, test_) ((void)0)
QL 9:ca2e6010d9e2 3566 #define Q_ALLEGE(test_) ((void)(test_))
QL 9:ca2e6010d9e2 3567 #define Q_ALLEGE_ID(id_, test_) ((void)(test_))
QL 9:ca2e6010d9e2 3568 #define Q_ERROR() ((void)0)
QL 9:ca2e6010d9e2 3569 #define Q_ERROR_ID(id_) ((void)0)
QL 9:ca2e6010d9e2 3570
QL 9:ca2e6010d9e2 3571 #else /* Q_NASSERT not defined--assertion checking enabled */
QL 9:ca2e6010d9e2 3572
QL 9:ca2e6010d9e2 3573 #ifdef __cplusplus
QL 9:ca2e6010d9e2 3574 extern "C" {
QL 9:ca2e6010d9e2 3575 #endif
QL 9:ca2e6010d9e2 3576
QL 9:ca2e6010d9e2 3577 /** \brief Type for line numbers.
QL 9:ca2e6010d9e2 3578 *
QL 9:ca2e6010d9e2 3579 * This typedef specifies strong type for line numbers. The use of this
QL 9:ca2e6010d9e2 3580 * type, rather than plain 'int', is in compliance with the MISRA-C 2004
QL 9:ca2e6010d9e2 3581 * Rule 6.3(adv).
QL 9:ca2e6010d9e2 3582 */
QL 9:ca2e6010d9e2 3583 typedef int int_t;
QL 9:ca2e6010d9e2 3584
QL 9:ca2e6010d9e2 3585 /** callback invoked in case the condition passed to #Q_ASSERT,
QL 9:ca2e6010d9e2 3586 * #Q_REQUIRE, #Q_ENSURE, #Q_ERROR, #Q_ALLEGE as well as #Q_ASSERT_ID,
QL 9:ca2e6010d9e2 3587 * #Q_REQUIRE_ID, #Q_ENSURE_ID, #Q_ERROR_ID, and #Q_ALLEGE_ID evaluates
QL 9:ca2e6010d9e2 3588 * to FALSE.
QL 9:ca2e6010d9e2 3589 *
QL 9:ca2e6010d9e2 3590 * \param file name where the assertion failed
QL 9:ca2e6010d9e2 3591 * \param line number at which the assertion failed
QL 9:ca2e6010d9e2 3592 */
QL 9:ca2e6010d9e2 3593 void Q_onAssert(char_t const Q_ROM * const Q_ROM_VAR file,
QL 9:ca2e6010d9e2 3594 int_t const line);
QL 9:ca2e6010d9e2 3595
QL 9:ca2e6010d9e2 3596 #ifdef __cplusplus
QL 9:ca2e6010d9e2 3597 }
QL 9:ca2e6010d9e2 3598 #endif
QL 9:ca2e6010d9e2 3599
QL 9:ca2e6010d9e2 3600 /** Place this macro at the top of each C/C++ module to define the file
QL 9:ca2e6010d9e2 3601 * name string using __FILE__ (NOTE: __FILE__ might contain lengthy path
QL 9:ca2e6010d9e2 3602 * name). This file name will be used in reporting assertions in this file.
QL 9:ca2e6010d9e2 3603 */
QL 9:ca2e6010d9e2 3604 #define Q_DEFINE_THIS_FILE \
QL 9:ca2e6010d9e2 3605 static char_t const Q_ROM Q_ROM_VAR l_this_file[] = __FILE__;
QL 9:ca2e6010d9e2 3606
QL 9:ca2e6010d9e2 3607 /** Place this macro at the top of each C/C++ module to define the module
QL 9:ca2e6010d9e2 3608 * name as the argument \a name_. This file name will be used in reporting
QL 9:ca2e6010d9e2 3609 * assertions in this file.
QL 9:ca2e6010d9e2 3610 */
QL 9:ca2e6010d9e2 3611 #define Q_DEFINE_THIS_MODULE(name_) \
QL 9:ca2e6010d9e2 3612 static char_t const Q_ROM Q_ROM_VAR l_this_file[] = name_;
QL 9:ca2e6010d9e2 3613
QL 9:ca2e6010d9e2 3614 /** General purpose assertion that makes sure the \a test_ argument is
QL 9:ca2e6010d9e2 3615 * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates
QL 9:ca2e6010d9e2 3616 * to FALSE.
QL 9:ca2e6010d9e2 3617 * \note the \a test_ is NOT evaluated if assertions are disabled with
QL 9:ca2e6010d9e2 3618 * the Q_NASSERT switch.
QL 9:ca2e6010d9e2 3619 * \sa #Q_ASSERT_ID
QL 9:ca2e6010d9e2 3620 */
QL 9:ca2e6010d9e2 3621 #define Q_ASSERT(test_) \
QL 9:ca2e6010d9e2 3622 ((test_) ? (void)0 : Q_onAssert(&l_this_file[0], (int_t)__LINE__))
QL 9:ca2e6010d9e2 3623
QL 9:ca2e6010d9e2 3624 /** General purpose assertion that makes sure the \a test_ argument is
QL 9:ca2e6010d9e2 3625 * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates
QL 9:ca2e6010d9e2 3626 * to FALSE. The argument \a id_ is the ID number (unique within
QL 9:ca2e6010d9e2 3627 * the file) of the assertion. This assertion style is better suited
QL 9:ca2e6010d9e2 3628 * for unit testig, because it avoids the volatility of line numbers
QL 9:ca2e6010d9e2 3629 * for indentifying assertions.
QL 9:ca2e6010d9e2 3630 * \note the \a test_ is NOT evaluated if assertions are disabled with
QL 9:ca2e6010d9e2 3631 * the Q_NASSERT switch.
QL 9:ca2e6010d9e2 3632 * \sa #Q_ASSERT
QL 9:ca2e6010d9e2 3633 */
QL 9:ca2e6010d9e2 3634 #define Q_ASSERT_ID(id_, test_) \
QL 9:ca2e6010d9e2 3635 ((test_) ? (void)0 : Q_onAssert(&l_this_file[0], (int_t)(id_))
QL 9:ca2e6010d9e2 3636
QL 9:ca2e6010d9e2 3637 /** General purpose assertion that ALWAYS evaluates the \a test_
QL 9:ca2e6010d9e2 3638 * argument and calls the Q_onAssert() callback if the \a test_
QL 9:ca2e6010d9e2 3639 * evaluates to FALSE.
QL 9:ca2e6010d9e2 3640 * \note the \a test_ argument IS always evaluated even when assertions
QL 9:ca2e6010d9e2 3641 * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is
QL 9:ca2e6010d9e2 3642 * defined, the Q_onAssert() callback is NOT called, even if the
QL 9:ca2e6010d9e2 3643 * \a test_ evaluates to FALSE.
QL 9:ca2e6010d9e2 3644 * \sa #Q_ALLEGE_ID
QL 9:ca2e6010d9e2 3645 */
QL 9:ca2e6010d9e2 3646 #define Q_ALLEGE(test_) Q_ASSERT(test_)
QL 9:ca2e6010d9e2 3647
QL 9:ca2e6010d9e2 3648 /** General purpose assertion that ALWAYS evaluates the \a test_
QL 9:ca2e6010d9e2 3649 * argument and calls the Q_onAssert() callback if the \a test_
QL 9:ca2e6010d9e2 3650 * evaluates to FALSE. This assertion style is better suited
QL 9:ca2e6010d9e2 3651 * for unit testig, because it avoids the volatility of line numbers
QL 9:ca2e6010d9e2 3652 * for indentifying assertions.
QL 9:ca2e6010d9e2 3653 * \note the \a test_ argument IS always evaluated even when assertions
QL 9:ca2e6010d9e2 3654 * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is
QL 9:ca2e6010d9e2 3655 * defined, the Q_onAssert() callback is NOT called, even if the
QL 9:ca2e6010d9e2 3656 * \a test_ evaluates to FALSE.
QL 9:ca2e6010d9e2 3657 * \sa #Q_ALLEGE
QL 9:ca2e6010d9e2 3658 */
QL 9:ca2e6010d9e2 3659 #define Q_ALLEGE_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 9:ca2e6010d9e2 3660
QL 9:ca2e6010d9e2 3661 /** Assertion that always calls the Q_onAssert() callback if
QL 9:ca2e6010d9e2 3662 * ever executed.
QL 9:ca2e6010d9e2 3663 * \note can be disabled with the Q_NASSERT switch.
QL 9:ca2e6010d9e2 3664 * \sa #Q_ERROR_ID
QL 9:ca2e6010d9e2 3665 */
QL 9:ca2e6010d9e2 3666 #define Q_ERROR() \
QL 9:ca2e6010d9e2 3667 Q_onAssert(&l_this_file[0], (int_t)__LINE__)
QL 9:ca2e6010d9e2 3668
QL 9:ca2e6010d9e2 3669 /** Assertion that always calls the Q_onAssert() callback if
QL 9:ca2e6010d9e2 3670 * ever executed. This assertion style is better suited for unit
QL 9:ca2e6010d9e2 3671 * testig, because it avoids the volatility of line numbers for
QL 9:ca2e6010d9e2 3672 * indentifying assertions.
QL 9:ca2e6010d9e2 3673 * \note can be disabled with the Q_NASSERT switch.
QL 9:ca2e6010d9e2 3674 * \sa #Q_ERROR
QL 9:ca2e6010d9e2 3675 */
QL 9:ca2e6010d9e2 3676 #define Q_ERROR_ID(id_) \
QL 9:ca2e6010d9e2 3677 Q_onAssert(l_this_file, (int_t)(id_))
QL 9:ca2e6010d9e2 3678
QL 9:ca2e6010d9e2 3679 #endif /* Q_NASSERT */
QL 9:ca2e6010d9e2 3680
QL 9:ca2e6010d9e2 3681 /** Assertion that checks for a precondition. This macro is equivalent to
QL 9:ca2e6010d9e2 3682 * #Q_ASSERT, except the name provides a better documentation of the
QL 9:ca2e6010d9e2 3683 * intention of this assertion.
QL 9:ca2e6010d9e2 3684 * \sa #Q_REQUIRE_ID
QL 9:ca2e6010d9e2 3685 */
QL 9:ca2e6010d9e2 3686 #define Q_REQUIRE(test_) Q_ASSERT(test_)
QL 9:ca2e6010d9e2 3687
QL 9:ca2e6010d9e2 3688 /** Assertion that checks for a precondition. This macro is equivalent to
QL 9:ca2e6010d9e2 3689 * #Q_ASSERT_ID, except the name provides a better documentation of the
QL 9:ca2e6010d9e2 3690 * intention of this assertion.
QL 9:ca2e6010d9e2 3691 * \sa #Q_REQUIRE
QL 9:ca2e6010d9e2 3692 */
QL 9:ca2e6010d9e2 3693 #define Q_REQUIRE_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 9:ca2e6010d9e2 3694
QL 9:ca2e6010d9e2 3695 /** Assertion that checks for a postcondition. This macro is equivalent to
QL 9:ca2e6010d9e2 3696 * #Q_ASSERT, except the name provides a better documentation of the
QL 9:ca2e6010d9e2 3697 * intention of this assertion.
QL 9:ca2e6010d9e2 3698 * \sa #Q_ENSURE_ID
QL 9:ca2e6010d9e2 3699 */
QL 9:ca2e6010d9e2 3700 #define Q_ENSURE(test_) Q_ASSERT(test_)
QL 9:ca2e6010d9e2 3701
QL 9:ca2e6010d9e2 3702 /** Assertion that checks for a postcondition. This macro is equivalent to
QL 9:ca2e6010d9e2 3703 * #Q_ASSERT_ID, except the name provides a better documentation of the
QL 9:ca2e6010d9e2 3704 * intention of this assertion.
QL 9:ca2e6010d9e2 3705 * \sa #Q_ENSURE
QL 9:ca2e6010d9e2 3706 */
QL 9:ca2e6010d9e2 3707 #define Q_ENSURE_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 9:ca2e6010d9e2 3708
QL 9:ca2e6010d9e2 3709 /** Assertion that checks for an invariant. This macro is equivalent to
QL 9:ca2e6010d9e2 3710 * #Q_ASSERT, except the name provides a better documentation of the
QL 9:ca2e6010d9e2 3711 * intention of this assertion.
QL 9:ca2e6010d9e2 3712 * \sa #Q_INVARIANT_ID
QL 9:ca2e6010d9e2 3713 */
QL 9:ca2e6010d9e2 3714 #define Q_INVARIANT(test_) Q_ASSERT(test_)
QL 9:ca2e6010d9e2 3715
QL 9:ca2e6010d9e2 3716 /** Assertion that checks for an invariant. This macro is equivalent to
QL 9:ca2e6010d9e2 3717 * #Q_ASSERT_ID, except the name provides a better documentation of the
QL 9:ca2e6010d9e2 3718 * intention of this assertion.
QL 9:ca2e6010d9e2 3719 * \sa #Q_INVARIANT
QL 9:ca2e6010d9e2 3720 */
QL 9:ca2e6010d9e2 3721 #define Q_INVARIANT_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 9:ca2e6010d9e2 3722
QL 9:ca2e6010d9e2 3723 /** Compile-time assertion exploits the fact that in C/C++ a dimension of
QL 9:ca2e6010d9e2 3724 * an array cannot be negative. The following declaration causes a compilation
QL 9:ca2e6010d9e2 3725 * error if the compile-time expression (\a test_) is not TRUE. The assertion
QL 9:ca2e6010d9e2 3726 * has no runtime side effects.
QL 9:ca2e6010d9e2 3727 */
QL 9:ca2e6010d9e2 3728 #define Q_ASSERT_COMPILE(test_) \
QL 9:ca2e6010d9e2 3729 extern int_t Q_assert_compile[(test_) ? 1 : -1]
QL 9:ca2e6010d9e2 3730
QL 9:ca2e6010d9e2 3731 #endif // qp_h