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