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