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

Dependents:   qp_hangman qp_dpp qp_blinky

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

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

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

Committer:
QL
Date:
Mon Sep 26 01:42:32 2011 +0000
Revision:
6:01d57c81e96a
Parent:
5:949864ba515c
Child:
7:bf92d3a6625e
4.2.04

Who changed what in which revision?

UserRevisionLine numberNew 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 0:064c79e7311a 901 extern uint8_t volatile QK_currPrio_; ///< current task/interrupt priority
QL 0:064c79e7311a 902 extern uint8_t volatile QK_intNest_; ///< interrupt nesting level
QL 0:064c79e7311a 903
QL 0:064c79e7311a 904 // QK active object queue implementation .....................................
QL 0:064c79e7311a 905
QL 0:064c79e7311a 906 /// \brief Platform-dependent macro defining how QF should block the calling
QL 0:064c79e7311a 907 /// task when the QF native queue is empty
QL 0:064c79e7311a 908 ///
QL 0:064c79e7311a 909 /// \note This is just an example of #QACTIVE_EQUEUE_WAIT_ for the QK-port
QL 0:064c79e7311a 910 /// of QF. QK never activates a task that has no events to process, so in this
QL 0:064c79e7311a 911 /// case the macro asserts that the queue is not empty. In other QF ports you
QL 0:064c79e7311a 912 // need to define the macro appropriately for the underlying kernel/OS you're
QL 0:064c79e7311a 913 /// using.
QL 0:064c79e7311a 914 #define QACTIVE_EQUEUE_WAIT_(me_) \
QL 0:064c79e7311a 915 Q_ASSERT((me_)->m_eQueue.m_frontEvt != (QEvent *)0)
QL 0:064c79e7311a 916
QL 0:064c79e7311a 917 /// \brief Platform-dependent macro defining how QF should signal the
QL 0:064c79e7311a 918 /// active object task that an event has just arrived.
QL 0:064c79e7311a 919 ///
QL 0:064c79e7311a 920 /// The macro is necessary only when the native QF event queue is used.
QL 0:064c79e7311a 921 /// The signaling of task involves unblocking the task if it is blocked.
QL 0:064c79e7311a 922 ///
QL 0:064c79e7311a 923 /// \note #QACTIVE_EQUEUE_SIGNAL_ is called from a critical section.
QL 0:064c79e7311a 924 /// It might leave the critical section internally, but must restore
QL 0:064c79e7311a 925 /// the critical section before exiting to the caller.
QL 0:064c79e7311a 926 ///
QL 0:064c79e7311a 927 /// \note This is just an example of #QACTIVE_EQUEUE_SIGNAL_ for the QK-port
QL 0:064c79e7311a 928 /// of QF. In other QF ports you need to define the macro appropriately for
QL 0:064c79e7311a 929 /// the underlying kernel/OS you're using.
QL 0:064c79e7311a 930 #define QACTIVE_EQUEUE_SIGNAL_(me_) \
QL 0:064c79e7311a 931 QK_readySet_.insert((me_)->m_prio); \
QL 0:064c79e7311a 932 if (QK_intNest_ == (uint8_t)0) { \
QL 0:064c79e7311a 933 QK_SCHEDULE_(); \
QL 0:064c79e7311a 934 } else ((void)0)
QL 0:064c79e7311a 935
QL 0:064c79e7311a 936 /// \brief Platform-dependent macro defining the action QF should take
QL 0:064c79e7311a 937 /// when the native QF event queue becomes empty.
QL 0:064c79e7311a 938 ///
QL 0:064c79e7311a 939 /// \note #QACTIVE_EQUEUE_ONEMPTY_ is called from a critical section.
QL 0:064c79e7311a 940 /// It should not leave the critical section.
QL 0:064c79e7311a 941 ///
QL 0:064c79e7311a 942 /// \note This is just an example of #QACTIVE_EQUEUE_ONEMPTY_ for the QK-port
QL 0:064c79e7311a 943 /// of QF. In other QF ports you need to define the macro appropriately for
QL 0:064c79e7311a 944 /// the underlying kernel/OS you're using.
QL 0:064c79e7311a 945 #define QACTIVE_EQUEUE_ONEMPTY_(me_) \
QL 0:064c79e7311a 946 QK_readySet_.remove((me_)->m_prio)
QL 0:064c79e7311a 947
QL 0:064c79e7311a 948 // QK event pool operations ..................................................
QL 0:064c79e7311a 949
QL 0:064c79e7311a 950 /// \brief This macro defines the type of the event pool used in this QF port.
QL 0:064c79e7311a 951 ///
QL 0:064c79e7311a 952 /// \note This is just an example of the macro definition. Typically, you need
QL 0:064c79e7311a 953 /// to define it in the specific QF port file (qf_port.h). In case of QK,
QL 0:064c79e7311a 954 /// which always depends on the native QF memory pool, this macro is defined
QL 0:064c79e7311a 955 /// at the level of the platform-independent interface qk.h.
QL 0:064c79e7311a 956 #define QF_EPOOL_TYPE_ QMPool
QL 0:064c79e7311a 957
QL 0:064c79e7311a 958 /// \brief Platform-dependent macro defining the event pool initialization
QL 0:064c79e7311a 959 ///
QL 0:064c79e7311a 960 /// \note This is just an example of #QF_EPOOL_INIT_ for the QK-port of QF.
QL 0:064c79e7311a 961 /// In other QF ports you need to define the macro appropriately for the
QL 0:064c79e7311a 962 /// underlying kernel/OS you're using.
QL 0:064c79e7311a 963 #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
QL 0:064c79e7311a 964 (p_).init(poolSto_, poolSize_, evtSize_)
QL 0:064c79e7311a 965
QL 0:064c79e7311a 966 /// \brief Platform-dependent macro defining how QF should obtain the
QL 0:064c79e7311a 967 /// event pool block-size
QL 0:064c79e7311a 968 ///
QL 0:064c79e7311a 969 /// \note This is just an example of #QF_EPOOL_EVENT_SIZE_ for the QK-port
QL 0:064c79e7311a 970 /// of QF. In other QF ports you need to define the macro appropriately for
QL 0:064c79e7311a 971 /// the underlying kernel/OS you're using.
QL 0:064c79e7311a 972 #define QF_EPOOL_EVENT_SIZE_(p_) ((p_).getBlockSize())
QL 0:064c79e7311a 973
QL 0:064c79e7311a 974 /// \brief Platform-dependent macro defining how QF should obtain an event
QL 0:064c79e7311a 975 /// \a e_ from the event pool \a p_
QL 0:064c79e7311a 976 ///
QL 0:064c79e7311a 977 /// \note This is just an example of #QF_EPOOL_GET_ for the QK-port of QF.
QL 0:064c79e7311a 978 /// In other QF ports you need to define the macro appropriately for the
QL 0:064c79e7311a 979 /// underlying kernel/OS you're using.
QL 0:064c79e7311a 980 #define QF_EPOOL_GET_(p_, e_) ((e_) = (QEvent *)(p_).get())
QL 0:064c79e7311a 981
QL 0:064c79e7311a 982 /// \brief Platform-dependent macro defining how QF should return an event
QL 0:064c79e7311a 983 /// \a e_ to the event pool \a p_
QL 0:064c79e7311a 984 ///
QL 0:064c79e7311a 985 /// \note This is just an example of #QF_EPOOL_PUT_ for the QK-port of QF.
QL 0:064c79e7311a 986 /// In other QF ports you need to define the macro appropriately for the
QL 0:064c79e7311a 987 /// underlying kernel/OS you're using.
QL 0:064c79e7311a 988 #define QF_EPOOL_PUT_(p_, e_) ((p_).put(e_))
QL 0:064c79e7311a 989
QL 0:064c79e7311a 990 #ifndef QK_NO_MUTEX
QL 0:064c79e7311a 991 //////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 992 /// \brief QK Mutex type.
QL 0:064c79e7311a 993 ///
QL 0:064c79e7311a 994 /// QMutex represents the priority-ceiling mutex available in QK.
QL 0:064c79e7311a 995 /// \sa QK::mutexLock()
QL 0:064c79e7311a 996 /// \sa QK::mutexUnlock()
QL 0:064c79e7311a 997 typedef uint8_t QMutex;
QL 0:064c79e7311a 998 #endif // QK_NO_MUTEX
QL 0:064c79e7311a 999
QL 0:064c79e7311a 1000 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1001 /// \brief QK services.
QL 0:064c79e7311a 1002 ///
QL 0:064c79e7311a 1003 /// This class groups together QK services. It has only static members and
QL 0:064c79e7311a 1004 /// should not be instantiated.
QL 0:064c79e7311a 1005 ///
QL 0:064c79e7311a 1006 // \note The QK scheduler, QK priority, QK ready set, etc. belong conceptually
QL 0:064c79e7311a 1007 /// to the QK class (as static class members). However, to avoid C++ potential
QL 0:064c79e7311a 1008 /// name-mangling problems in assembly language, these elements are defined
QL 0:064c79e7311a 1009 /// outside of the QK class and use the extern "C" linkage specification.
QL 0:064c79e7311a 1010 ///
QL 0:064c79e7311a 1011 class QK {
QL 0:064c79e7311a 1012 public:
QL 0:064c79e7311a 1013
QL 0:064c79e7311a 1014 /// \brief get the current QK version number string
QL 0:064c79e7311a 1015 ///
QL 0:064c79e7311a 1016 /// \return version of the QK as a constant 6-character string of the
QL 0:064c79e7311a 1017 /// form x.y.zz, where x is a 1-digit major version number, y is a
QL 0:064c79e7311a 1018 /// 1-digit minor version number, and zz is a 2-digit release number.
QL 0:064c79e7311a 1019 ///
QL 0:064c79e7311a 1020 /// \sa QK::getPortVersion()
QL 0:064c79e7311a 1021 static char const Q_ROM * Q_ROM_VAR getVersion(void);
QL 0:064c79e7311a 1022
QL 0:064c79e7311a 1023 /// \brief Returns the QK-port version.
QL 0:064c79e7311a 1024 ///
QL 0:064c79e7311a 1025 /// This function returns constant version string in the format x.y.zz,
QL 0:064c79e7311a 1026 /// where x (one digit) is the major version, y (one digit) is the minor
QL 0:064c79e7311a 1027 /// version, and zz (two digits) is the maintenance release version.
QL 0:064c79e7311a 1028 /// An example of the QK-port version string is "1.1.03".
QL 0:064c79e7311a 1029 ///
QL 0:064c79e7311a 1030 /// \sa QK::getVersion()
QL 0:064c79e7311a 1031 static char const Q_ROM * Q_ROM_VAR getPortVersion(void);
QL 0:064c79e7311a 1032
QL 0:064c79e7311a 1033 /// \brief QK idle callback (customized in BSPs for QK)
QL 0:064c79e7311a 1034 ///
QL 0:064c79e7311a 1035 /// QK::onIdle() is called continously by the QK idle loop. This callback
QL 0:064c79e7311a 1036 /// gives the application an opportunity to enter a power-saving CPU mode,
QL 0:064c79e7311a 1037 /// or perform some other idle processing.
QL 0:064c79e7311a 1038 ///
QL 0:064c79e7311a 1039 /// \note QK::onIdle() is invoked with interrupts unlocked and must also
QL 0:064c79e7311a 1040 /// return with interrupts unlocked.
QL 0:064c79e7311a 1041 ///
QL 0:064c79e7311a 1042 /// \sa QF::onIdle()
QL 0:064c79e7311a 1043 static void onIdle(void);
QL 0:064c79e7311a 1044
QL 0:064c79e7311a 1045 #ifndef QK_NO_MUTEX
QL 0:064c79e7311a 1046
QL 0:064c79e7311a 1047 /// \brief QK priority-ceiling mutex lock
QL 0:064c79e7311a 1048 ///
QL 0:064c79e7311a 1049 /// Lock the QK scheduler up to the priority level \a prioCeiling.
QL 0:064c79e7311a 1050 ///
QL 0:064c79e7311a 1051 // \note This function should be always paired with QK::mutexUnlock().
QL 0:064c79e7311a 1052 /// The code between QK::mutexLock() and QK::mutexUnlock() should be
QL 0:064c79e7311a 1053 /// kept to the minimum.
QL 0:064c79e7311a 1054 ///
QL 0:064c79e7311a 1055 /// \include qk_mux.cpp
QL 0:064c79e7311a 1056 static QMutex mutexLock(uint8_t prioCeiling);
QL 0:064c79e7311a 1057
QL 0:064c79e7311a 1058 /// \brief QK priority-ceiling mutex unlock
QL 0:064c79e7311a 1059 ///
QL 0:064c79e7311a 1060 /// \note This function should be always paired with QK::mutexLock().
QL 0:064c79e7311a 1061 /// The code between QK::mutexLock() and QK::mutexUnlock() should be
QL 0:064c79e7311a 1062 /// kept to the minimum.
QL 0:064c79e7311a 1063 ///
QL 0:064c79e7311a 1064 /// \include qk_mux.cpp
QL 0:064c79e7311a 1065 static void mutexUnlock(QMutex mutex);
QL 0:064c79e7311a 1066
QL 0:064c79e7311a 1067 #endif // QK_NO_MUTEX
QL 0:064c79e7311a 1068
QL 0:064c79e7311a 1069 };
QL 0:064c79e7311a 1070
QL 0:064c79e7311a 1071 extern "C" {
QL 0:064c79e7311a 1072
QL 0:064c79e7311a 1073 /// \brief QK initialization
QL 0:064c79e7311a 1074 ///
QL 0:064c79e7311a 1075 /// QK_init() is called from QF_init() in qk.cpp. This function is
QL 0:064c79e7311a 1076 /// defined in the QK ports.
QL 0:064c79e7311a 1077 void QK_init(void);
QL 0:064c79e7311a 1078
QL 0:064c79e7311a 1079 // QK scheduler and extended scheduler
QL 0:064c79e7311a 1080 #ifndef QF_INT_KEY_TYPE
QL 0:064c79e7311a 1081 void QK_schedule_(void); // QK scheduler
QL 0:064c79e7311a 1082 void QK_scheduleExt_(void); // QK extended scheduler
QL 0:064c79e7311a 1083
QL 0:064c79e7311a 1084 #define QK_SCHEDULE_() QK_schedule_()
QL 0:064c79e7311a 1085 #else
QL 0:064c79e7311a 1086
QL 0:064c79e7311a 1087 /// \brief The QK scheduler
QL 0:064c79e7311a 1088 ///
QL 0:064c79e7311a 1089 /// \note The QK scheduler must be always called with the interrupts
QL 0:064c79e7311a 1090 /// locked and unlocks interrupts internally.
QL 0:064c79e7311a 1091 ///
QL 0:064c79e7311a 1092 /// The signature of QK_schedule_() depends on the policy of locking and
QL 0:064c79e7311a 1093 /// unlocking interrupts. When the interrupt lock key is not used
QL 0:064c79e7311a 1094 /// (#QF_INT_KEY_TYPE undefined), the signature is as follows: \n
QL 0:064c79e7311a 1095 /// void QK_schedule_(void); \n
QL 0:064c79e7311a 1096 ///
QL 0:064c79e7311a 1097 /// However, when the interrupt key lock is used (#QF_INT_KEY_TYPE
QL 0:064c79e7311a 1098 /// defined), the signature is different: \n
QL 0:064c79e7311a 1099 /// void QK_schedule_(QF_INT_KEY_TYPE intLockKey); \n
QL 0:064c79e7311a 1100 ///
QL 0:064c79e7311a 1101 /// For the internal use, these differences are hidden by the macro
QL 0:064c79e7311a 1102 /// #QK_SCHEDULE_.
QL 0:064c79e7311a 1103 void QK_schedule_(QF_INT_KEY_TYPE intLockKey);
QL 0:064c79e7311a 1104
QL 0:064c79e7311a 1105 /// \brief The QK extended scheduler for interrupt context
QL 0:064c79e7311a 1106 ///
QL 0:064c79e7311a 1107 /// \note The QK extended exscheduler must be always called with the
QL 0:064c79e7311a 1108 /// interrupts locked and unlocks interrupts internally.
QL 0:064c79e7311a 1109 ///
QL 0:064c79e7311a 1110 /// The signature of QK_scheduleExt_() depends on the policy of locking
QL 0:064c79e7311a 1111 /// and unlocking interrupts. When the interrupt lock key is not used
QL 0:064c79e7311a 1112 /// (#QF_INT_KEY_TYPE undefined), the signature is as follows: \n
QL 0:064c79e7311a 1113 /// void QK_scheduleExt_(void); \n
QL 0:064c79e7311a 1114 ///
QL 0:064c79e7311a 1115 /// However, when the interrupt key lock is used (#QF_INT_KEY_TYPE
QL 0:064c79e7311a 1116 /// defined), the signature is different: \n
QL 0:064c79e7311a 1117 /// void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey); \n
QL 0:064c79e7311a 1118 void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey); // QK extended scheduler
QL 0:064c79e7311a 1119
QL 0:064c79e7311a 1120 /// #QF_INT_KEY_TYPE is defined, this internal macro invokes
QL 0:064c79e7311a 1121 /// QK_schedule_() passing the key variable as the parameter. Otherwise
QL 0:064c79e7311a 1122 /// QK_schedule_() is invoked without parameters.
QL 0:064c79e7311a 1123 /// \sa #QK_INT_LOCK, #QK_INT_UNLOCK
QL 0:064c79e7311a 1124 #define QK_SCHEDULE_() QK_schedule_(intLockKey_)
QL 0:064c79e7311a 1125
QL 0:064c79e7311a 1126 #endif
QL 0:064c79e7311a 1127 } // extern "C"
QL 0:064c79e7311a 1128
QL 0:064c79e7311a 1129 #else // QK_PREEMPTIVE
QL 0:064c79e7311a 1130
QL 0:064c79e7311a 1131 // "qvanilla.h" ==============================================================
QL 0:064c79e7311a 1132 #define QF_EQUEUE_TYPE QEQueue
QL 0:064c79e7311a 1133 // native event queue operations
QL 0:064c79e7311a 1134 #define QACTIVE_EQUEUE_WAIT_(me_) \
QL 0:064c79e7311a 1135 Q_ASSERT((me_)->m_eQueue.m_frontEvt != (QEvent *)0)
QL 0:064c79e7311a 1136
QL 0:064c79e7311a 1137 #define QACTIVE_EQUEUE_SIGNAL_(me_) \
QL 0:064c79e7311a 1138 QF_readySet_.insert((me_)->m_prio)
QL 0:064c79e7311a 1139
QL 0:064c79e7311a 1140 #define QACTIVE_EQUEUE_ONEMPTY_(me_) \
QL 0:064c79e7311a 1141 QF_readySet_.remove((me_)->m_prio)
QL 0:064c79e7311a 1142
QL 0:064c79e7311a 1143 // native QF event pool operations
QL 0:064c79e7311a 1144 #define QF_EPOOL_TYPE_ QMPool
QL 0:064c79e7311a 1145 #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
QL 0:064c79e7311a 1146 (p_).init(poolSto_, poolSize_, evtSize_)
QL 0:064c79e7311a 1147 #define QF_EPOOL_EVENT_SIZE_(p_) ((p_).getBlockSize())
QL 0:064c79e7311a 1148 #define QF_EPOOL_GET_(p_, e_) ((e_) = (QEvent *)(p_).get())
QL 0:064c79e7311a 1149 #define QF_EPOOL_PUT_(p_, e_) ((p_).put(e_))
QL 0:064c79e7311a 1150
QL 0:064c79e7311a 1151 #if (QF_MAX_ACTIVE <= 8)
QL 0:064c79e7311a 1152 extern QPSet8 volatile QF_readySet_; ///< QF-ready set of active objects
QL 0:064c79e7311a 1153 #else
QL 0:064c79e7311a 1154 extern QPSet64 volatile QF_readySet_; ///< QF-ready set of active objects
QL 0:064c79e7311a 1155 #endif
QL 0:064c79e7311a 1156
QL 0:064c79e7311a 1157 #endif // QK_PREEMPTIVE
QL 0:064c79e7311a 1158
QL 0:064c79e7311a 1159
QL 0:064c79e7311a 1160 // qf.h (QF platform-independent public interface) ===========================
QL 0:064c79e7311a 1161 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1162 #if (QF_MAX_ACTIVE < 1) || (63 < QF_MAX_ACTIVE)
QL 0:064c79e7311a 1163 #error "QF_MAX_ACTIVE not defined or out of range. Valid range is 1..63"
QL 0:064c79e7311a 1164 #endif
QL 0:064c79e7311a 1165
QL 0:064c79e7311a 1166 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1167 #ifndef QF_EVENT_SIZ_SIZE
QL 0:064c79e7311a 1168
QL 0:064c79e7311a 1169 /// \brief Default value of the macro configurable value in qf_port.h
QL 0:064c79e7311a 1170 #define QF_EVENT_SIZ_SIZE 2
QL 0:064c79e7311a 1171 #endif
QL 0:064c79e7311a 1172 #if (QF_EVENT_SIZ_SIZE == 1)
QL 0:064c79e7311a 1173
QL 0:064c79e7311a 1174 /// \brief The data type to store the block-size defined based on
QL 0:064c79e7311a 1175 /// the macro #QF_EVENT_SIZ_SIZE.
QL 0:064c79e7311a 1176 ///
QL 0:064c79e7311a 1177 /// The dynamic range of this data type determines the maximum block
QL 0:064c79e7311a 1178 /// size that can be managed by the pool.
QL 0:064c79e7311a 1179 typedef uint8_t QEventSize;
QL 0:064c79e7311a 1180 #elif (QF_EVENT_SIZ_SIZE == 2)
QL 0:064c79e7311a 1181 typedef uint16_t QEventSize;
QL 0:064c79e7311a 1182 #elif (QF_EVENT_SIZ_SIZE == 4)
QL 0:064c79e7311a 1183 typedef uint32_t QEventSize;
QL 0:064c79e7311a 1184 #else
QL 0:064c79e7311a 1185 #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
QL 0:064c79e7311a 1186 #endif
QL 0:064c79e7311a 1187
QL 6:01d57c81e96a 1188 //////////////////////////////////////////////////////////////////////////////
QL 6:01d57c81e96a 1189 #ifndef QF_MAX_EPOOL
QL 6:01d57c81e96a 1190 /// \brief Default value of the macro configurable value in qf_port.h
QL 6:01d57c81e96a 1191 #define QF_MAX_EPOOL 3
QL 6:01d57c81e96a 1192 #endif
QL 0:064c79e7311a 1193
QL 0:064c79e7311a 1194 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1195 #ifndef QF_ACTIVE_SUPER_
QL 0:064c79e7311a 1196
QL 0:064c79e7311a 1197 //////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1198 /// \brief The macro defining the base class for QActive.
QL 0:064c79e7311a 1199 ///
QL 0:064c79e7311a 1200 /// By default, the ::QActive class is derived from ::QHsm. However,
QL 0:064c79e7311a 1201 /// if the macro QF_ACTIVE_SUPER_ is defined, QActive is derived from
QL 0:064c79e7311a 1202 /// QF_ACTIVE_SUPER_.
QL 0:064c79e7311a 1203 ///
QL 0:064c79e7311a 1204 /// Clients might choose, for example, to define QF_ACTIVE_SUPER_ as QFsm
QL 0:064c79e7311a 1205 /// to avoid the 1-2KB overhead of the hierarchical event processor.
QL 0:064c79e7311a 1206 ///
QL 0:064c79e7311a 1207 /// Clients might also choose to define QF_ACTIVE_SUPER_ as their own
QL 0:064c79e7311a 1208 /// completely customized class that has nothing to do with QHsm or QFsm.
QL 0:064c79e7311a 1209 /// The QF_ACTIVE_SUPER_ class must provide member functions init() and
QL 0:064c79e7311a 1210 /// dispatch(), consistent with the signatures of QHsm and QFsm. But
QL 0:064c79e7311a 1211 /// the implementatin of these functions is completely open.
QL 0:064c79e7311a 1212 #define QF_ACTIVE_SUPER_ QHsm
QL 0:064c79e7311a 1213
QL 0:064c79e7311a 1214 /// \brief The argument of the base class' constructor.
QL 0:064c79e7311a 1215 #define QF_ACTIVE_STATE_ QStateHandler
QL 0:064c79e7311a 1216
QL 0:064c79e7311a 1217 #endif
QL 0:064c79e7311a 1218
QL 0:064c79e7311a 1219 class QEQueue; // forward declaration
QL 0:064c79e7311a 1220
QL 0:064c79e7311a 1221
QL 0:064c79e7311a 1222 /// \brief Base class for derivation of application-level active object
QL 0:064c79e7311a 1223 /// classes.
QL 0:064c79e7311a 1224 ///
QL 0:064c79e7311a 1225 /// QActive is the base class for derivation of active objects. Active objects
QL 0:064c79e7311a 1226 /// in QF are encapsulated tasks (each embedding a state machine and an event
QL 0:064c79e7311a 1227 /// queue) that communicate with one another asynchronously by sending and
QL 0:064c79e7311a 1228 /// receiving events. Within an active object, events are processed
QL 0:064c79e7311a 1229 /// sequentially in a run-to-completion (RTC) fashion, while QF encapsulates
QL 0:064c79e7311a 1230 /// all the details of thread-safe event exchange and queuing.
QL 0:064c79e7311a 1231 ///
QL 0:064c79e7311a 1232 /// \note QActive is not intended to be instantiated directly, but rather
QL 0:064c79e7311a 1233 /// serves as the base class for derivation of active objects in the
QL 0:064c79e7311a 1234 /// application code.
QL 0:064c79e7311a 1235 ///
QL 0:064c79e7311a 1236 /// The following example illustrates how to derive an active object from
QL 0:064c79e7311a 1237 /// QActive.
QL 0:064c79e7311a 1238 /// \include qf_qactive.cpp
QL 0:064c79e7311a 1239 ///
QL 0:064c79e7311a 1240 /// \sa #QF_ACTIVE_SUPER_ defines the base class for QActive
QL 0:064c79e7311a 1241 class QActive : public QF_ACTIVE_SUPER_ {
QL 0:064c79e7311a 1242 private:
QL 0:064c79e7311a 1243
QL 0:064c79e7311a 1244 /// \brief OS-dependent event-queue type.
QL 0:064c79e7311a 1245 ///
QL 0:064c79e7311a 1246 /// The type of the queue depends on the underlying operating system or
QL 0:064c79e7311a 1247 /// a kernel. Many kernels support "message queues" that can be adapted
QL 0:064c79e7311a 1248 /// to deliver QF events to the active object. Alternatively, QF provides
QL 0:064c79e7311a 1249 /// a native event queue implementation that can be used as well.
QL 0:064c79e7311a 1250 ///
QL 0:064c79e7311a 1251 /// The native QF event queue is configured by defining the macro
QL 0:064c79e7311a 1252 /// #QF_EQUEUE_TYPE as ::QEQueue.
QL 0:064c79e7311a 1253 QF_EQUEUE_TYPE m_eQueue;
QL 0:064c79e7311a 1254
QL 0:064c79e7311a 1255 public:
QL 0:064c79e7311a 1256 #ifdef QF_OS_OBJECT_TYPE
QL 0:064c79e7311a 1257 /// \brief OS-dependent per-thread object.
QL 0:064c79e7311a 1258 ///
QL 0:064c79e7311a 1259 /// This data might be used in various ways, depending on the QF port.
QL 0:064c79e7311a 1260 /// In some ports m_osObject is used to block the calling thread when
QL 0:064c79e7311a 1261 /// the native QF queue is empty. In other QF ports the OS-dependent
QL 0:064c79e7311a 1262 /// object might be used differently.
QL 0:064c79e7311a 1263 QF_OS_OBJECT_TYPE m_osObject;
QL 0:064c79e7311a 1264 #endif
QL 0:064c79e7311a 1265
QL 0:064c79e7311a 1266 #ifdef QF_THREAD_TYPE
QL 0:064c79e7311a 1267 /// \brief OS-dependent representation of the thread of the active
QL 0:064c79e7311a 1268 /// object.
QL 0:064c79e7311a 1269 ///
QL 0:064c79e7311a 1270 /// This data might be used in various ways, depending on the QF port.
QL 0:064c79e7311a 1271 /// In some ports m_thread is used store the thread handle. In other ports
QL 0:064c79e7311a 1272 /// m_thread can be the pointer to the Thread-Local-Storage (TLS).
QL 0:064c79e7311a 1273 QF_THREAD_TYPE m_thread;
QL 0:064c79e7311a 1274 #endif
QL 0:064c79e7311a 1275
QL 0:064c79e7311a 1276 /// \brief QF priority associated with the active object.
QL 0:064c79e7311a 1277 /// \sa QActive::start()
QL 0:064c79e7311a 1278 uint8_t m_prio;
QL 0:064c79e7311a 1279
QL 0:064c79e7311a 1280 /// \brief The Boolean loop variable determining if the thread routine
QL 0:064c79e7311a 1281 /// of the active object is running.
QL 0:064c79e7311a 1282 ///
QL 0:064c79e7311a 1283 /// This flag is only used with the traditional loop-structured thread
QL 0:064c79e7311a 1284 /// routines. Clearing this flag breaks out of the thread loop, which is
QL 0:064c79e7311a 1285 /// often the cleanest way to terminate the thread. The following example
QL 0:064c79e7311a 1286 /// illustrates the thread routine for Win32:
QL 0:064c79e7311a 1287 /// \include qf_run.cpp
QL 0:064c79e7311a 1288 uint8_t m_running;
QL 0:064c79e7311a 1289
QL 0:064c79e7311a 1290 public:
QL 0:064c79e7311a 1291
QL 0:064c79e7311a 1292 /// \brief Starts execution of an active object and registers the object
QL 0:064c79e7311a 1293 /// with the framework.
QL 0:064c79e7311a 1294 ///
QL 0:064c79e7311a 1295 /// The function takes six arguments.
QL 0:064c79e7311a 1296 /// \a prio is the priority of the active object. QF allows you to start
QL 0:064c79e7311a 1297 /// up to 63 active objects, each one having a unique priority number
QL 0:064c79e7311a 1298 /// between 1 and 63 inclusive, where higher numerical values correspond
QL 0:064c79e7311a 1299 /// to higher priority (urgency) of the active object relative to the
QL 0:064c79e7311a 1300 /// others.
QL 0:064c79e7311a 1301 /// \a qSto[] and \a qLen arguments are the storage and size of the event
QL 0:064c79e7311a 1302 /// queue used by this active object.
QL 0:064c79e7311a 1303 /// \a stkSto and \a stkSize are the stack storage and size in bytes.
QL 0:064c79e7311a 1304 /// Please note that a per-active object stack is used only when the
QL 0:064c79e7311a 1305 /// underlying OS requies it. If the stack is not required, or the
QL 0:064c79e7311a 1306 /// underlying OS allocates the stack internally, the \a stkSto should be
QL 0:064c79e7311a 1307 /// NULL and/or \a stkSize should be 0.
QL 0:064c79e7311a 1308 /// \a ie is an optional initialization event that can be used to pass
QL 0:064c79e7311a 1309 /// additional startup data to the active object. (Pass NULL if your
QL 0:064c79e7311a 1310 /// active object does not expect the initialization event).
QL 0:064c79e7311a 1311 ///
QL 0:064c79e7311a 1312 /// \note This function is strongly OS-dependent and must be defined in
QL 0:064c79e7311a 1313 /// the QF port to a particular platform.
QL 0:064c79e7311a 1314 ///
QL 0:064c79e7311a 1315 /// The following example shows starting of the Philosopher object when a
QL 0:064c79e7311a 1316 /// per-task stack is required:
QL 0:064c79e7311a 1317 /// \include qf_start.cpp
QL 0:064c79e7311a 1318 void start(uint8_t prio,
QL 0:064c79e7311a 1319 QEvent const *qSto[], uint32_t qLen,
QL 6:01d57c81e96a 1320 void *stkSto, uint32_t stkSize,
QL 0:064c79e7311a 1321 QEvent const *ie = (QEvent *)0);
QL 0:064c79e7311a 1322
QL 0:064c79e7311a 1323 /// \brief Posts an event \a e directly to the event queue of the acitve
QL 0:064c79e7311a 1324 /// object \a me using the First-In-First-Out (FIFO) policy.
QL 0:064c79e7311a 1325 ///
QL 0:064c79e7311a 1326 /// Direct event posting is the simplest asynchronous communication method
QL 0:064c79e7311a 1327 /// available in QF. The following example illustrates how the Philosopher
QL 0:064c79e7311a 1328 /// active obejct posts directly the HUNGRY event to the Table active
QL 0:064c79e7311a 1329 /// object. \include qf_post.cpp
QL 0:064c79e7311a 1330 ///
QL 0:064c79e7311a 1331 /// \note The producer of the event (Philosopher in this case) must only
QL 0:064c79e7311a 1332 /// "know" the recipient (Table) by a generic (QActive *QDPP_table)
QL 0:064c79e7311a 1333 /// pointer, but the specific definition of the Table class is not
QL 0:064c79e7311a 1334 /// required.
QL 0:064c79e7311a 1335 ///
QL 0:064c79e7311a 1336 /// \note Direct event posting should not be confused with direct event
QL 0:064c79e7311a 1337 /// dispatching. In contrast to asynchronous event posting through event
QL 0:064c79e7311a 1338 /// queues, direct event dispatching is synchronous. Direct event
QL 0:064c79e7311a 1339 /// dispatching occurs when you call QHsm::dispatch(), or QFsm::dispatch()
QL 0:064c79e7311a 1340 /// function.
QL 6:01d57c81e96a 1341 #ifndef Q_SPY
QL 0:064c79e7311a 1342 void postFIFO(QEvent const *e);
QL 6:01d57c81e96a 1343 #else
QL 6:01d57c81e96a 1344 void postFIFO(QEvent const *e, void const *sender);
QL 6:01d57c81e96a 1345 #endif
QL 0:064c79e7311a 1346
QL 0:064c79e7311a 1347 /// \brief Posts an event directly to the event queue of the active object
QL 0:064c79e7311a 1348 /// \a me using the Last-In-First-Out (LIFO) policy.
QL 0:064c79e7311a 1349 ///
QL 6:01d57c81e96a 1350 /// \note The LIFO policy should be used only for self-posting and with
QL 6:01d57c81e96a 1351 /// great caution because it alters order of events in the queue.
QL 6:01d57c81e96a 1352 ///
QL 0:064c79e7311a 1353 /// \sa QActive::postFIFO()
QL 0:064c79e7311a 1354 void postLIFO(QEvent const *e);
QL 0:064c79e7311a 1355
QL 0:064c79e7311a 1356 /// \brief Traditional loop-structured thread routine for an active object
QL 0:064c79e7311a 1357 ///
QL 0:064c79e7311a 1358 /// This function is only used when QF is ported to a traditional
QL 0:064c79e7311a 1359 /// RTOS/Kernel. QActive::run() is structured as a typical endless loop,
QL 0:064c79e7311a 1360 /// which blocks on the event queue get() operation of an active object.
QL 0:064c79e7311a 1361 /// When an event becomes available, it's dispatched to the active
QL 0:064c79e7311a 1362 /// object's state machine and after this recycled with QF::gc().
QL 0:064c79e7311a 1363 /// The loop might optionally use the QActive::m_running flag to terminate
QL 0:064c79e7311a 1364 /// and cause QActive::run() to return which is often the cleanest way to
QL 0:064c79e7311a 1365 /// terminate the thread.
QL 0:064c79e7311a 1366 void run(void);
QL 0:064c79e7311a 1367
QL 0:064c79e7311a 1368 /// \brief Get an event from the event queue of an active object.
QL 0:064c79e7311a 1369 ///
QL 0:064c79e7311a 1370 /// This function is used internally by a QF port to extract events from
QL 0:064c79e7311a 1371 /// the event queue of an active object. This function depends on the
QL 0:064c79e7311a 1372 /// event queue implementation and is sometimes implemented in the QF port
QL 0:064c79e7311a 1373 /// (qf_port.cpp file). Depending on the underlying OS or kernel, the
QL 0:064c79e7311a 1374 /// function might block the calling thread when no events are available.
QL 0:064c79e7311a 1375 ///
QL 0:064c79e7311a 1376 /// \note QActive::get_() is public because it often needs to be called
QL 0:064c79e7311a 1377 /// from thread-run routines with difficult to foresee signature (so
QL 0:064c79e7311a 1378 /// declaring friendship with such function(s) is not possible.)
QL 0:064c79e7311a 1379 ///
QL 0:064c79e7311a 1380 /// \sa QActive::postFIFO(), QActive::postLIFO()
QL 0:064c79e7311a 1381 QEvent const *get_(void);
QL 0:064c79e7311a 1382
QL 0:064c79e7311a 1383 protected:
QL 0:064c79e7311a 1384
QL 0:064c79e7311a 1385 /// \brief protected constructor
QL 0:064c79e7311a 1386 ///
QL 0:064c79e7311a 1387 /// Performs the first step of active object initialization by assigning
QL 0:064c79e7311a 1388 /// the initial pseudostate to the currently active state of the state
QL 0:064c79e7311a 1389 /// machine.
QL 0:064c79e7311a 1390 ///
QL 0:064c79e7311a 1391 /// \note The constructor is protected to prevent direct instantiation
QL 0:064c79e7311a 1392 /// of QActive objects. This class is intended only for derivation
QL 0:064c79e7311a 1393 /// (abstract class).
QL 0:064c79e7311a 1394 QActive(QF_ACTIVE_STATE_ initial) : QF_ACTIVE_SUPER_(initial) {
QL 0:064c79e7311a 1395 }
QL 0:064c79e7311a 1396
QL 0:064c79e7311a 1397 /// \brief Stops execution of an active object and removes it from the
QL 0:064c79e7311a 1398 /// framework's supervision.
QL 0:064c79e7311a 1399 ///
QL 0:064c79e7311a 1400 /// The preferred way of calling this function is from within the active
QL 0:064c79e7311a 1401 /// object that needs to stop (that's why this function is protected).
QL 0:064c79e7311a 1402 /// In other words, an active object should stop itself rather than being
QL 0:064c79e7311a 1403 /// stopped by some other entity. This policy works best, because only
QL 0:064c79e7311a 1404 /// the active object itself "knows" when it has reached the appropriate
QL 0:064c79e7311a 1405 /// state for the shutdown.
QL 0:064c79e7311a 1406 ///
QL 0:064c79e7311a 1407 /// \note This function is strongly OS-dependent and should be defined in
QL 0:064c79e7311a 1408 /// the QF port to a particular platform. This function is optional in
QL 0:064c79e7311a 1409 /// embedded systems where active objects never need to be stopped.
QL 0:064c79e7311a 1410 void stop(void);
QL 0:064c79e7311a 1411
QL 0:064c79e7311a 1412 /// \brief Subscribes for delivery of signal \a sig to the active object
QL 0:064c79e7311a 1413 ///
QL 0:064c79e7311a 1414 /// This function is part of the Publish-Subscribe event delivery
QL 0:064c79e7311a 1415 /// mechanism available in QF. Subscribing to an event means that the
QL 0:064c79e7311a 1416 /// framework will start posting all published events with a given signal
QL 0:064c79e7311a 1417 /// \a sig to the event queue of the active object.
QL 0:064c79e7311a 1418 ///
QL 0:064c79e7311a 1419 /// The following example shows how the Table active object subscribes
QL 0:064c79e7311a 1420 /// to three signals in the initial transition:
QL 0:064c79e7311a 1421 /// \include qf_subscribe.cpp
QL 0:064c79e7311a 1422 ///
QL 0:064c79e7311a 1423 /// \sa QF::publish(), QActive::unsubscribe(), and
QL 0:064c79e7311a 1424 /// QActive::unsubscribeAll()
QL 0:064c79e7311a 1425 void subscribe(QSignal sig) const;
QL 0:064c79e7311a 1426
QL 0:064c79e7311a 1427 /// \brief Un-subscribes from the delivery of signal \a sig to the
QL 0:064c79e7311a 1428 /// active object.
QL 0:064c79e7311a 1429 ///
QL 0:064c79e7311a 1430 /// This function is part of the Publish-Subscribe event delivery
QL 0:064c79e7311a 1431 /// mechanism available in QF. Un-subscribing from an event means that
QL 0:064c79e7311a 1432 /// the framework will stop posting published events with a given signal
QL 0:064c79e7311a 1433 /// \a sig to the event queue of the active object.
QL 0:064c79e7311a 1434 ///
QL 0:064c79e7311a 1435 /// \note Due to the latency of event queues, an active object should NOT
QL 0:064c79e7311a 1436 /// assume that a given signal \a sig will never be dispatched to the
QL 0:064c79e7311a 1437 /// state machine of the active object after un-subscribing from that
QL 0:064c79e7311a 1438 /// signal. The event might be already in the queue, or just about to be
QL 0:064c79e7311a 1439 /// posted and the un-subscribe operation will not flush such events.
QL 0:064c79e7311a 1440 ///
QL 0:064c79e7311a 1441 /// \note Un-subscribing from a signal that has never been subscribed in
QL 0:064c79e7311a 1442 /// the first place is considered an error and QF will rise an assertion.
QL 0:064c79e7311a 1443 ///
QL 0:064c79e7311a 1444 /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribeAll()
QL 0:064c79e7311a 1445 void unsubscribe(QSignal sig) const;
QL 0:064c79e7311a 1446
QL 0:064c79e7311a 1447 /// \brief Defer an event to a given separate event queue.
QL 0:064c79e7311a 1448 ///
QL 0:064c79e7311a 1449 /// This function is part of the event deferral support. An active object
QL 0:064c79e7311a 1450 /// uses this function to defer an event \a e to the QF-supported native
QL 0:064c79e7311a 1451 /// event queue \a eq. QF correctly accounts for another outstanding
QL 0:064c79e7311a 1452 /// reference to the event and will not recycle the event at the end of
QL 0:064c79e7311a 1453 /// the RTC step. Later, the active object might recall one event at a
QL 0:064c79e7311a 1454 /// time from the event queue.
QL 0:064c79e7311a 1455 ///
QL 0:064c79e7311a 1456 /// An active object can use multiple event queues to defer events of
QL 0:064c79e7311a 1457 /// different kinds.
QL 0:064c79e7311a 1458 ///
QL 0:064c79e7311a 1459 /// \sa QActive::recall(), QEQueue
QL 0:064c79e7311a 1460 void defer(QEQueue *eq, QEvent const *e);
QL 0:064c79e7311a 1461
QL 0:064c79e7311a 1462 /// \brief Recall a deferred event from a given event queue.
QL 0:064c79e7311a 1463 ///
QL 0:064c79e7311a 1464 /// This function is part of the event deferral support. An active object
QL 0:064c79e7311a 1465 /// uses this function to recall a deferred event from a given QF
QL 0:064c79e7311a 1466 /// event queue. Recalling an event means that it is removed from the
QL 0:064c79e7311a 1467 /// deferred event queue \a eq and posted (LIFO) to the event queue of
QL 0:064c79e7311a 1468 /// the active object.
QL 0:064c79e7311a 1469 ///
QL 6:01d57c81e96a 1470 /// QActive::recall() returns 1 (TRUE) if an event has been recalled.
QL 6:01d57c81e96a 1471 /// Otherwise the function returns 0.
QL 0:064c79e7311a 1472 ///
QL 0:064c79e7311a 1473 /// An active object can use multiple event queues to defer events of
QL 0:064c79e7311a 1474 /// different kinds.
QL 0:064c79e7311a 1475 ///
QL 0:064c79e7311a 1476 /// \sa QActive::defer(), QEQueue, QActive::postLIFO()
QL 6:01d57c81e96a 1477 uint8_t recall(QEQueue *eq);
QL 0:064c79e7311a 1478
QL 0:064c79e7311a 1479 public:
QL 0:064c79e7311a 1480 /// \brief Un-subscribes from the delivery of all signals to the active
QL 0:064c79e7311a 1481 /// object.
QL 0:064c79e7311a 1482 ///
QL 0:064c79e7311a 1483 /// This function is part of the Publish-Subscribe event delivery
QL 0:064c79e7311a 1484 /// mechanism available in QF. Un-subscribing from all events means that
QL 0:064c79e7311a 1485 /// the framework will stop posting any published events to the event
QL 0:064c79e7311a 1486 /// queue of the active object.
QL 0:064c79e7311a 1487 ///
QL 0:064c79e7311a 1488 /// \note Due to the latency of event queues, an active object should NOT
QL 0:064c79e7311a 1489 /// assume that no events will ever be dispatched to the state machine of
QL 0:064c79e7311a 1490 /// the active object after un-subscribing from all events.
QL 0:064c79e7311a 1491 /// The events might be already in the queue, or just about to be posted
QL 0:064c79e7311a 1492 /// and the un-subscribe operation will not flush such events. Also, the
QL 0:064c79e7311a 1493 /// alternative event-delivery mechanisms, such as direct event posting or
QL 0:064c79e7311a 1494 /// time events, can be still delivered to the event queue of the active
QL 0:064c79e7311a 1495 /// object.
QL 0:064c79e7311a 1496 ///
QL 0:064c79e7311a 1497 /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribe()
QL 0:064c79e7311a 1498 void unsubscribeAll(void) const;
QL 0:064c79e7311a 1499
QL 0:064c79e7311a 1500 private:
QL 0:064c79e7311a 1501
QL 0:064c79e7311a 1502 friend class QF;
QL 0:064c79e7311a 1503 friend class QTimeEvt;
QL 0:064c79e7311a 1504 #ifndef QF_INT_KEY_TYPE
QL 0:064c79e7311a 1505 friend void QK_schedule_(void);
QL 0:064c79e7311a 1506 friend void QK_scheduleExt_(void);
QL 0:064c79e7311a 1507 #else
QL 0:064c79e7311a 1508 friend void QK_schedule_(QF_INT_KEY_TYPE intLockKey);
QL 0:064c79e7311a 1509 friend void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey);
QL 0:064c79e7311a 1510 #endif
QL 0:064c79e7311a 1511 };
QL 0:064c79e7311a 1512
QL 0:064c79e7311a 1513
QL 0:064c79e7311a 1514 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1515 #ifndef QF_TIMEEVT_CTR_SIZE
QL 0:064c79e7311a 1516 /// \brief macro to override the default QTimeEvtCtr size.
QL 0:064c79e7311a 1517 /// Valid values 1, 2, or 4; default 2
QL 0:064c79e7311a 1518 #define QF_TIMEEVT_CTR_SIZE 2
QL 0:064c79e7311a 1519 #endif
QL 0:064c79e7311a 1520 #if (QF_TIMEEVT_CTR_SIZE == 1)
QL 0:064c79e7311a 1521
QL 0:064c79e7311a 1522 /// \brief type of the Time Event counter, which determines the dynamic
QL 0:064c79e7311a 1523 /// range of the time delays measured in clock ticks.
QL 0:064c79e7311a 1524 ///
QL 0:064c79e7311a 1525 /// This typedef is configurable via the preprocessor switch
QL 0:064c79e7311a 1526 /// #QF_TIMEEVT_CTR_SIZE. The other possible values of this type are
QL 0:064c79e7311a 1527 /// as follows: \n
QL 0:064c79e7311a 1528 /// uint8_t when (QF_TIMEEVT_CTR_SIZE == 1), and \n
QL 0:064c79e7311a 1529 /// uint32_t when (QF_TIMEEVT_CTR_SIZE == 4).
QL 0:064c79e7311a 1530 typedef uint8_t QTimeEvtCtr;
QL 0:064c79e7311a 1531 #elif (QF_TIMEEVT_CTR_SIZE == 2)
QL 0:064c79e7311a 1532 typedef uint16_t QTimeEvtCtr;
QL 0:064c79e7311a 1533 #elif (QF_TIMEEVT_CTR_SIZE == 4)
QL 0:064c79e7311a 1534 typedef uint32_t QTimeEvtCtr;
QL 0:064c79e7311a 1535 #else
QL 0:064c79e7311a 1536 #error "QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
QL 0:064c79e7311a 1537 #endif
QL 0:064c79e7311a 1538
QL 0:064c79e7311a 1539 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1540 /// \brief Time Event class
QL 0:064c79e7311a 1541 ///
QL 0:064c79e7311a 1542 /// Time events are special QF events equipped with the notion of time
QL 0:064c79e7311a 1543 /// passage. The basic usage model of the time events is as follows. An
QL 0:064c79e7311a 1544 /// active object allocates one or more QTimeEvt objects (provides the
QL 0:064c79e7311a 1545 /// storage for them). When the active object needs to arrange for a timeout,
QL 0:064c79e7311a 1546 /// it arms one of its time events to fire either just once (one-shot) or
QL 0:064c79e7311a 1547 /// periodically. Each time event times out independently from the others,
QL 0:064c79e7311a 1548 /// so a QF application can make multiple parallel timeout requests (from the
QL 0:064c79e7311a 1549 /// same or different active objects). When QF detects that the appropriate
QL 0:064c79e7311a 1550 /// moment has arrived, it inserts the time event directly into the
QL 0:064c79e7311a 1551 /// recipient's event queue. The recipient then processes the time event just
QL 0:064c79e7311a 1552 /// like any other event.
QL 0:064c79e7311a 1553 ///
QL 0:064c79e7311a 1554 /// Time events, as any other QF events derive from the ::QEvent base
QL 0:064c79e7311a 1555 /// class. Typically, you will use a time event as-is, but you can also
QL 0:064c79e7311a 1556 /// further derive more specialized time events from it by adding some more
QL 0:064c79e7311a 1557 /// data members and/or specialized functions that operate on the specialized
QL 0:064c79e7311a 1558 /// time events.
QL 0:064c79e7311a 1559 ///
QL 0:064c79e7311a 1560 /// Internally, the armed time events are organized into a bi-directional
QL 0:064c79e7311a 1561 /// linked list. This linked list is scanned in every invocation of the
QL 0:064c79e7311a 1562 /// QF::tick() function. Only armed (timing out) time events are in the list,
QL 0:064c79e7311a 1563 /// so only armed time events consume CPU cycles.
QL 0:064c79e7311a 1564 ///
QL 0:064c79e7311a 1565 /// \note QF manages the time events in the function QF::tick(), which
QL 0:064c79e7311a 1566 /// must be called periodically, preferably from the clock tick ISR.
QL 0:064c79e7311a 1567 /// \note In this version of QF QTimeEvt objects should be allocated
QL 0:064c79e7311a 1568 /// statically rather than dynamically from event pools. Currently, QF will
QL 0:064c79e7311a 1569 /// not correctly recycle the dynamically allocated Time Events.
QL 0:064c79e7311a 1570 class QTimeEvt : public QEvent {
QL 0:064c79e7311a 1571 private:
QL 0:064c79e7311a 1572
QL 0:064c79e7311a 1573 //// link to the previous time event in the list
QL 0:064c79e7311a 1574 QTimeEvt *m_prev;
QL 0:064c79e7311a 1575
QL 0:064c79e7311a 1576 /// link to the next time event in the list
QL 0:064c79e7311a 1577 QTimeEvt *m_next;
QL 0:064c79e7311a 1578
QL 0:064c79e7311a 1579 /// the active object that receives the time events.
QL 0:064c79e7311a 1580 QActive *m_act;
QL 0:064c79e7311a 1581
QL 0:064c79e7311a 1582 /// the internal down-counter of the time event. The down-counter
QL 0:064c79e7311a 1583 /// is decremented by 1 in every QF_tick() invocation. The time event
QL 0:064c79e7311a 1584 /// fires (gets posted or published) when the down-counter reaches zero.
QL 0:064c79e7311a 1585 QTimeEvtCtr m_ctr;
QL 0:064c79e7311a 1586
QL 0:064c79e7311a 1587 /// the interval for the periodic time event (zero for the one-shot
QL 0:064c79e7311a 1588 /// time event). The value of the interval is re-loaded to the internal
QL 0:064c79e7311a 1589 /// down-counter when the time event expires, so that the time event
QL 0:064c79e7311a 1590 /// keeps timing out periodically.
QL 0:064c79e7311a 1591 QTimeEvtCtr m_interval;
QL 0:064c79e7311a 1592
QL 0:064c79e7311a 1593 public:
QL 0:064c79e7311a 1594
QL 0:064c79e7311a 1595 /// \brief The Time Event constructor.
QL 0:064c79e7311a 1596 ///
QL 0:064c79e7311a 1597 /// The most important initialization performed in the constructor is
QL 0:064c79e7311a 1598 /// assigning a signal to the Time Event. You can reuse the Time Event
QL 0:064c79e7311a 1599 /// any number of times, but you cannot change the signal.
QL 0:064c79e7311a 1600 /// This is because pointers to Time Events might still be held in event
QL 0:064c79e7311a 1601 /// queues and changing signal could to hard-to-detect errors.
QL 0:064c79e7311a 1602 ///
QL 0:064c79e7311a 1603 /// The following example shows the use of QTimeEvt::QTimeEvt()
QL 0:064c79e7311a 1604 /// constructor in the constructor initializer list of the Philosopher
QL 0:064c79e7311a 1605 /// active object constructor that owns the time event
QL 0:064c79e7311a 1606 /// \include qf_ctor.cpp
QL 0:064c79e7311a 1607 QTimeEvt(QSignal s);
QL 0:064c79e7311a 1608
QL 0:064c79e7311a 1609 /// \brief Arm a one-shot time event for direct event posting.
QL 0:064c79e7311a 1610 ///
QL 0:064c79e7311a 1611 /// Arms a time event to fire in \a nTicks clock ticks (one-shot time
QL 0:064c79e7311a 1612 /// event). The time event gets directly posted (using the FIFO policy)
QL 0:064c79e7311a 1613 /// into the event queue of the active object \a act.
QL 0:064c79e7311a 1614 ///
QL 0:064c79e7311a 1615 /// After posting, the time event gets automatically disarmed and can be
QL 0:064c79e7311a 1616 /// reused for a one-shot or periodic timeout requests.
QL 0:064c79e7311a 1617 ///
QL 0:064c79e7311a 1618 /// A one-shot time event can be disarmed at any time by calling the
QL 0:064c79e7311a 1619 /// QTimeEvt::disarm() function. Also, a one-shot time event can be
QL 0:064c79e7311a 1620 /// re-armed to fire in a different number of clock ticks by calling the
QL 0:064c79e7311a 1621 /// QTimeEvt::rearm() function.
QL 0:064c79e7311a 1622 ///
QL 0:064c79e7311a 1623 /// The following example shows how to arm a one-shot time event from a
QL 0:064c79e7311a 1624 /// state machine of an active object:
QL 0:064c79e7311a 1625 /// \include qf_state.cpp
QL 0:064c79e7311a 1626 void postIn(QActive *act, QTimeEvtCtr nTicks) {
QL 0:064c79e7311a 1627 m_interval = (uint16_t)0;
QL 0:064c79e7311a 1628 arm_(act, nTicks);
QL 0:064c79e7311a 1629 }
QL 0:064c79e7311a 1630
QL 0:064c79e7311a 1631 /// \brief Arm a periodic time event for direct event posting.
QL 0:064c79e7311a 1632 ///
QL 0:064c79e7311a 1633 /// Arms a time event to fire every \a nTicks clock ticks (periodic time
QL 0:064c79e7311a 1634 /// event). The time event gets directly posted (using the FIFO policy)
QL 0:064c79e7311a 1635 /// into the event queue of the active object \a act.
QL 0:064c79e7311a 1636 ///
QL 0:064c79e7311a 1637 /// After posting, the time event gets automatically re-armed to fire
QL 0:064c79e7311a 1638 /// again in the specified \a nTicks clock ticks.
QL 0:064c79e7311a 1639 ///
QL 0:064c79e7311a 1640 /// A periodic time event can be disarmed only by calling the
QL 0:064c79e7311a 1641 /// QTimeEvt::disarm() function. After disarming, the time event can be
QL 0:064c79e7311a 1642 /// reused for a one-shot or periodic timeout requests.
QL 0:064c79e7311a 1643 ///
QL 0:064c79e7311a 1644 /// \note An attempt to reuse (arm again) a running periodic time event
QL 0:064c79e7311a 1645 /// raises an assertion.
QL 0:064c79e7311a 1646 ///
QL 0:064c79e7311a 1647 /// Also, a periodic time event can be re-armed to shorten or extend the
QL 0:064c79e7311a 1648 /// current period by calling the QTimeEvt_rearm() function. After
QL 0:064c79e7311a 1649 /// adjusting the current period, the periodic time event goes back
QL 0:064c79e7311a 1650 /// timing out at the original rate.
QL 0:064c79e7311a 1651 void postEvery(QActive *act, QTimeEvtCtr nTicks) {
QL 0:064c79e7311a 1652 m_interval = nTicks;
QL 0:064c79e7311a 1653 arm_(act, nTicks);
QL 0:064c79e7311a 1654 }
QL 0:064c79e7311a 1655
QL 0:064c79e7311a 1656 /// \brief Disarm a time event.
QL 0:064c79e7311a 1657 ///
QL 0:064c79e7311a 1658 /// The time event gets disarmed and can be reused. The function
QL 0:064c79e7311a 1659 /// returns 1 (TRUE) if the time event was truly disarmed, that is, it
QL 0:064c79e7311a 1660 /// was running. The return of 0 (FALSE) means that the time event was
QL 0:064c79e7311a 1661 /// not truly disarmed because it was not running. The FALSE return is
QL 0:064c79e7311a 1662 /// only possible for one-shot time events that have been automatically
QL 0:064c79e7311a 1663 /// disarmed upon expiration. In this case the FALSE return means that
QL 0:064c79e7311a 1664 /// the time event has already been posted or published and should be
QL 0:064c79e7311a 1665 /// expected in the active object's state machine.
QL 0:064c79e7311a 1666 uint8_t disarm(void);
QL 0:064c79e7311a 1667
QL 0:064c79e7311a 1668 /// \brief Rearm a time event.
QL 0:064c79e7311a 1669 ///
QL 0:064c79e7311a 1670 /// The time event gets rearmed with a new number of clock ticks
QL 0:064c79e7311a 1671 /// \a nTicks. This facility can be used to prevent a one-shot time event
QL 0:064c79e7311a 1672 /// from expiring (e.g., a watchdog time event), or to adjusts the
QL 0:064c79e7311a 1673 /// current period of a periodic time event. Rearming a periodic timer
QL 0:064c79e7311a 1674 /// leaves the interval unchanged and is a convenient method to adjust the
QL 0:064c79e7311a 1675 /// phasing of the periodic time event.
QL 0:064c79e7311a 1676 ///
QL 0:064c79e7311a 1677 /// The function returns 1 (TRUE) if the time event was running as it
QL 0:064c79e7311a 1678 /// was re-armed. The return of 0 (FALSE) means that the time event was
QL 0:064c79e7311a 1679 /// not truly rearmed because it was not running. The FALSE return is only
QL 0:064c79e7311a 1680 /// possible for one-shot time events that have been automatically
QL 0:064c79e7311a 1681 /// disarmed upon expiration. In this case the FALSE return means that
QL 0:064c79e7311a 1682 /// the time event has already been posted or published and should be
QL 0:064c79e7311a 1683 /// expected in the active object's state machine.
QL 0:064c79e7311a 1684 uint8_t rearm(QTimeEvtCtr nTicks);
QL 0:064c79e7311a 1685
QL 6:01d57c81e96a 1686 /// \brief Get the current value of the down-counter of a time event.
QL 0:064c79e7311a 1687 ///
QL 6:01d57c81e96a 1688 /// If the time event is armed, the function returns the current value of
QL 6:01d57c81e96a 1689 /// the down-counter of the given time event. If the time event is not
QL 6:01d57c81e96a 1690 /// armed, the function returns 0.
QL 0:064c79e7311a 1691 ///
QL 6:01d57c81e96a 1692 /// /note The function is thread-safe.
QL 6:01d57c81e96a 1693 QTimeEvtCtr ctr(void);
QL 0:064c79e7311a 1694
QL 0:064c79e7311a 1695 private:
QL 0:064c79e7311a 1696
QL 0:064c79e7311a 1697 /// \brief Arm a time event (internal function to be used through macros
QL 0:064c79e7311a 1698 /// only).
QL 0:064c79e7311a 1699 ///
QL 0:064c79e7311a 1700 /// \sa QTimeEvt::postIn(), QTimeEvt::postEvery(),
QL 0:064c79e7311a 1701 /// \sa QTimeEvt::publishIn(), QTimeEvt::publishEvery()
QL 0:064c79e7311a 1702 void arm_(QActive *act, QTimeEvtCtr nTicks);
QL 0:064c79e7311a 1703
QL 0:064c79e7311a 1704 friend class QF;
QL 0:064c79e7311a 1705 };
QL 0:064c79e7311a 1706
QL 0:064c79e7311a 1707
QL 0:064c79e7311a 1708 #if (QF_MAX_ACTIVE > 63)
QL 0:064c79e7311a 1709 #error "QF_MAX_ACTIVE exceeds 63"
QL 0:064c79e7311a 1710 #endif
QL 0:064c79e7311a 1711
QL 0:064c79e7311a 1712 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1713 /// \brief Subscriber List class
QL 0:064c79e7311a 1714 ///
QL 0:064c79e7311a 1715 /// This data type represents a set of active objects that subscribe to
QL 0:064c79e7311a 1716 /// a given signal. The set is represented as an array of bits, where each
QL 0:064c79e7311a 1717 /// bit corresponds to the unique priority of an active object.
QL 0:064c79e7311a 1718 class QSubscrList {
QL 0:064c79e7311a 1719 private:
QL 0:064c79e7311a 1720
QL 0:064c79e7311a 1721 /// An array of bits representing subscriber active objects. Each bit
QL 0:064c79e7311a 1722 /// in the array corresponds to the unique priority of the active object.
QL 0:064c79e7311a 1723 /// The size of the array is determined of the maximum number of active
QL 0:064c79e7311a 1724 /// objects in the application configured by the #QF_MAX_ACTIVE macro.
QL 0:064c79e7311a 1725 /// For example, an active object of priority p is a subscriber if the
QL 0:064c79e7311a 1726 /// following is true: ((m_bits[QF_div8Lkup[p]] & QF_pwr2Lkup[p]) != 0)
QL 0:064c79e7311a 1727 ///
QL 0:064c79e7311a 1728 /// \sa QF::psInit(), QF_div8Lkup, QF_pwr2Lkup, #QF_MAX_ACTIVE
QL 0:064c79e7311a 1729 uint8_t m_bits[((QF_MAX_ACTIVE - 1) / 8) + 1];
QL 0:064c79e7311a 1730
QL 0:064c79e7311a 1731 friend class QF;
QL 0:064c79e7311a 1732 friend class QActive;
QL 0:064c79e7311a 1733 };
QL 0:064c79e7311a 1734
QL 0:064c79e7311a 1735 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 1736 /// \brief QF services.
QL 0:064c79e7311a 1737 ///
QL 0:064c79e7311a 1738 /// This class groups together QF services. It has only static members and
QL 0:064c79e7311a 1739 /// should not be instantiated.
QL 0:064c79e7311a 1740 class QF {
QL 0:064c79e7311a 1741 public:
QL 0:064c79e7311a 1742
QL 0:064c79e7311a 1743 /// \brief QF initialization.
QL 0:064c79e7311a 1744 ///
QL 0:064c79e7311a 1745 /// This function initializes QF and must be called exactly once before
QL 0:064c79e7311a 1746 /// any other QF function.
QL 0:064c79e7311a 1747 static void init(void);
QL 0:064c79e7311a 1748
QL 0:064c79e7311a 1749 /// \brief Publish-subscribe initialization.
QL 0:064c79e7311a 1750 ///
QL 0:064c79e7311a 1751 /// This function initializes the publish-subscribe facilities of QF and
QL 0:064c79e7311a 1752 /// must be called exactly once before any subscriptions/publications
QL 0:064c79e7311a 1753 /// occur in the application. The arguments are as follows: \a subscrSto
QL 0:064c79e7311a 1754 /// is a pointer to the array of subscriber-lists. \a maxSignal is the
QL 0:064c79e7311a 1755 /// dimension of this array and at the same time the maximum signal that
QL 0:064c79e7311a 1756 /// can be published or subscribed.
QL 0:064c79e7311a 1757 ///
QL 0:064c79e7311a 1758 /// The array of subscriber-lists is indexed by signals and provides
QL 0:064c79e7311a 1759 /// mapping between the signals and subscirber-lists. The subscriber-
QL 0:064c79e7311a 1760 /// lists are bitmasks of type ::QSubscrList, each bit in the bitmask
QL 0:064c79e7311a 1761 /// corresponding to the unique priority of an active object. The size
QL 0:064c79e7311a 1762 /// of the ::QSubscrList bitmask depends on the value of the
QL 0:064c79e7311a 1763 /// #QF_MAX_ACTIVE macro.
QL 0:064c79e7311a 1764 ///
QL 0:064c79e7311a 1765 /// \note The publish-subscribe facilities are optional, meaning that
QL 0:064c79e7311a 1766 /// you might choose not to use publish-subscribe. In that case calling
QL 0:064c79e7311a 1767 /// QF::psInit() and using up memory for the subscriber-lists is
QL 0:064c79e7311a 1768 /// unnecessary.
QL 0:064c79e7311a 1769 ///
QL 0:064c79e7311a 1770 /// \sa ::QSubscrList
QL 0:064c79e7311a 1771 ///
QL 0:064c79e7311a 1772 /// The following example shows the typical initialization sequence of
QL 0:064c79e7311a 1773 /// QF: \include qf_main.cpp
QL 0:064c79e7311a 1774 static void psInit(QSubscrList *subscrSto, QSignal maxSignal);
QL 0:064c79e7311a 1775
QL 0:064c79e7311a 1776 /// \brief Event pool initialization for dynamic allocation of events.
QL 0:064c79e7311a 1777 ///
QL 0:064c79e7311a 1778 /// This function initializes one event pool at a time and must be called
QL 0:064c79e7311a 1779 /// exactly once for each event pool before the pool can be used.
QL 0:064c79e7311a 1780 /// The arguments are as follows: \a poolSto is a pointer to the memory
QL 0:064c79e7311a 1781 /// block for the events. \a poolSize is the size of the memory block in
QL 0:064c79e7311a 1782 /// bytes. \a evtSize is the block-size of the pool in bytes, which
QL 0:064c79e7311a 1783 /// determines the maximum size of events that can be allocated from the
QL 0:064c79e7311a 1784 /// pool.
QL 0:064c79e7311a 1785 ///
QL 0:064c79e7311a 1786 /// You might initialize one, two, and up to three event pools by making
QL 0:064c79e7311a 1787 /// one, two, or three calls to the QF_poolInit() function. However,
QL 0:064c79e7311a 1788 /// for the simplicity of the internal implementation, you must initialize
QL 0:064c79e7311a 1789 /// event pools in the ascending order of the event size.
QL 0:064c79e7311a 1790 ///
QL 0:064c79e7311a 1791 /// Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that
QL 0:064c79e7311a 1792 /// can be used for QF event pools. In case such support is missing, QF
QL 0:064c79e7311a 1793 /// provides a native QF event pool implementation. The macro
QL 0:064c79e7311a 1794 /// #QF_EPOOL_TYPE_ determines the type of event pool used by a
QL 0:064c79e7311a 1795 /// particular QF port. See class ::QMPool for more information.
QL 0:064c79e7311a 1796 ///
QL 0:064c79e7311a 1797 /// \note The actual number of events available in the pool might be
QL 0:064c79e7311a 1798 /// actually less than (\a poolSize / \a evtSize) due to the internal
QL 0:064c79e7311a 1799 /// alignment of the blocks that the pool might perform. You can always
QL 0:064c79e7311a 1800 /// check the capacity of the pool by calling QF::getPoolMargin().
QL 0:064c79e7311a 1801 ///
QL 0:064c79e7311a 1802 /// \note The dynamic allocation of events is optional, meaning that you
QL 0:064c79e7311a 1803 /// might choose not to use dynamic events. In that case calling
QL 0:064c79e7311a 1804 /// QF::poolInit() and using up memory for the memory blocks is
QL 0:064c79e7311a 1805 /// unnecessary.
QL 0:064c79e7311a 1806 ///
QL 0:064c79e7311a 1807 /// \sa QF initialization example for QF::init()
QL 0:064c79e7311a 1808 static void poolInit(void *poolSto, uint32_t poolSize,
QL 0:064c79e7311a 1809 QEventSize evtSize);
QL 0:064c79e7311a 1810
QL 0:064c79e7311a 1811 /// \brief Transfers control to QF to run the application.
QL 0:064c79e7311a 1812 ///
QL 0:064c79e7311a 1813 /// QF::run() is typically called from your startup code after you
QL 0:064c79e7311a 1814 /// initialize the QF and start at least one active object with
QL 0:064c79e7311a 1815 /// QActive::start(). Also, QF::start() call must precede the transfer
QL 0:064c79e7311a 1816 /// of control to QF::run(), but some QF ports might call QF::start()
QL 0:064c79e7311a 1817 /// from QF::run(). QF::run() typically never returns to the caller.
QL 0:064c79e7311a 1818 ///
QL 0:064c79e7311a 1819 /// \note This function is strongly platform-dependent and is not
QL 0:064c79e7311a 1820 /// implemented in the QF, but either in the QF port or in the
QL 0:064c79e7311a 1821 /// Board Support Package (BSP) for the given application. All QF ports
QL 0:064c79e7311a 1822 /// must implement QF::run().
QL 0:064c79e7311a 1823 ///
QL 0:064c79e7311a 1824 /// \note When the Quantum Kernel (QK) is used as the underlying real-time
QL 0:064c79e7311a 1825 /// kernel for the QF, all platfrom dependencies are handled in the QK, so
QL 0:064c79e7311a 1826 /// no porting of QF is necessary. In other words, you only need to
QL 0:064c79e7311a 1827 /// recompile the QF platform-independent code with the compiler for your
QL 0:064c79e7311a 1828 /// platform, but you don't need to provide any platform-specific
QL 0:064c79e7311a 1829 /// implementation (so, no qf_port.cpp file is necessary). Moreover, QK
QL 0:064c79e7311a 1830 /// implements the function QF::run() in a platform-independent way,
QL 0:064c79e7311a 1831 /// in the modile qk.cpp.
QL 0:064c79e7311a 1832 static void run(void);
QL 0:064c79e7311a 1833
QL 0:064c79e7311a 1834 /// \brief Startup QF callback.
QL 0:064c79e7311a 1835 ///
QL 0:064c79e7311a 1836 /// The timeline for calling QF::onStartup() depends on the particular
QL 0:064c79e7311a 1837 /// QF port. In most cases, QF::onStartup() is called from QF::run(),
QL 0:064c79e7311a 1838 /// right before starting any multitasking kernel or the background loop.
QL 0:064c79e7311a 1839 static void onStartup(void);
QL 0:064c79e7311a 1840
QL 0:064c79e7311a 1841 /// \brief Cleanup QF callback.
QL 0:064c79e7311a 1842 ///
QL 0:064c79e7311a 1843 /// QF::onCleanup() is called in some QF ports before QF returns to the
QL 0:064c79e7311a 1844 /// underlying operating system or RTOS.
QL 0:064c79e7311a 1845 ///
QL 0:064c79e7311a 1846 /// This function is strongly platform-specific and is not implemented in
QL 0:064c79e7311a 1847 /// the QF but either in the QF port or in the Board Support Package (BSP)
QL 0:064c79e7311a 1848 /// for the given application. Some QF ports might not require
QL 0:064c79e7311a 1849 /// implementing QF::onCleanup() at all, because many embedded
QL 0:064c79e7311a 1850 /// applications don't have anything to exit to.
QL 0:064c79e7311a 1851 ///
QL 0:064c79e7311a 1852 /// \sa QF::init() and QF::stop()
QL 0:064c79e7311a 1853 static void onCleanup(void);
QL 0:064c79e7311a 1854
QL 0:064c79e7311a 1855 #ifndef QF_INT_KEY_TYPE
QL 0:064c79e7311a 1856 static void onIdle(void); // interrupt lock key NOT defined
QL 0:064c79e7311a 1857
QL 0:064c79e7311a 1858 #else
QL 0:064c79e7311a 1859
QL 0:064c79e7311a 1860 /// \brief QF idle callback (customized in BSPs for QF)
QL 0:064c79e7311a 1861 ///
QL 0:064c79e7311a 1862 /// QF::onIdle() is called by the non-preemptive scheduler built into QF
QL 0:064c79e7311a 1863 /// when the framework detects that no events are available for active
QL 0:064c79e7311a 1864 /// objects (the idle condition). This callback gives the application an
QL 0:064c79e7311a 1865 /// opportunity to enter a power-saving CPU mode, or perform some other
QL 0:064c79e7311a 1866 /// idle processing (such as Q-Spy output).
QL 0:064c79e7311a 1867 ///
QL 0:064c79e7311a 1868 /// \note QF::onIdle() is invoked with interrupts LOCKED because the idle
QL 0:064c79e7311a 1869 /// condition can be asynchronously changed at any time by an interrupt.
QL 0:064c79e7311a 1870 /// QF::onIdle() MUST unlock the interrupts internally, but not before
QL 0:064c79e7311a 1871 /// putting the CPU into the low-power mode. (Ideally, unlocking
QL 0:064c79e7311a 1872 /// interrupts and low-power mode should happen atomically). At the very
QL 0:064c79e7311a 1873 /// least, the function MUST unlock interrupts, otherwise interrups will
QL 0:064c79e7311a 1874 /// be locked permanently.
QL 0:064c79e7311a 1875 ///
QL 0:064c79e7311a 1876 /// \note QF::onIdle() is only used by the non-preemptive scheduler built
QL 0:064c79e7311a 1877 /// into QF in the "bare metal" port, and is NOT used in any other ports.
QL 0:064c79e7311a 1878 /// When QF is combined with QK, the QK idle loop calls a different
QL 0:064c79e7311a 1879 /// function QK::onIdle(), with different semantics than QF::onIdle().
QL 0:064c79e7311a 1880 /// When QF is combined with a 3rd-party RTOS or kernel, the idle
QL 0:064c79e7311a 1881 /// processing mechanism of the RTOS or kernal is used instead of
QL 0:064c79e7311a 1882 /// QF::onIdle().
QL 0:064c79e7311a 1883 static void onIdle(QF_INT_KEY_TYPE intLockKey); // int. lock key defined
QL 0:064c79e7311a 1884
QL 0:064c79e7311a 1885 #endif // QF_INT_KEY_TYPE
QL 0:064c79e7311a 1886
QL 0:064c79e7311a 1887 /// \brief Function invoked by the application layer to stop the QF
QL 0:064c79e7311a 1888 /// application and return control to the OS/Kernel.
QL 0:064c79e7311a 1889 ///
QL 0:064c79e7311a 1890 /// This function stops the QF application. After calling this function,
QL 0:064c79e7311a 1891 /// QF attempts to gracefully stop the application. This graceful
QL 0:064c79e7311a 1892 /// shutdown might take some time to complete. The typical use of this
QL 0:064c79e7311a 1893 /// funcition is for terminating the QF application to return back to the
QL 0:064c79e7311a 1894 /// operating system or for handling fatal errors that require shutting
QL 0:064c79e7311a 1895 /// down (and possibly re-setting) the system.
QL 0:064c79e7311a 1896 ///
QL 0:064c79e7311a 1897 /// This function is strongly platform-specific and is not implemented in
QL 0:064c79e7311a 1898 /// the QF but either in the QF port or in the Board Support Package (BSP)
QL 0:064c79e7311a 1899 /// for the given application. Some QF ports might not require
QL 0:064c79e7311a 1900 /// implementing QF::stop() at all, because many embedded application
QL 0:064c79e7311a 1901 /// don't have anything to exit to.
QL 0:064c79e7311a 1902 ///
QL 0:064c79e7311a 1903 /// \sa QF::stop() and QF::onCleanup()
QL 0:064c79e7311a 1904 static void stop(void);
QL 0:064c79e7311a 1905
QL 0:064c79e7311a 1906 /// \brief Publish event to the framework.
QL 0:064c79e7311a 1907 ///
QL 0:064c79e7311a 1908 /// This function posts (using the FIFO policy) the event \a e it to ALL
QL 0:064c79e7311a 1909 /// active object that have subscribed to the signal \a e->sig.
QL 0:064c79e7311a 1910 /// This function is designed to be callable from any part of the system,
QL 0:064c79e7311a 1911 /// including ISRs, device drivers, and active objects.
QL 0:064c79e7311a 1912 ///
QL 0:064c79e7311a 1913 /// In the general case, event publishing requires multi-casting the
QL 0:064c79e7311a 1914 /// event to multiple subscribers. This happens in the caller's thread
QL 0:064c79e7311a 1915 /// with the scheduler locked to prevent preemptions during the multi-
QL 0:064c79e7311a 1916 /// casting process. (Please note that the interrupts are not locked.)
QL 6:01d57c81e96a 1917 #ifndef Q_SPY
QL 0:064c79e7311a 1918 static void publish(QEvent const *e);
QL 6:01d57c81e96a 1919 #else
QL 6:01d57c81e96a 1920 static void publish(QEvent const *e, void const *sender);
QL 6:01d57c81e96a 1921 #endif
QL 0:064c79e7311a 1922
QL 0:064c79e7311a 1923 /// \brief Processes all armed time events at every clock tick.
QL 0:064c79e7311a 1924 ///
QL 0:064c79e7311a 1925 /// This function must be called periodically from a time-tick ISR or from
QL 0:064c79e7311a 1926 /// the highest-priority task so that QF can manage the timeout events.
QL 0:064c79e7311a 1927 ///
QL 0:064c79e7311a 1928 /// \note The QF::tick() function is not reentrant meaning that it must
QL 0:064c79e7311a 1929 /// run to completion before it is called again. Also, QF::tick() assumes
QL 0:064c79e7311a 1930 /// that it never will get preempted by a task, which is always the case
QL 0:064c79e7311a 1931 /// when it is called from an ISR or the highest-priority task.
QL 0:064c79e7311a 1932 ///
QL 0:064c79e7311a 1933 /// \sa ::QTimeEvt.
QL 0:064c79e7311a 1934 ///
QL 0:064c79e7311a 1935 /// The following example illustrates the call to QF::tick():
QL 0:064c79e7311a 1936 /// \include qf_tick.cpp
QL 6:01d57c81e96a 1937 #ifndef Q_SPY
QL 0:064c79e7311a 1938 static void tick(void);
QL 6:01d57c81e96a 1939 #else
QL 6:01d57c81e96a 1940 static void tick(void const *sender);
QL 6:01d57c81e96a 1941 #endif
QL 0:064c79e7311a 1942
QL 0:064c79e7311a 1943 /// \brief Returns the QF version.
QL 0:064c79e7311a 1944 ///
QL 0:064c79e7311a 1945 /// This function returns constant version string in the format x.y.zz,
QL 0:064c79e7311a 1946 /// where x (one digit) is the major version, y (one digit) is the minor
QL 0:064c79e7311a 1947 /// version, and zz (two digits) is the maintenance release version.
QL 0:064c79e7311a 1948 /// An example of the version string is "3.1.03".
QL 0:064c79e7311a 1949 ///
QL 0:064c79e7311a 1950 /// The following example illustrates the usage of this function:
QL 0:064c79e7311a 1951 /// \include qf_version.cpp
QL 0:064c79e7311a 1952 static char const Q_ROM * Q_ROM_VAR getVersion(void);
QL 0:064c79e7311a 1953
QL 0:064c79e7311a 1954 /// \brief Returns the QF-port version.
QL 0:064c79e7311a 1955 ///
QL 0:064c79e7311a 1956 /// This function returns constant version string in the format x.y.zz,
QL 0:064c79e7311a 1957 /// where x (one digit) is the major version, y (one digit) is the minor
QL 0:064c79e7311a 1958 /// version, and zz (two digits) is the maintenance release version.
QL 0:064c79e7311a 1959 /// An example of the QF-port version string is "1.1.03".
QL 0:064c79e7311a 1960 ///
QL 0:064c79e7311a 1961 /// \sa QF::getVersion()
QL 0:064c79e7311a 1962 static char const Q_ROM * Q_ROM_VAR getPortVersion(void);
QL 0:064c79e7311a 1963
QL 0:064c79e7311a 1964 /// \brief This function returns the margin of the given event pool.
QL 0:064c79e7311a 1965 ///
QL 0:064c79e7311a 1966 /// This function returns the margin of the given event pool \a poolId,
QL 0:064c79e7311a 1967 /// where poolId is the ID of the pool initialized by the call to
QL 0:064c79e7311a 1968 /// QF::poolInit(). The poolId of the first initialized pool is 1, the
QL 0:064c79e7311a 1969 /// second 2, and so on.
QL 0:064c79e7311a 1970 ///
QL 0:064c79e7311a 1971 /// The returned pool margin is the minimal number of free blocks
QL 0:064c79e7311a 1972 /// encountered in the given pool since system startup.
QL 0:064c79e7311a 1973 ///
QL 0:064c79e7311a 1974 /// \note Requesting the margin of an un-initialized pool raises an
QL 0:064c79e7311a 1975 /// assertion in the QF.
QL 0:064c79e7311a 1976 static uint32_t getPoolMargin(uint8_t poolId);
QL 0:064c79e7311a 1977
QL 0:064c79e7311a 1978 /// \brief This function returns the margin of the given event queue.
QL 0:064c79e7311a 1979 ///
QL 0:064c79e7311a 1980 /// This function returns the margin of the given event queue of an active
QL 0:064c79e7311a 1981 /// object with priority \a prio. (QF priorities start with 1 and go up to
QL 0:064c79e7311a 1982 /// #QF_MAX_ACTIVE.) The margin is the minimal number of free events
QL 0:064c79e7311a 1983 /// encountered in the given queue since system startup.
QL 0:064c79e7311a 1984 ///
QL 0:064c79e7311a 1985 /// \note QF::getQueueMargin() is available only when the native QF event
QL 0:064c79e7311a 1986 /// queue implementation is used. Requesting the queue margin of an unused
QL 0:064c79e7311a 1987 /// priority level raises an assertion in the QF. (A priority level
QL 0:064c79e7311a 1988 /// becomes used in QF after the call to the QF::add_() function.)
QL 0:064c79e7311a 1989 static uint32_t getQueueMargin(uint8_t prio);
QL 0:064c79e7311a 1990
QL 0:064c79e7311a 1991 /// \brief Internal QF implementation of the dynamic event allocator.
QL 0:064c79e7311a 1992 ///
QL 0:064c79e7311a 1993 /// \note The application code should not call this function directly.
QL 0:064c79e7311a 1994 /// Please use the macro #Q_NEW.
QL 0:064c79e7311a 1995 static QEvent *new_(uint16_t evtSize, QSignal sig);
QL 0:064c79e7311a 1996
QL 6:01d57c81e96a 1997 #ifdef Q_EVT_CTOR
QL 6:01d57c81e96a 1998 #define Q_NEW(evtT_, sig_, ...) \
QL 6:01d57c81e96a 1999 (new(QF::new_(sizeof(evtT_), sig_)) evtT_((sig_), ##__VA_ARGS__))
QL 6:01d57c81e96a 2000 #else
QL 0:064c79e7311a 2001 /// \brief Allocate a dynamic event.
QL 0:064c79e7311a 2002 ///
QL 0:064c79e7311a 2003 /// This macro returns an event pointer cast to the type \a evtT_. The
QL 0:064c79e7311a 2004 /// event is initialized with the signal \a sig. Internally, the macro
QL 0:064c79e7311a 2005 /// calls the internal QF function QF::new_(), which always returns a
QL 0:064c79e7311a 2006 /// valid event pointer.
QL 0:064c79e7311a 2007 ///
QL 0:064c79e7311a 2008 /// \note The internal QF function QF::new_() raises an assertion when
QL 0:064c79e7311a 2009 /// the allocation of the event turns out to be impossible due to event
QL 0:064c79e7311a 2010 /// pool depletion, or incorrect (too big) size of the requested event.
QL 0:064c79e7311a 2011 ///
QL 0:064c79e7311a 2012 /// The following example illustrates dynamic allocation of an event:
QL 0:064c79e7311a 2013 /// \include qf_post.cpp
QL 0:064c79e7311a 2014 #define Q_NEW(evtT_, sig_) ((evtT_ *)QF::new_(sizeof(evtT_), (sig_)))
QL 6:01d57c81e96a 2015 #endif
QL 0:064c79e7311a 2016
QL 0:064c79e7311a 2017 /// \brief Recycle a dynamic event.
QL 0:064c79e7311a 2018 ///
QL 0:064c79e7311a 2019 /// This function implements a simple garbage collector for the dynamic
QL 0:064c79e7311a 2020 /// events. Only dynamic events are candidates for recycling. (A dynamic
QL 0:064c79e7311a 2021 /// event is one that is allocated from an event pool, which is
QL 0:064c79e7311a 2022 /// determined as non-zero e->attrQF__ attribute.) Next, the function
QL 0:064c79e7311a 2023 /// decrements the reference counter of the event, and recycles the event
QL 0:064c79e7311a 2024 /// only if the counter drops to zero (meaning that no more references
QL 0:064c79e7311a 2025 /// are outstanding for this event). The dynamic event is recycled by
QL 0:064c79e7311a 2026 /// returning it to the pool from which it was originally allocated.
QL 0:064c79e7311a 2027 /// The pool-of-origin information is stored in the upper 2-MSBs of the
QL 0:064c79e7311a 2028 /// e->attrQF__ attribute.)
QL 0:064c79e7311a 2029 ///
QL 0:064c79e7311a 2030 /// \note QF invokes the garbage collector at all appropriate contexts,
QL 0:064c79e7311a 2031 /// when an event can become garbage (automatic garbage collection),
QL 0:064c79e7311a 2032 /// so the application code should have NO need to call QF::gc() directly.
QL 0:064c79e7311a 2033 /// The QF::gc() function is exposed only for special cases when your
QL 0:064c79e7311a 2034 /// application sends dynamic events to the "raw" thread-safe queues
QL 0:064c79e7311a 2035 /// (see ::QEQueue). Such queues are processed outside of QF and the
QL 0:064c79e7311a 2036 /// automatic garbage collection CANNOT be performed for these events.
QL 0:064c79e7311a 2037 /// In this case you need to call QF::gc() explicitly.
QL 0:064c79e7311a 2038 static void gc(QEvent const *e);
QL 0:064c79e7311a 2039
QL 0:064c79e7311a 2040 /// \brief array of registered active objects
QL 0:064c79e7311a 2041 ///
QL 0:064c79e7311a 2042 /// \note Not to be used by Clients directly, only in ports of QF
QL 0:064c79e7311a 2043 static QActive *active_[];
QL 0:064c79e7311a 2044
QL 0:064c79e7311a 2045 private: // functions to be used in QF ports only
QL 0:064c79e7311a 2046
QL 0:064c79e7311a 2047 /// \brief Register an active object to be managed by the framework
QL 0:064c79e7311a 2048 ///
QL 0:064c79e7311a 2049 /// This function should not be called by the application directly, only
QL 0:064c79e7311a 2050 /// through the function QActive::start(). The priority of the active
QL 0:064c79e7311a 2051 /// object \a a should be set before calling this function.
QL 0:064c79e7311a 2052 ///
QL 0:064c79e7311a 2053 /// \note This function raises an assertion if the priority of the active
QL 0:064c79e7311a 2054 /// object exceeds the maximum value #QF_MAX_ACTIVE. Also, this function
QL 0:064c79e7311a 2055 /// raises an assertion if the priority of the active object is already in
QL 0:064c79e7311a 2056 /// use. (QF requires each active object to have a UNIQUE priority.)
QL 0:064c79e7311a 2057 static void add_(QActive *a);
QL 0:064c79e7311a 2058
QL 0:064c79e7311a 2059 public:
QL 0:064c79e7311a 2060 /// \brief Remove the active object from the framework.
QL 0:064c79e7311a 2061 ///
QL 0:064c79e7311a 2062 /// This function should not be called by the application directly, only
QL 0:064c79e7311a 2063 /// inside the QF port. The priority level occupied by the active object
QL 0:064c79e7311a 2064 /// is freed-up and can be reused for another active object.
QL 0:064c79e7311a 2065 ///
QL 0:064c79e7311a 2066 /// The active object that is removed from the framework can no longer
QL 0:064c79e7311a 2067 /// participate in the publish-subscribe event exchange.
QL 0:064c79e7311a 2068 ///
QL 0:064c79e7311a 2069 /// \note This function raises an assertion if the priority of the active
QL 0:064c79e7311a 2070 /// object exceeds the maximum value #QF_MAX_ACTIVE or is not used.
QL 0:064c79e7311a 2071 static void remove_(QActive const *a);
QL 0:064c79e7311a 2072
QL 0:064c79e7311a 2073 friend class QActive;
QL 0:064c79e7311a 2074 };
QL 0:064c79e7311a 2075
QL 0:064c79e7311a 2076 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2077 // useful lookup tables
QL 0:064c79e7311a 2078
QL 0:064c79e7311a 2079 /// \brief Lookup table for (log2(n) + 1), where n is the index
QL 0:064c79e7311a 2080 /// into the table.
QL 0:064c79e7311a 2081 ///
QL 0:064c79e7311a 2082 /// This lookup delivers the 1-based number of the most significant 1-bit
QL 0:064c79e7311a 2083 /// of a byte.
QL 0:064c79e7311a 2084 ///
QL 0:064c79e7311a 2085 /// \note Index range n = 0..255. The first index (n == 0) should never
QL 0:064c79e7311a 2086 /// be used.
QL 0:064c79e7311a 2087 ///
QL 0:064c79e7311a 2088 extern uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256];
QL 0:064c79e7311a 2089
QL 0:064c79e7311a 2090 /// \brief Lookup table for (1 << ((n-1) % 8)), where n is the index
QL 0:064c79e7311a 2091 /// into the table.
QL 0:064c79e7311a 2092 ///
QL 0:064c79e7311a 2093 /// \note Index range n = 0..64. The first index (n == 0) should never
QL 0:064c79e7311a 2094 /// be used.
QL 0:064c79e7311a 2095 extern uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65];
QL 0:064c79e7311a 2096
QL 0:064c79e7311a 2097 /// \brief Lookup table for ~(1 << ((n-1) % 8)), where n is the index
QL 0:064c79e7311a 2098 /// into the table.
QL 0:064c79e7311a 2099 ///
QL 0:064c79e7311a 2100 /// \note Index range n = 0..64. The first index (n == 0) should never
QL 0:064c79e7311a 2101 /// be used.
QL 0:064c79e7311a 2102 extern uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65];
QL 0:064c79e7311a 2103
QL 0:064c79e7311a 2104 /// \brief Lookup table for (n-1)/8
QL 0:064c79e7311a 2105 ///
QL 0:064c79e7311a 2106 /// \note Index range n = 0..64. The first index (n == 0) should never
QL 0:064c79e7311a 2107 /// be used.
QL 0:064c79e7311a 2108 extern uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65];
QL 0:064c79e7311a 2109
QL 0:064c79e7311a 2110 //////////////////////////////////////////////////////////////////////////////
QL 6:01d57c81e96a 2111 #ifdef Q_EVT_CTOR
QL 6:01d57c81e96a 2112 #include <new> // for placement new
QL 6:01d57c81e96a 2113 #endif
QL 6:01d57c81e96a 2114
QL 6:01d57c81e96a 2115 // from qf.h -----------------------------------------------------------------
QL 6:01d57c81e96a 2116 //////////////////////////////////////////////////////////////////////////////
QL 6:01d57c81e96a 2117 // QS software tracing integration, only if enabled
QL 6:01d57c81e96a 2118 #ifdef Q_SPY // QS software tracing enabled?
QL 6:01d57c81e96a 2119 #define QS_TIME_SIZE 4
QL 6:01d57c81e96a 2120 #define QS_OBJ_PTR_SIZE 4
QL 6:01d57c81e96a 2121 #define QS_FUN_PTR_SIZE 4
QL 6:01d57c81e96a 2122
QL 6:01d57c81e96a 2123 /// \brief Invoke the system clock tick processing QF::tick(). This macro
QL 6:01d57c81e96a 2124 /// is the recommended way of invoking clock tick processing, because it
QL 6:01d57c81e96a 2125 /// provides the vital information for software tracing and avoids any
QL 6:01d57c81e96a 2126 /// overhead when the tracing is disabled.
QL 6:01d57c81e96a 2127 ///
QL 6:01d57c81e96a 2128 /// This macro takes the argument \a sender_, which is a pointer to the
QL 6:01d57c81e96a 2129 /// sender object. This argument is actually only used when QS software
QL 6:01d57c81e96a 2130 /// tracing is enabled (macro #Q_SPY is defined). When QS software
QL 6:01d57c81e96a 2131 /// tracing is disabled, the macro calls QF::tick() without any
QL 6:01d57c81e96a 2132 /// arguments, so the overhead of passing this extra argument is
QL 6:01d57c81e96a 2133 /// entirely avoided.
QL 6:01d57c81e96a 2134 ///
QL 6:01d57c81e96a 2135 /// \note the pointer to the sender object is not necessarily a poiner
QL 6:01d57c81e96a 2136 /// to an active object. In fact, typically QF::TICK() will be called from
QL 6:01d57c81e96a 2137 /// an interrupt, in which case you would create a unique object just to
QL 6:01d57c81e96a 2138 /// unambiguously identify the ISR as the sender of the time events.
QL 6:01d57c81e96a 2139 ///
QL 6:01d57c81e96a 2140 /// \sa QF::tick()
QL 6:01d57c81e96a 2141 #define TICK(sender_) tick(sender_)
QL 6:01d57c81e96a 2142
QL 6:01d57c81e96a 2143 /// \brief Invoke the event publishing facility QF::publish(). This macro
QL 6:01d57c81e96a 2144 /// is the recommended way of publishing events, because it provides the
QL 6:01d57c81e96a 2145 /// vital information for software tracing and avoids any overhead when the
QL 6:01d57c81e96a 2146 /// tracing is disabled.
QL 6:01d57c81e96a 2147 ///
QL 6:01d57c81e96a 2148 ///
QL 6:01d57c81e96a 2149 /// This macro takes the last argument \a sender_, which is a pointer to
QL 6:01d57c81e96a 2150 /// the sender object. This argument is actually only used when QS software
QL 6:01d57c81e96a 2151 /// tracing is enabled (macro #Q_SPY is defined). When QS software
QL 6:01d57c81e96a 2152 /// tracing is disabled, the macro calls QF::publish() without the
QL 6:01d57c81e96a 2153 /// \a sender_ argument, so the overhead of passing this extra argument
QL 6:01d57c81e96a 2154 /// is entirely avoided.
QL 6:01d57c81e96a 2155 ///
QL 6:01d57c81e96a 2156 /// \note the pointer to the sender object is not necessarily a poiner
QL 6:01d57c81e96a 2157 /// to an active object. In fact, if QF::PUBLISH() is called from an
QL 6:01d57c81e96a 2158 /// interrupt or other context, you can create a unique object just to
QL 6:01d57c81e96a 2159 /// unambiguously identify the publisher of the event.
QL 6:01d57c81e96a 2160 ///
QL 6:01d57c81e96a 2161 /// \sa QF::publish()
QL 6:01d57c81e96a 2162 #define PUBLISH(e_, sender_) publish((e_), (sender_))
QL 6:01d57c81e96a 2163
QL 6:01d57c81e96a 2164 /// \brief Invoke the direct event posting facility QActive::postFIFO().
QL 6:01d57c81e96a 2165 /// This macro is the recommended way of posting events, because it provides
QL 6:01d57c81e96a 2166 /// the vital information for software tracing and avoids any overhead when
QL 6:01d57c81e96a 2167 /// the tracing is disabled.
QL 6:01d57c81e96a 2168 ///
QL 6:01d57c81e96a 2169 ///
QL 6:01d57c81e96a 2170 /// This macro takes the last argument \a sender_, which is a pointer to
QL 6:01d57c81e96a 2171 /// the sender object. This argument is actually only used when QS software
QL 6:01d57c81e96a 2172 /// tracing is disabled (macro #Q_SPY is defined). When QS software
QL 6:01d57c81e96a 2173 /// tracing is not enabled, the macro calls QF_publish() without the
QL 6:01d57c81e96a 2174 /// \a sender_ argument, so the overhead of passing this extra argument
QL 6:01d57c81e96a 2175 /// is entirely avoided.
QL 6:01d57c81e96a 2176 ///
QL 6:01d57c81e96a 2177 /// \note the pointer to the sender object is not necessarily a poiner
QL 6:01d57c81e96a 2178 /// to an active object. In fact, if ao->POST() is called from an
QL 6:01d57c81e96a 2179 /// interrupt or other context, you can create a unique object just to
QL 6:01d57c81e96a 2180 /// unambiguously identify the publisher of the event.
QL 6:01d57c81e96a 2181 ///
QL 6:01d57c81e96a 2182 /// \sa QActive::postFIFO()
QL 6:01d57c81e96a 2183 #define POST(e_, sender_) postFIFO((e_), (sender_))
QL 6:01d57c81e96a 2184
QL 6:01d57c81e96a 2185 #if (QF_EQUEUE_CTR_SIZE == 1)
QL 6:01d57c81e96a 2186
QL 6:01d57c81e96a 2187 /// \brief Internal QS macro to output an unformatted event queue
QL 6:01d57c81e96a 2188 /// counter data element
QL 6:01d57c81e96a 2189 /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE.
QL 6:01d57c81e96a 2190 #define QS_EQC_(ctr_) QS::u8_(ctr_)
QL 6:01d57c81e96a 2191 #elif (QF_EQUEUE_CTR_SIZE == 2)
QL 6:01d57c81e96a 2192 #define QS_EQC_(ctr_) QS::u16_(ctr_)
QL 6:01d57c81e96a 2193 #elif (QF_EQUEUE_CTR_SIZE == 4)
QL 6:01d57c81e96a 2194 #define QS_EQC_(ctr_) QS::u32_(ctr_)
QL 6:01d57c81e96a 2195 #else
QL 6:01d57c81e96a 2196 #error "QF_EQUEUE_CTR_SIZE not defined"
QL 6:01d57c81e96a 2197 #endif
QL 6:01d57c81e96a 2198
QL 6:01d57c81e96a 2199
QL 6:01d57c81e96a 2200 #if (QF_EVENT_SIZ_SIZE == 1)
QL 6:01d57c81e96a 2201
QL 6:01d57c81e96a 2202 /// \brief Internal QS macro to output an unformatted event size
QL 6:01d57c81e96a 2203 /// data element
QL 6:01d57c81e96a 2204 /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE.
QL 6:01d57c81e96a 2205 #define QS_EVS_(size_) QS::u8_(size_)
QL 6:01d57c81e96a 2206 #elif (QF_EVENT_SIZ_SIZE == 2)
QL 6:01d57c81e96a 2207 #define QS_EVS_(size_) QS::u16_(size_)
QL 6:01d57c81e96a 2208 #elif (QF_EVENT_SIZ_SIZE == 4)
QL 6:01d57c81e96a 2209 #define QS_EVS_(size_) QS::u32_(size_)
QL 6:01d57c81e96a 2210 #endif
QL 6:01d57c81e96a 2211
QL 6:01d57c81e96a 2212
QL 6:01d57c81e96a 2213 #if (QF_MPOOL_SIZ_SIZE == 1)
QL 6:01d57c81e96a 2214
QL 6:01d57c81e96a 2215 /// \brief Internal QS macro to output an unformatted memory pool
QL 6:01d57c81e96a 2216 /// block-size data element
QL 6:01d57c81e96a 2217 /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE.
QL 6:01d57c81e96a 2218 #define QS_MPS_(size_) QS::u8_(size_)
QL 6:01d57c81e96a 2219 #elif (QF_MPOOL_SIZ_SIZE == 2)
QL 6:01d57c81e96a 2220 #define QS_MPS_(size_) QS::u16_(size_)
QL 6:01d57c81e96a 2221 #elif (QF_MPOOL_SIZ_SIZE == 4)
QL 6:01d57c81e96a 2222 #define QS_MPS_(size_) QS::u32_(size_)
QL 6:01d57c81e96a 2223 #endif
QL 6:01d57c81e96a 2224
QL 6:01d57c81e96a 2225 #if (QF_MPOOL_CTR_SIZE == 1)
QL 6:01d57c81e96a 2226
QL 6:01d57c81e96a 2227 /// \brief Internal QS macro to output an unformatted memory pool
QL 6:01d57c81e96a 2228 /// block-counter data element
QL 6:01d57c81e96a 2229 /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE.
QL 6:01d57c81e96a 2230 #define QS_MPC_(ctr_) QS::u8_(ctr_)
QL 6:01d57c81e96a 2231 #elif (QF_MPOOL_CTR_SIZE == 2)
QL 6:01d57c81e96a 2232 #define QS_MPC_(ctr_) QS::u16_(ctr_)
QL 6:01d57c81e96a 2233 #elif (QF_MPOOL_CTR_SIZE == 4)
QL 6:01d57c81e96a 2234 #define QS_MPC_(ctr_) QS::u32_(ctr_)
QL 6:01d57c81e96a 2235 #endif
QL 6:01d57c81e96a 2236
QL 6:01d57c81e96a 2237
QL 6:01d57c81e96a 2238 #if (QF_TIMEEVT_CTR_SIZE == 1)
QL 6:01d57c81e96a 2239
QL 6:01d57c81e96a 2240 /// \brief Internal QS macro to output an unformatted time event
QL 6:01d57c81e96a 2241 /// tick-counter data element
QL 6:01d57c81e96a 2242 /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE.
QL 6:01d57c81e96a 2243 #define QS_TEC_(ctr_) QS::u8_(ctr_)
QL 6:01d57c81e96a 2244 #elif (QF_TIMEEVT_CTR_SIZE == 2)
QL 6:01d57c81e96a 2245 #define QS_TEC_(ctr_) QS::u16_(ctr_)
QL 6:01d57c81e96a 2246 #elif (QF_TIMEEVT_CTR_SIZE == 4)
QL 6:01d57c81e96a 2247 #define QS_TEC_(ctr_) QS::u32_(ctr_)
QL 6:01d57c81e96a 2248 #endif
QL 6:01d57c81e96a 2249
QL 6:01d57c81e96a 2250 #else
QL 6:01d57c81e96a 2251 #ifndef qs_dummy_h
QL 6:01d57c81e96a 2252 #include "qs_dummy.h" // disable the QS software tracing
QL 6:01d57c81e96a 2253 #endif
QL 6:01d57c81e96a 2254
QL 6:01d57c81e96a 2255 #define TICK(dummy_) tick()
QL 6:01d57c81e96a 2256 #define PUBLISH(e_, dummy_) publish((e_))
QL 6:01d57c81e96a 2257 #define POST(e_, dummy_) postFIFO((e_))
QL 6:01d57c81e96a 2258
QL 6:01d57c81e96a 2259 #endif // Q_SPY
QL 6:01d57c81e96a 2260
QL 6:01d57c81e96a 2261 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2262 // QS software tracing
QL 0:064c79e7311a 2263 #ifdef Q_SPY
QL 0:064c79e7311a 2264
QL 0:064c79e7311a 2265 // qs.h ======================================================================
QL 0:064c79e7311a 2266 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2267
QL 0:064c79e7311a 2268 /// \brief Quantum Spy record types.
QL 0:064c79e7311a 2269 ///
QL 0:064c79e7311a 2270 /// This enumeration specifies the record types used in the QP components.
QL 0:064c79e7311a 2271 /// You can specify your own record types starting from ::QS_USER offset.
QL 0:064c79e7311a 2272 /// Currently, the maximum of all records cannot exceed 256.
QL 0:064c79e7311a 2273 /// \sa QS::filterOn()/#QS_FILTER_ON and QS::filterOff()/#QS_FILTER_OFF
QL 0:064c79e7311a 2274 enum QSpyRecords {
QL 0:064c79e7311a 2275 // QEP records
QL 0:064c79e7311a 2276 QS_QEP_STATE_EMPTY,
QL 0:064c79e7311a 2277 QS_QEP_STATE_ENTRY, ///< a state was entered
QL 0:064c79e7311a 2278 QS_QEP_STATE_EXIT, ///< a state was exited
QL 0:064c79e7311a 2279 QS_QEP_STATE_INIT, ///< an intial transition was taken in a state
QL 0:064c79e7311a 2280 QS_QEP_INIT_TRAN, ///< the top-most initial transition was taken
QL 0:064c79e7311a 2281 QS_QEP_INTERN_TRAN, ///< an internal transition was taken
QL 0:064c79e7311a 2282 QS_QEP_TRAN, ///< a regular transition was taken
QL 0:064c79e7311a 2283 QS_QEP_IGNORED, ///< an event was ignored (silently discarded)
QL 0:064c79e7311a 2284 QS_QEP_DISPATCH, ///< an event was dispatched (begin of RTC step)
QL 0:064c79e7311a 2285 QS_QEP_RESERVED0,
QL 0:064c79e7311a 2286
QL 0:064c79e7311a 2287 // QF records
QL 0:064c79e7311a 2288 QS_QF_ACTIVE_ADD, ///< an AO has been added to QF (started)
QL 0:064c79e7311a 2289 QS_QF_ACTIVE_REMOVE, ///< an AO has been removed from QF (stopped)
QL 0:064c79e7311a 2290 QS_QF_ACTIVE_SUBSCRIBE, ///< an AO subscribed to an event
QL 0:064c79e7311a 2291 QS_QF_ACTIVE_UNSUBSCRIBE, ///< an AO unsubscribed to an event
QL 0:064c79e7311a 2292 QS_QF_ACTIVE_POST_FIFO, ///< an event was posted (FIFO) directly to an AO
QL 0:064c79e7311a 2293 QS_QF_ACTIVE_POST_LIFO, ///< an event was posted (LIFO) directly to an AO
QL 0:064c79e7311a 2294 QS_QF_ACTIVE_GET, ///< an AO got an event and its queue is still not empty
QL 0:064c79e7311a 2295 QS_QF_ACTIVE_GET_LAST, ///< an AO got an event and its queue is empty
QL 0:064c79e7311a 2296 QS_QF_EQUEUE_INIT, ///< an event queue was initialized
QL 0:064c79e7311a 2297 QS_QF_EQUEUE_POST_FIFO, ///< an event was posted (FIFO) to a raw queue
QL 0:064c79e7311a 2298 QS_QF_EQUEUE_POST_LIFO, ///< an event was posted (LIFO) to a raw queue
QL 0:064c79e7311a 2299 QS_QF_EQUEUE_GET, ///< get an event and queue still not empty
QL 0:064c79e7311a 2300 QS_QF_EQUEUE_GET_LAST, ///< get the last event from the queue
QL 0:064c79e7311a 2301 QS_QF_MPOOL_INIT, ///< a memory pool was initialized
QL 0:064c79e7311a 2302 QS_QF_MPOOL_GET, ///< a memory block was removed from a memory pool
QL 0:064c79e7311a 2303 QS_QF_MPOOL_PUT, ///< a memory block was returned to a memory pool
QL 0:064c79e7311a 2304 QS_QF_PUBLISH, ///< an event was truly published to some subscribers
QL 0:064c79e7311a 2305 QS_QF_RESERVED8,
QL 0:064c79e7311a 2306 QS_QF_NEW, ///< new event creation
QL 0:064c79e7311a 2307 QS_QF_GC_ATTEMPT, ///< garbage collection attempt
QL 0:064c79e7311a 2308 QS_QF_GC, ///< garbage collection
QL 0:064c79e7311a 2309 QS_QF_TICK, ///< QF::tick() was called
QL 0:064c79e7311a 2310 QS_QF_TIMEEVT_ARM, ///< a time event was armed
QL 0:064c79e7311a 2311 QS_QF_TIMEEVT_AUTO_DISARM, ///< a time event expired and was disarmed
QL 0:064c79e7311a 2312 QS_QF_TIMEEVT_DISARM_ATTEMPT,///< an attempt to disarmed a disarmed tevent
QL 0:064c79e7311a 2313 QS_QF_TIMEEVT_DISARM, ///< true disarming of an armed time event
QL 0:064c79e7311a 2314 QS_QF_TIMEEVT_REARM, ///< rearming of a time event
QL 0:064c79e7311a 2315 QS_QF_TIMEEVT_POST, ///< a time event posted itself directly to an AO
QL 6:01d57c81e96a 2316 QS_QF_TIMEEVT_CTR, ///< a time event counter was requested
QL 0:064c79e7311a 2317 QS_QF_INT_LOCK, ///< interrupts were locked
QL 0:064c79e7311a 2318 QS_QF_INT_UNLOCK, ///< interrupts were unlocked
QL 0:064c79e7311a 2319 QS_QF_ISR_ENTRY, ///< an ISR was entered
QL 0:064c79e7311a 2320 QS_QF_ISR_EXIT, ///< an ISR was exited
QL 0:064c79e7311a 2321 QS_QF_RESERVED6,
QL 0:064c79e7311a 2322 QS_QF_RESERVED5,
QL 0:064c79e7311a 2323 QS_QF_RESERVED4,
QL 0:064c79e7311a 2324 QS_QF_RESERVED3,
QL 0:064c79e7311a 2325 QS_QF_RESERVED2,
QL 0:064c79e7311a 2326 QS_QF_RESERVED1,
QL 0:064c79e7311a 2327 QS_QF_RESERVED0,
QL 0:064c79e7311a 2328
QL 0:064c79e7311a 2329 // QK records
QL 0:064c79e7311a 2330 QS_QK_MUTEX_LOCK, ///< the QK mutex was locked
QL 0:064c79e7311a 2331 QS_QK_MUTEX_UNLOCK, ///< the QK mutex was unlocked
QL 0:064c79e7311a 2332 QS_QK_SCHEDULE, ///< the QK scheduler scheduled a new task to execute
QL 0:064c79e7311a 2333 QS_QK_RESERVED6,
QL 0:064c79e7311a 2334 QS_QK_RESERVED5,
QL 0:064c79e7311a 2335 QS_QK_RESERVED4,
QL 0:064c79e7311a 2336 QS_QK_RESERVED3,
QL 0:064c79e7311a 2337 QS_QK_RESERVED2,
QL 0:064c79e7311a 2338 QS_QK_RESERVED1,
QL 0:064c79e7311a 2339 QS_QK_RESERVED0,
QL 0:064c79e7311a 2340
QL 0:064c79e7311a 2341 // Miscellaneous QS records
QL 0:064c79e7311a 2342 QS_SIG_DICTIONARY, ///< signal dictionary entry
QL 0:064c79e7311a 2343 QS_OBJ_DICTIONARY, ///< object dictionary entry
QL 0:064c79e7311a 2344 QS_FUN_DICTIONARY, ///< function dictionary entry
QL 0:064c79e7311a 2345 QS_ASSERT, ///< assertion fired in the code
QL 0:064c79e7311a 2346 QS_RESERVED5,
QL 0:064c79e7311a 2347 QS_RESERVED4,
QL 0:064c79e7311a 2348 QS_RESERVED3,
QL 0:064c79e7311a 2349 QS_RESERVED2,
QL 0:064c79e7311a 2350 QS_RESERVED1,
QL 0:064c79e7311a 2351 QS_RESERVED0,
QL 0:064c79e7311a 2352
QL 0:064c79e7311a 2353 // User records
QL 0:064c79e7311a 2354 QS_USER ///< the first record available for user QS records
QL 0:064c79e7311a 2355 };
QL 0:064c79e7311a 2356
QL 0:064c79e7311a 2357 /// \brief Specification of all QS records for the QS::filterOn() and
QL 0:064c79e7311a 2358 /// QS::filterOff()
QL 0:064c79e7311a 2359 #define QS_ALL_RECORDS ((uint8_t)0xFF)
QL 0:064c79e7311a 2360
QL 0:064c79e7311a 2361 /// \brief Constant representing End-Of-Data condition returned from the
QL 0:064c79e7311a 2362 /// QS::getByte() function.
QL 0:064c79e7311a 2363 #define QS_EOD ((uint16_t)0xFFFF)
QL 0:064c79e7311a 2364
QL 0:064c79e7311a 2365
QL 0:064c79e7311a 2366 #ifndef QS_TIME_SIZE
QL 0:064c79e7311a 2367
QL 0:064c79e7311a 2368 /// \brief The size (in bytes) of the QS time stamp. Valid values: 1, 2,
QL 0:064c79e7311a 2369 /// or 4; default 4.
QL 0:064c79e7311a 2370 ///
QL 0:064c79e7311a 2371 /// This macro can be defined in the QS port file (qs_port.h) to
QL 0:064c79e7311a 2372 /// configure the ::QSTimeCtr type. Here the macro is not defined so the
QL 0:064c79e7311a 2373 /// default of 4 byte is chosen.
QL 0:064c79e7311a 2374 #define QS_TIME_SIZE 4
QL 0:064c79e7311a 2375 #endif
QL 0:064c79e7311a 2376 #if (QS_TIME_SIZE == 1)
QL 0:064c79e7311a 2377 typedef uint8_t QSTimeCtr;
QL 0:064c79e7311a 2378 #define QS_TIME_() QS::u8_(QS::onGetTime())
QL 0:064c79e7311a 2379 #elif (QS_TIME_SIZE == 2)
QL 0:064c79e7311a 2380 typedef uint16_t QSTimeCtr;
QL 0:064c79e7311a 2381 #define QS_TIME_() QS::u16_(QS::onGetTime())
QL 0:064c79e7311a 2382 #elif (QS_TIME_SIZE == 4)
QL 0:064c79e7311a 2383
QL 0:064c79e7311a 2384 /// \brief The type of the QS time stamp
QL 0:064c79e7311a 2385 ///
QL 0:064c79e7311a 2386 /// This type determines the dynamic range of QS time stamps
QL 0:064c79e7311a 2387 typedef uint32_t QSTimeCtr;
QL 0:064c79e7311a 2388
QL 0:064c79e7311a 2389 /// \brief Internal macro to output time stamp to the QS record
QL 0:064c79e7311a 2390 #define QS_TIME_() QS::u32_(QS::onGetTime())
QL 0:064c79e7311a 2391 #else
QL 0:064c79e7311a 2392 #error "QS_TIME_SIZE defined incorrectly, expected 1, 2, or 4"
QL 0:064c79e7311a 2393 #endif
QL 0:064c79e7311a 2394
QL 0:064c79e7311a 2395 #ifndef Q_ROM // provide the default if Q_ROM NOT defined
QL 0:064c79e7311a 2396 #define Q_ROM
QL 0:064c79e7311a 2397 #endif
QL 0:064c79e7311a 2398 #ifndef Q_ROM_VAR // provide the default if Q_ROM_VAR NOT defined
QL 0:064c79e7311a 2399 #define Q_ROM_VAR
QL 0:064c79e7311a 2400 #endif
QL 0:064c79e7311a 2401 #ifndef Q_ROM_BYTE // provide the default if Q_ROM_BYTE NOT defined
QL 0:064c79e7311a 2402 #define Q_ROM_BYTE(rom_var_) (rom_var_)
QL 0:064c79e7311a 2403 #endif
QL 0:064c79e7311a 2404
QL 0:064c79e7311a 2405
QL 0:064c79e7311a 2406 /// \brief Quantum Spy logging facilities
QL 0:064c79e7311a 2407 ///
QL 0:064c79e7311a 2408 /// This class groups together QS services. It has only static members and
QL 0:064c79e7311a 2409 /// should not be instantiated.
QL 0:064c79e7311a 2410 class QS {
QL 0:064c79e7311a 2411 public:
QL 0:064c79e7311a 2412
QL 0:064c79e7311a 2413 /// \brief Get the current version of QS
QL 0:064c79e7311a 2414 ///
QL 0:064c79e7311a 2415 /// \return version of the QS as a constant 6-character string of the form
QL 0:064c79e7311a 2416 /// x.y.zz, where x is a 1-digit major version number, y is a 1-digit
QL 0:064c79e7311a 2417 /// minor version number, and zz is a 2-digit release number.
QL 0:064c79e7311a 2418 static char const Q_ROM * Q_ROM_VAR getVersion(void);
QL 0:064c79e7311a 2419
QL 0:064c79e7311a 2420 /// \brief Initialize the QS data buffer.
QL 0:064c79e7311a 2421 ///
QL 0:064c79e7311a 2422 /// This function should be called from QS_init() to provide QS with the
QL 0:064c79e7311a 2423 /// data buffer. The first argument \a sto[] is the address of the memory
QL 0:064c79e7311a 2424 /// block, and the second argument \a stoSize is the size of this block
QL 0:064c79e7311a 2425 /// in bytes. Currently the size of the QS buffer cannot exceed 64KB.
QL 0:064c79e7311a 2426 ///
QL 0:064c79e7311a 2427 /// QS can work with quite small data buffers, but you will start losing
QL 0:064c79e7311a 2428 /// data if the buffer is too small for the bursts of logging activity.
QL 0:064c79e7311a 2429 /// The right size of the buffer depends on the data production rate and
QL 0:064c79e7311a 2430 /// the data output rate. QS offers flexible filtering to reduce the data
QL 0:064c79e7311a 2431 /// production rate.
QL 0:064c79e7311a 2432 ///
QL 0:064c79e7311a 2433 /// \note If the data output rate cannot keep up with the production rate,
QL 0:064c79e7311a 2434 /// QS will start overwriting the older data with newer data. This is
QL 0:064c79e7311a 2435 /// consistent with the "last-is-best" QS policy. The record sequence
QL 0:064c79e7311a 2436 /// counters and checksums on each record allow to easily detect data
QL 0:064c79e7311a 2437 /// loss.
QL 0:064c79e7311a 2438 static void initBuf(uint8_t sto[], uint32_t stoSize);
QL 0:064c79e7311a 2439
QL 0:064c79e7311a 2440 /// \brief Turn the global Filter on for a given record type \a rec.
QL 0:064c79e7311a 2441 ///
QL 0:064c79e7311a 2442 /// This function sets up the QS filter to enable the record type \a rec.
QL 0:064c79e7311a 2443 /// The argument #QS_ALL_RECORDS specifies to filter-on all records.
QL 0:064c79e7311a 2444 /// This function should be called indirectly through the macro
QL 0:064c79e7311a 2445 /// #QS_FILTER_ON.
QL 0:064c79e7311a 2446 ///
QL 0:064c79e7311a 2447 /// \note Filtering based on the record-type is only the first layer of
QL 0:064c79e7311a 2448 /// filtering. The second layer is based on the object-type. Both filter
QL 0:064c79e7311a 2449 /// layers must be enabled for the QS record to be inserted into the QS
QL 0:064c79e7311a 2450 /// buffer.
QL 0:064c79e7311a 2451 /// \sa QS_filterOff(), #QS_FILTER_SM_OBJ, #QS_FILTER_AO_OBJ,
QL 0:064c79e7311a 2452 /// #QS_FILTER_MP_OBJ, #QS_FILTER_EQ_OBJ, and #QS_FILTER_TE_OBJ.
QL 0:064c79e7311a 2453 static void filterOn(uint8_t rec);
QL 0:064c79e7311a 2454
QL 0:064c79e7311a 2455 /// \brief Turn the global Filter off for a given record type \a rec.
QL 0:064c79e7311a 2456 ///
QL 0:064c79e7311a 2457 /// This function sets up the QS filter to disable the record type \a rec.
QL 0:064c79e7311a 2458 /// The argument #QS_ALL_RECORDS specifies to suppress all records.
QL 0:064c79e7311a 2459 /// This function should be called indirectly through the macro
QL 0:064c79e7311a 2460 /// #QS_FILTER_OFF.
QL 0:064c79e7311a 2461 ///
QL 0:064c79e7311a 2462 /// \note Filtering records based on the record-type is only the first
QL 0:064c79e7311a 2463 /// layer of filtering. The second layer is based on the object-type.
QL 0:064c79e7311a 2464 /// Both filter layers must be enabled for the QS record to be inserted
QL 0:064c79e7311a 2465 /// into the QS buffer.
QL 0:064c79e7311a 2466 /// \sa
QL 0:064c79e7311a 2467 static void filterOff(uint8_t rec);
QL 0:064c79e7311a 2468
QL 0:064c79e7311a 2469 /// \brief Mark the begin of a QS record \a rec
QL 0:064c79e7311a 2470 ///
QL 0:064c79e7311a 2471 /// This function must be called at the beginning of each QS record.
QL 0:064c79e7311a 2472 /// This function should be called indirectly through the macro #QS_BEGIN,
QL 0:064c79e7311a 2473 /// or #QS_BEGIN_NOLOCK, depending if it's called in a normal code or from
QL 0:064c79e7311a 2474 /// a critical section.
QL 0:064c79e7311a 2475 static void begin(uint8_t rec);
QL 0:064c79e7311a 2476
QL 0:064c79e7311a 2477 /// \brief Mark the end of a QS record \a rec
QL 0:064c79e7311a 2478 ///
QL 0:064c79e7311a 2479 /// This function must be called at the end of each QS record.
QL 0:064c79e7311a 2480 /// This function should be called indirectly through the macro #QS_END,
QL 0:064c79e7311a 2481 /// or #QS_END_NOLOCK, depending if it's called in a normal code or from
QL 0:064c79e7311a 2482 /// a critical section.
QL 0:064c79e7311a 2483 static void end(void);
QL 0:064c79e7311a 2484
QL 0:064c79e7311a 2485 // unformatted data elements output ......................................
QL 0:064c79e7311a 2486
QL 0:064c79e7311a 2487 /// \brief output uint8_t data element without format information
QL 0:064c79e7311a 2488 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2489 /// client code directly.
QL 0:064c79e7311a 2490 static void u8_(uint8_t d);
QL 0:064c79e7311a 2491
QL 0:064c79e7311a 2492 /// \brief Output uint16_t data element without format information
QL 0:064c79e7311a 2493 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2494 /// client code directly.
QL 0:064c79e7311a 2495 static void u16_(uint16_t d);
QL 0:064c79e7311a 2496
QL 0:064c79e7311a 2497 /// \brief Output uint32_t data element without format information
QL 0:064c79e7311a 2498 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2499 /// client code directly.
QL 0:064c79e7311a 2500 static void u32_(uint32_t d);
QL 0:064c79e7311a 2501
QL 0:064c79e7311a 2502 /// \brief Output zero-terminated ASCII string element without format
QL 0:064c79e7311a 2503 /// information
QL 0:064c79e7311a 2504 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2505 /// client code directly.
QL 0:064c79e7311a 2506 static void str_(char const *s);
QL 0:064c79e7311a 2507
QL 0:064c79e7311a 2508 /// \brief Output zero-terminated ASCII string element allocated in ROM
QL 0:064c79e7311a 2509 /// without format information
QL 0:064c79e7311a 2510 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2511 /// client code directly.
QL 0:064c79e7311a 2512 static void str_ROM_(char const Q_ROM * Q_ROM_VAR s);
QL 0:064c79e7311a 2513
QL 0:064c79e7311a 2514 // formatted data elements output ........................................
QL 0:064c79e7311a 2515
QL 0:064c79e7311a 2516 /// \brief Output uint8_t data element with format information
QL 0:064c79e7311a 2517 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2518 /// client code directly.
QL 0:064c79e7311a 2519 static void u8(uint8_t format, uint8_t d);
QL 0:064c79e7311a 2520
QL 0:064c79e7311a 2521 /// \brief output uint16_t data element with format information
QL 0:064c79e7311a 2522 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2523 /// client code directly.
QL 0:064c79e7311a 2524 static void u16(uint8_t format, uint16_t d);
QL 0:064c79e7311a 2525
QL 0:064c79e7311a 2526 /// \brief Output uint32_t data element with format information
QL 0:064c79e7311a 2527 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2528 /// client code directly.
QL 0:064c79e7311a 2529 static void u32(uint8_t format, uint32_t d);
QL 0:064c79e7311a 2530
QL 0:064c79e7311a 2531 /// \brief Output 32-bit floating point data element with format
QL 0:064c79e7311a 2532 /// information
QL 0:064c79e7311a 2533 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2534 /// client code directly.
QL 0:064c79e7311a 2535 static void f32(uint8_t format, float d);
QL 0:064c79e7311a 2536
QL 0:064c79e7311a 2537 /// \brief Output 64-bit floating point data element with format
QL 0:064c79e7311a 2538 /// information
QL 0:064c79e7311a 2539 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2540 /// client code directly.
QL 0:064c79e7311a 2541 static void f64(uint8_t format, double d);
QL 0:064c79e7311a 2542
QL 0:064c79e7311a 2543 /// \brief Output zero-terminated ASCII string element with format
QL 0:064c79e7311a 2544 /// information
QL 0:064c79e7311a 2545 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2546 /// client code directly.
QL 0:064c79e7311a 2547 static void str(char const *s);
QL 0:064c79e7311a 2548
QL 0:064c79e7311a 2549 /// \brief Output zero-terminated ASCII string element allocated in ROM
QL 0:064c79e7311a 2550 /// with format information
QL 0:064c79e7311a 2551 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2552 /// client code directly.
QL 0:064c79e7311a 2553 static void str_ROM(char const Q_ROM * Q_ROM_VAR s);
QL 0:064c79e7311a 2554
QL 0:064c79e7311a 2555 /// \brief Output memory block of up to 255-bytes with format information
QL 0:064c79e7311a 2556 /// \note This function is only to be used through macros, never in the
QL 0:064c79e7311a 2557 /// client code directly.
QL 0:064c79e7311a 2558 static void mem(uint8_t const *blk, uint8_t size);
QL 0:064c79e7311a 2559
QL 6:01d57c81e96a 2560 #if (QS_OBJ_PTR_SIZE == 8) || (QS_FUN_PTR_SIZE == 8)
QL 6:01d57c81e96a 2561 /// \brief Output uint64_t data element without format information
QL 6:01d57c81e96a 2562 /// \note This function is only to be used through macros, never in the
QL 6:01d57c81e96a 2563 /// client code directly.
QL 6:01d57c81e96a 2564 static void u64_(uint64_t d);
QL 6:01d57c81e96a 2565
QL 6:01d57c81e96a 2566 /// \brief Output uint64_t data element with format information
QL 6:01d57c81e96a 2567 /// \note This function is only to be used through macros, never in the
QL 6:01d57c81e96a 2568 /// client code directly.
QL 6:01d57c81e96a 2569 static void u64(uint8_t format, uint64_t d);
QL 6:01d57c81e96a 2570 #endif
QL 6:01d57c81e96a 2571
QL 0:064c79e7311a 2572 // QS buffer access ......................................................
QL 0:064c79e7311a 2573
QL 0:064c79e7311a 2574 /// \brief Byte-oriented interface to the QS data buffer.
QL 0:064c79e7311a 2575 ///
QL 0:064c79e7311a 2576 /// This function delivers one byte at a time from the QS data buffer.
QL 0:064c79e7311a 2577 /// The function returns the byte in the least-significant 8-bits of the
QL 0:064c79e7311a 2578 /// 16-bit return value if the byte is available. If no more data is
QL 0:064c79e7311a 2579 /// available at the time, the function returns QS_EOD (End-Of-Data).
QL 0:064c79e7311a 2580 ///
QL 0:064c79e7311a 2581 /// \note QS::getByte() is NOT protected with a critical section.
QL 0:064c79e7311a 2582 static uint16_t getByte(void);
QL 0:064c79e7311a 2583
QL 0:064c79e7311a 2584 /// \brief Block-oriented interface to the QS data buffer.
QL 0:064c79e7311a 2585 ///
QL 0:064c79e7311a 2586 /// This function delivers a contiguous block of data from the QS data
QL 0:064c79e7311a 2587 /// buffer. The function returns the pointer to the beginning of the
QL 0:064c79e7311a 2588 /// block, and writes the number of bytes in the block to the location
QL 0:064c79e7311a 2589 /// pointed to by \a pNbytes. The argument \a pNbytes is also used as
QL 0:064c79e7311a 2590 /// input to provide the maximum size of the data block that the caller
QL 0:064c79e7311a 2591 /// can accept.
QL 0:064c79e7311a 2592 ///
QL 0:064c79e7311a 2593 /// If no bytes are available in the QS buffer when the function is
QL 0:064c79e7311a 2594 /// called, the function returns a NULL pointer and sets the value
QL 0:064c79e7311a 2595 /// pointed to by \a pNbytes to zero.
QL 0:064c79e7311a 2596 ///
QL 0:064c79e7311a 2597 /// \note Only the NULL return from QS::getBlock() indicates that the QS
QL 0:064c79e7311a 2598 /// buffer is empty at the time of the call. The non-NULL return often
QL 0:064c79e7311a 2599 /// means that the block is at the end of the buffer and you need to call
QL 0:064c79e7311a 2600 /// QS::getBlock() again to obtain the rest of the data that "wrapped
QL 0:064c79e7311a 2601 /// around" to the beginning of the QS data buffer.
QL 0:064c79e7311a 2602 ///
QL 0:064c79e7311a 2603 /// \note QS::getBlock() is NOT protected with a critical section.
QL 0:064c79e7311a 2604 static uint8_t const *getBlock(uint16_t *pNbytes);
QL 0:064c79e7311a 2605
QL 0:064c79e7311a 2606 // platform-dependent callback functions, need to be implemented by clients
QL 0:064c79e7311a 2607 public:
QL 0:064c79e7311a 2608
QL 0:064c79e7311a 2609 // platform-specific callback functions, need to be implemented by clients
QL 0:064c79e7311a 2610 /// \brief Callback to startup the QS facility
QL 0:064c79e7311a 2611 ///
QL 0:064c79e7311a 2612 /// This is a platform-dependent "callback" function invoked through the
QL 0:064c79e7311a 2613 /// macro #QS_INIT. You need to implement this function in your
QL 0:064c79e7311a 2614 /// application. At a minimum, the function must configure the QS buffer
QL 0:064c79e7311a 2615 /// by calling QS::initBuf(). Typically, you will also want to open/
QL 0:064c79e7311a 2616 /// configure the QS output channel, such as a serial port, or a file.
QL 0:064c79e7311a 2617 /// The void* argument \a arg can be used to pass parameter(s) needed to
QL 0:064c79e7311a 2618 /// configure the output channel.
QL 0:064c79e7311a 2619 ///
QL 0:064c79e7311a 2620 /// The function returns TRUE (1) if the QS initialization was successful,
QL 0:064c79e7311a 2621 /// or FALSE (0) if it failed.
QL 0:064c79e7311a 2622 ///
QL 0:064c79e7311a 2623 /// The following example illustrates an implementation of QS_onStartup():
QL 0:064c79e7311a 2624 /// \include qs_startup.cpp
QL 0:064c79e7311a 2625 static uint8_t onStartup(void const *arg);
QL 0:064c79e7311a 2626
QL 0:064c79e7311a 2627 /// \brief Callback to cleanup the QS facility
QL 0:064c79e7311a 2628 ///
QL 0:064c79e7311a 2629 /// This is a platform-dependent "callback" function invoked through the
QL 0:064c79e7311a 2630 /// macro #QS_EXIT. You need to implement this function in your
QL 0:064c79e7311a 2631 /// application. The main purpose of this function is to close the QS
QL 0:064c79e7311a 2632 /// output channel, if necessary.
QL 0:064c79e7311a 2633 static void onCleanup(void);
QL 0:064c79e7311a 2634
QL 0:064c79e7311a 2635 /// \brief Callback to flush the QS trace data to the host
QL 0:064c79e7311a 2636 ///
QL 0:064c79e7311a 2637 /// This is a platform-dependent "callback" function to flush the QS
QL 0:064c79e7311a 2638 /// trace buffer to the host. The function typically busy-waits until all
QL 0:064c79e7311a 2639 /// the data in the buffer is sent to the host. This is acceptable only
QL 0:064c79e7311a 2640 /// in the initial transient.
QL 0:064c79e7311a 2641 static void onFlush(void);
QL 0:064c79e7311a 2642
QL 0:064c79e7311a 2643 /// \brief Callback to obtain a timestamp for a QS record.
QL 0:064c79e7311a 2644 ///
QL 0:064c79e7311a 2645 /// This is a platform-dependent "callback" function invoked from the
QL 0:064c79e7311a 2646 /// macro #QS_TIME_ to add the time stamp to the QS record.
QL 0:064c79e7311a 2647 ///
QL 0:064c79e7311a 2648 /// \note Some of the pre-defined QS records from QP do not output the
QL 0:064c79e7311a 2649 /// time stamp. However, ALL user records do output the time stamp.
QL 0:064c79e7311a 2650 /// \note QS::onGetTime() is called in a critical section and should not
QL 0:064c79e7311a 2651 /// unlock interrupts.
QL 0:064c79e7311a 2652 ///
QL 0:064c79e7311a 2653 /// The following example shows using a system call to implement QS
QL 0:064c79e7311a 2654 /// time stamping:
QL 0:064c79e7311a 2655 /// \include qs_onGetTime.cpp
QL 0:064c79e7311a 2656 static QSTimeCtr onGetTime(void);
QL 0:064c79e7311a 2657
QL 0:064c79e7311a 2658 // Global and Local QS filters ...............................................
QL 0:064c79e7311a 2659 public:
QL 0:064c79e7311a 2660 static uint8_t glbFilter_[32]; ///< global on/off QS filter
QL 0:064c79e7311a 2661 static void const *smObj_; ///< state machine for QEP local filter
QL 0:064c79e7311a 2662 static void const *aoObj_; ///< active object for QF/QK local filter
QL 0:064c79e7311a 2663 static void const *mpObj_; ///< event pool for QF local filter
QL 0:064c79e7311a 2664 static void const *eqObj_; ///< raw queue for QF local filter
QL 0:064c79e7311a 2665 static void const *teObj_; ///< time event for QF local filter
QL 0:064c79e7311a 2666 static void const *apObj_;///< generic object Application QF local filter
QL 0:064c79e7311a 2667
QL 0:064c79e7311a 2668 // Miscallaneous .............................................................
QL 0:064c79e7311a 2669 public:
QL 0:064c79e7311a 2670 /// tick counter for the QS_QF_TICK record
QL 0:064c79e7311a 2671 static QSTimeCtr volatile tickCtr_;
QL 0:064c79e7311a 2672 };
QL 0:064c79e7311a 2673
QL 0:064c79e7311a 2674
QL 0:064c79e7311a 2675 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2676 // Macros for adding QS instrumentation to the client code
QL 0:064c79e7311a 2677
QL 0:064c79e7311a 2678 /// \brief Initialize the QS facility.
QL 0:064c79e7311a 2679 ///
QL 0:064c79e7311a 2680 /// This macro provides an indirection layer to invoke the QS initialization
QL 0:064c79e7311a 2681 /// routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
QL 0:064c79e7311a 2682 /// \sa QS::onStartup(), example of setting up a QS filter in #QS_FILTER_IN
QL 0:064c79e7311a 2683 #define QS_INIT(arg_) QS::onStartup(arg_)
QL 0:064c79e7311a 2684
QL 0:064c79e7311a 2685 /// \brief Cleanup the QS facility.
QL 0:064c79e7311a 2686 ///
QL 0:064c79e7311a 2687 /// This macro provides an indirection layer to invoke the QS cleanup
QL 0:064c79e7311a 2688 /// routine if #Q_SPY is defined, or do nothing if #Q_SPY is not defined.
QL 0:064c79e7311a 2689 /// \sa QS::onCleanup()
QL 0:064c79e7311a 2690 #define QS_EXIT() QS::onCleanup()
QL 0:064c79e7311a 2691
QL 0:064c79e7311a 2692 /// \brief Global Filter ON for a given record type \a rec.
QL 0:064c79e7311a 2693 ///
QL 0:064c79e7311a 2694 /// This macro provides an indirection layer to call QS::filterOn() if #Q_SPY
QL 0:064c79e7311a 2695 /// is defined, or do nothing if #Q_SPY is not defined.
QL 0:064c79e7311a 2696 ///
QL 0:064c79e7311a 2697 /// The following example shows how to use QS filters:
QL 0:064c79e7311a 2698 /// \include qs_filter.cpp
QL 0:064c79e7311a 2699 #define QS_FILTER_ON(rec_) QS::filterOn(rec_)
QL 0:064c79e7311a 2700
QL 0:064c79e7311a 2701 /// \brief Global filter OFF for a given record type \a rec.
QL 0:064c79e7311a 2702 ///
QL 0:064c79e7311a 2703 /// This macro provides an indirection layer to call QS::filterOff() if #Q_SPY
QL 0:064c79e7311a 2704 /// is defined, or do nothing if #Q_SPY is not defined.
QL 0:064c79e7311a 2705 ///
QL 0:064c79e7311a 2706 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 0:064c79e7311a 2707 #define QS_FILTER_OFF(rec_) QS::filterOff(rec_)
QL 0:064c79e7311a 2708
QL 0:064c79e7311a 2709 /// \brief Local Filter for a given state machine object \a obj_.
QL 0:064c79e7311a 2710 ///
QL 0:064c79e7311a 2711 /// This macro sets up the state machine object local filter if #Q_SPY is
QL 0:064c79e7311a 2712 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 0:064c79e7311a 2713 /// is the pointer to the state machine object that you want to monitor.
QL 0:064c79e7311a 2714 ///
QL 0:064c79e7311a 2715 /// The state machine object filter allows you to filter QS records pertaining
QL 0:064c79e7311a 2716 /// only to a given state machine object. With this filter disabled, QS will
QL 0:064c79e7311a 2717 /// output records from all state machines in your application. The object
QL 0:064c79e7311a 2718 /// filter is disabled by setting the state machine pointer to NULL.
QL 0:064c79e7311a 2719 ///
QL 0:064c79e7311a 2720 /// The state machine filter affects the following QS records:
QL 0:064c79e7311a 2721 /// ::QS_QEP_STATE_ENTRY, ::QS_QEP_STATE_EXIT, ::QS_QEP_STATE_INIT,
QL 0:064c79e7311a 2722 /// ::QS_QEP_INIT_TRAN, ::QS_QEP_INTERN_TRAN, ::QS_QEP_TRAN,
QL 0:064c79e7311a 2723 /// and ::QS_QEP_IGNORED.
QL 0:064c79e7311a 2724 ///
QL 0:064c79e7311a 2725 /// \note Because active objects are state machines at the same time,
QL 0:064c79e7311a 2726 /// the state machine filter (#QS_FILTER_SM_OBJ) pertains to active
QL 0:064c79e7311a 2727 /// objects as well. However, the state machine filter is more general,
QL 0:064c79e7311a 2728 /// because it can be used only for state machines that are not active
QL 0:064c79e7311a 2729 /// objects, such as "Orthogonal Components".
QL 0:064c79e7311a 2730 ///
QL 0:064c79e7311a 2731 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 0:064c79e7311a 2732 #define QS_FILTER_SM_OBJ(obj_) (QS::smObj_ = (obj_))
QL 0:064c79e7311a 2733
QL 0:064c79e7311a 2734 /// \brief Local Filter for a given active object \a obj_.
QL 0:064c79e7311a 2735 ///
QL 0:064c79e7311a 2736 /// This macro sets up the active object local filter if #Q_SPY is defined,
QL 0:064c79e7311a 2737 /// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
QL 0:064c79e7311a 2738 /// pointer to the active object that you want to monitor.
QL 0:064c79e7311a 2739 ///
QL 0:064c79e7311a 2740 /// The active object filter allows you to filter QS records pertaining
QL 0:064c79e7311a 2741 /// only to a given active object. With this filter disabled, QS will
QL 0:064c79e7311a 2742 /// output records from all active objects in your application. The object
QL 0:064c79e7311a 2743 /// filter is disabled by setting the active object pointer \a obj_ to NULL.
QL 0:064c79e7311a 2744 ///
QL 0:064c79e7311a 2745 /// The active object filter affects the following QS records:
QL 0:064c79e7311a 2746 /// ::QS_QF_ACTIVE_ADD, ::QS_QF_ACTIVE_REMOVE, ::QS_QF_ACTIVE_SUBSCRIBE,
QL 0:064c79e7311a 2747 /// ::QS_QF_ACTIVE_UNSUBSCRIBE, ::QS_QF_ACTIVE_POST_FIFO,
QL 0:064c79e7311a 2748 /// ::QS_QF_ACTIVE_POST_LIFO, ::QS_QF_ACTIVE_GET, and ::QS_QF_ACTIVE_GET_LAST.
QL 0:064c79e7311a 2749 ///
QL 0:064c79e7311a 2750 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 0:064c79e7311a 2751 #define QS_FILTER_AO_OBJ(obj_) (QS::aoObj_ = (obj_))
QL 0:064c79e7311a 2752
QL 0:064c79e7311a 2753 /// \brief Local Filter for a given memory pool object \a obj_.
QL 0:064c79e7311a 2754 ///
QL 0:064c79e7311a 2755 /// This macro sets up the memory pool object local filter if #Q_SPY is
QL 0:064c79e7311a 2756 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 0:064c79e7311a 2757 /// is the pointer to the memory buffer used during the initialization of the
QL 0:064c79e7311a 2758 /// event pool with QF::poolInit().
QL 0:064c79e7311a 2759 ///
QL 0:064c79e7311a 2760 /// The memory pool filter allows you to filter QS records pertaining
QL 0:064c79e7311a 2761 /// only to a given memory pool. With this filter disabled, QS will
QL 0:064c79e7311a 2762 /// output records from all memory pools in your application. The object
QL 0:064c79e7311a 2763 /// filter is disabled by setting the memory pool pointer \a obj_ to NULL.
QL 0:064c79e7311a 2764 ///
QL 0:064c79e7311a 2765 /// The memory pool filter affects the following QS records:
QL 0:064c79e7311a 2766 /// ::QS_QF_MPOOL_INIT, ::QS_QF_MPOOL_GET, and ::QS_QF_MPOOL_PUT.
QL 0:064c79e7311a 2767 ///
QL 0:064c79e7311a 2768 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 0:064c79e7311a 2769 #define QS_FILTER_MP_OBJ(obj_) (QS::mpObj_ = (obj_))
QL 0:064c79e7311a 2770
QL 0:064c79e7311a 2771 /// \brief Filter for a given event queue object \a obj_.
QL 0:064c79e7311a 2772 ///
QL 0:064c79e7311a 2773 /// This macro sets up the event queue object filter if #Q_SPY is defined,
QL 0:064c79e7311a 2774 /// or does nothing if #Q_SPY is not defined. The argument \a obj_ is the
QL 0:064c79e7311a 2775 /// pointer to the "raw" thread-safe queue object you want to monitor.
QL 0:064c79e7311a 2776 ///
QL 0:064c79e7311a 2777 /// The event queue filter allows you to filter QS records pertaining
QL 0:064c79e7311a 2778 /// only to a given event queue. With this filter disabled, QS will
QL 0:064c79e7311a 2779 /// output records from all event queues in your application. The object
QL 0:064c79e7311a 2780 /// filter is disabled by setting the event queue pointer \a obj_ to NULL.
QL 0:064c79e7311a 2781 ///
QL 0:064c79e7311a 2782 /// The event queue filter affects the following QS records:
QL 0:064c79e7311a 2783 /// ::QS_QF_EQUEUE_INIT, ::QS_QF_EQUEUE_POST_FIFO, ::QS_QF_EQUEUE_POST_LIFO,
QL 0:064c79e7311a 2784 /// ::QS_QF_EQUEUE_GET, and ::QS_QF_EQUEUE_GET_LAST.
QL 0:064c79e7311a 2785 ///
QL 0:064c79e7311a 2786 /// \sa Example of using QS filters in #QS_FILTER_IN documentation
QL 0:064c79e7311a 2787 #define QS_FILTER_EQ_OBJ(obj_) (QS::eqObj_ = (obj_))
QL 0:064c79e7311a 2788
QL 0:064c79e7311a 2789 /// \brief Local Filter for a given time event object \a obj_.
QL 0:064c79e7311a 2790 ///
QL 0:064c79e7311a 2791 /// This macro sets up the time event object local filter if #Q_SPY is
QL 0:064c79e7311a 2792 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 0:064c79e7311a 2793 /// is the pointer to the time event object you want to monitor.
QL 0:064c79e7311a 2794 ///
QL 0:064c79e7311a 2795 /// The time event filter allows you to filter QS records pertaining
QL 0:064c79e7311a 2796 /// only to a given time event. With this filter disabled, QS will
QL 0:064c79e7311a 2797 /// output records from all time events in your application. The object
QL 0:064c79e7311a 2798 /// filter is disabled by setting the time event pointer \a obj_ to NULL.
QL 0:064c79e7311a 2799 ///
QL 0:064c79e7311a 2800 /// The time event filter affects the following QS records:
QL 0:064c79e7311a 2801 /// ::QS_QF_TIMEEVT_ARM, ::QS_QF_TIMEEVT_AUTO_DISARM,
QL 0:064c79e7311a 2802 /// ::QS_QF_TIMEEVT_DISARM_ATTEMPT, ::QS_QF_TIMEEVT_DISARM,
QL 0:064c79e7311a 2803 /// ::QS_QF_TIMEEVT_REARM, ::QS_QF_TIMEEVT_POST, and ::QS_QF_TIMEEVT_PUBLISH.
QL 0:064c79e7311a 2804 ///
QL 0:064c79e7311a 2805 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 0:064c79e7311a 2806 #define QS_FILTER_TE_OBJ(obj_) (QS::teObj_ = (obj_))
QL 0:064c79e7311a 2807
QL 0:064c79e7311a 2808 /// \brief Local Filter for a generic application object \a obj_.
QL 0:064c79e7311a 2809 ///
QL 0:064c79e7311a 2810 /// This macro sets up the local application object filter if #Q_SPY is
QL 0:064c79e7311a 2811 /// defined, or does nothing if #Q_SPY is not defined. The argument \a obj_
QL 0:064c79e7311a 2812 /// is the pointer to the application object you want to monitor.
QL 0:064c79e7311a 2813 ///
QL 0:064c79e7311a 2814 /// The application object filter allows you to filter QS records pertaining
QL 0:064c79e7311a 2815 /// only to a given application object. With this filter disabled, QS will
QL 0:064c79e7311a 2816 /// output records from all application-records enabled by the global filter.
QL 0:064c79e7311a 2817 /// The local filter is disabled by setting the time event pointer \a obj_
QL 0:064c79e7311a 2818 /// to NULL.
QL 0:064c79e7311a 2819 ///
QL 0:064c79e7311a 2820 /// \sa Example of using QS filters in #QS_FILTER_ON documentation
QL 6:01d57c81e96a 2821 #define QS_FILTER_AP_OBJ(obj_) (QS::apObj_ = (obj_))
QL 0:064c79e7311a 2822
QL 0:064c79e7311a 2823
QL 0:064c79e7311a 2824 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2825 // Macros to generate user QS records
QL 0:064c79e7311a 2826
QL 0:064c79e7311a 2827 /// \brief Begin a QS user record without locking interrupts.
QL 0:064c79e7311a 2828 #define QS_BEGIN_NOLOCK(rec_, obj_) \
QL 0:064c79e7311a 2829 if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
QL 0:064c79e7311a 2830 & (1U << ((uint8_t)(rec_) & 7U))) != 0) \
QL 0:064c79e7311a 2831 && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \
QL 0:064c79e7311a 2832 { \
QL 0:064c79e7311a 2833 QS::begin((uint8_t)(rec_)); \
QL 0:064c79e7311a 2834 QS_TIME_();
QL 0:064c79e7311a 2835
QL 0:064c79e7311a 2836 /// \brief End a QS user record without locking interrupts.
QL 0:064c79e7311a 2837 #define QS_END_NOLOCK() \
QL 0:064c79e7311a 2838 QS_END_NOLOCK_()
QL 0:064c79e7311a 2839
QL 0:064c79e7311a 2840 // QS-specific interrupt locking/unlocking
QL 0:064c79e7311a 2841 #ifndef QF_INT_KEY_TYPE
QL 0:064c79e7311a 2842 /// \brief This is an internal macro for defining the interrupt lock key.
QL 0:064c79e7311a 2843 ///
QL 0:064c79e7311a 2844 /// The purpose of this macro is to enable writing the same code for the
QL 0:064c79e7311a 2845 /// case when interrupt key is defined and when it is not. If the macro
QL 0:064c79e7311a 2846 /// #QS_INT_KEY_TYPE is defined, this internal macro provides the
QL 0:064c79e7311a 2847 /// definition of the lock key variable. Otherwise this macro is empty.
QL 0:064c79e7311a 2848 /// \sa #QS_INT_KEY_TYPE, #QF_INT_KEY_TYPE
QL 0:064c79e7311a 2849 #define QS_INT_LOCK_KEY_
QL 0:064c79e7311a 2850
QL 0:064c79e7311a 2851 /// \brief This is an internal macro for locking interrupts.
QL 0:064c79e7311a 2852 ///
QL 0:064c79e7311a 2853 /// The purpose of this macro is to enable writing the same code for the
QL 0:064c79e7311a 2854 /// case when interrupt key is defined and when it is not. If the macro
QL 0:064c79e7311a 2855 /// #QS_INT_KEY_TYPE is defined, this internal macro invokes #QS_INT_LOCK
QL 0:064c79e7311a 2856 /// passing the key variable as the parameter. Otherwise #QS_INT_LOCK
QL 0:064c79e7311a 2857 /// is invoked with a dummy parameter.
QL 0:064c79e7311a 2858 /// \sa #QS_INT_LOCK, #QF_INT_LOCK, #QK_INT_LOCK
QL 0:064c79e7311a 2859 #define QS_INT_LOCK_() QF_INT_LOCK(ignore_)
QL 0:064c79e7311a 2860
QL 0:064c79e7311a 2861 /// \brief This is an internal macro for unlocking interrupts.
QL 0:064c79e7311a 2862 ///
QL 0:064c79e7311a 2863 /// The purpose of this macro is to enable writing the same code for the
QL 0:064c79e7311a 2864 /// case when interrupt key is defined and when it is not. If the macro
QL 0:064c79e7311a 2865 /// #QS_INT_KEY_TYPE is defined, this internal macro invokes
QL 0:064c79e7311a 2866 /// #QS_INT_UNLOCK passing the key variable as the parameter. Otherwise
QL 0:064c79e7311a 2867 /// #QS_INT_UNLOCK is invoked with a dummy parameter.
QL 0:064c79e7311a 2868 /// \sa #QS_INT_UNLOCK, #QF_INT_UNLOCK, #QK_INT_UNLOCK
QL 0:064c79e7311a 2869 #define QS_INT_UNLOCK_() QF_INT_UNLOCK(ignore_)
QL 0:064c79e7311a 2870 #else
QL 0:064c79e7311a 2871 #define QS_INT_LOCK_KEY_ QF_INT_KEY_TYPE intLockKey_;
QL 0:064c79e7311a 2872 #define QS_INT_LOCK_() QF_INT_LOCK(intLockKey_)
QL 0:064c79e7311a 2873 #define QS_INT_UNLOCK_() QF_INT_UNLOCK(intLockKey_)
QL 0:064c79e7311a 2874 #endif
QL 0:064c79e7311a 2875
QL 0:064c79e7311a 2876 /// \brief Begin a user QS record with locking interrupts.
QL 0:064c79e7311a 2877 ///
QL 0:064c79e7311a 2878 /// The following example shows how to build a user QS record using the
QL 0:064c79e7311a 2879 /// macros #QS_BEGIN, #QS_END, and the formatted output macros: #QS_U8 and
QL 0:064c79e7311a 2880 /// #QS_STR.
QL 0:064c79e7311a 2881 /// \include qs_user.cpp
QL 0:064c79e7311a 2882 /// \note Must always be used in pair with #QS_END
QL 0:064c79e7311a 2883 #define QS_BEGIN(rec_, obj_) \
QL 0:064c79e7311a 2884 if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
QL 0:064c79e7311a 2885 & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
QL 0:064c79e7311a 2886 && ((QS::apObj_ == (void *)0) || (QS::apObj_ == (obj_)))) \
QL 0:064c79e7311a 2887 { \
QL 0:064c79e7311a 2888 QS_INT_LOCK_KEY_ \
QL 0:064c79e7311a 2889 QS_INT_LOCK_(); \
QL 0:064c79e7311a 2890 QS::begin((uint8_t)(rec_)); \
QL 0:064c79e7311a 2891 QS_TIME_();
QL 0:064c79e7311a 2892
QL 0:064c79e7311a 2893 /// \brief End a QS record with locking interrupts.
QL 0:064c79e7311a 2894 /// \sa example for #QS_BEGIN
QL 0:064c79e7311a 2895 /// \note Must always be used in pair with #QS_BEGIN
QL 0:064c79e7311a 2896 #define QS_END() \
QL 0:064c79e7311a 2897 QS_END_()
QL 0:064c79e7311a 2898
QL 0:064c79e7311a 2899
QL 0:064c79e7311a 2900 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2901 // Macros for use inside other macros or internally in the QP code
QL 0:064c79e7311a 2902
QL 0:064c79e7311a 2903 /// \brief Internal QS macro to begin a QS record with locking the interrupts.
QL 0:064c79e7311a 2904 /// \note This macro is intended to use only inside QP components and NOT
QL 0:064c79e7311a 2905 /// at the application level. \sa #QS_BEGIN
QL 0:064c79e7311a 2906 #define QS_BEGIN_(rec_, objFilter_, obj_) \
QL 0:064c79e7311a 2907 if (((QS::glbFilter_[(uint8_t)(rec_) >> 3U] \
QL 0:064c79e7311a 2908 & (1U << ((uint8_t)(rec_) & 7U))) != 0U) \
QL 0:064c79e7311a 2909 && (((objFilter_) == (void *)0) || ((objFilter_) == (obj_)))) \
QL 0:064c79e7311a 2910 { \
QL 0:064c79e7311a 2911 QS_INT_LOCK_(); \
QL 0:064c79e7311a 2912 QS::begin((uint8_t)(rec_));
QL 0:064c79e7311a 2913
QL 0:064c79e7311a 2914 /// \brief Internal QS macro to end a QS record with locking the interrupts.
QL 0:064c79e7311a 2915 /// \note This macro is intended to use only inside QP components and NOT
QL 0:064c79e7311a 2916 /// at the application level. \sa #QS_END
QL 0:064c79e7311a 2917 #define QS_END_() \
QL 0:064c79e7311a 2918 QS::end(); \
QL 0:064c79e7311a 2919 QS_INT_UNLOCK_(); \
QL 0:064c79e7311a 2920 }
QL 0:064c79e7311a 2921
QL 0:064c79e7311a 2922 /// \brief Internal QS macro to begin a QS record without locking the
QL 0:064c79e7311a 2923 /// 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_NOLOCK
QL 0:064c79e7311a 2926 #define QS_BEGIN_NOLOCK_(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::begin((uint8_t)(rec_));
QL 0:064c79e7311a 2932
QL 0:064c79e7311a 2933 /// \brief Internal QS macro to end a QS record without locking
QL 0:064c79e7311a 2934 /// 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_NOLOCK
QL 0:064c79e7311a 2937 #define QS_END_NOLOCK_() \
QL 0:064c79e7311a 2938 QS::end(); \
QL 0:064c79e7311a 2939 }
QL 0:064c79e7311a 2940
QL 0:064c79e7311a 2941 /// \brief Internal QS macro to output an unformatted uint8_t data element
QL 0:064c79e7311a 2942 #define QS_U8_(data_) QS::u8_(data_)
QL 0:064c79e7311a 2943
QL 0:064c79e7311a 2944 /// \brief Internal QS macro to output an unformatted uint16_t data element
QL 0:064c79e7311a 2945 #define QS_U16_(data_) QS::u16_(data_)
QL 0:064c79e7311a 2946
QL 0:064c79e7311a 2947 /// \brief Internal QS macro to output an unformatted uint32_t data element
QL 0:064c79e7311a 2948 #define QS_U32_(data_) QS::u32_(data_)
QL 0:064c79e7311a 2949
QL 0:064c79e7311a 2950
QL 0:064c79e7311a 2951 #if (QS_OBJ_PTR_SIZE == 1)
QL 0:064c79e7311a 2952 #define QS_OBJ_(obj_) QS::u8_((uint8_t)(obj_))
QL 0:064c79e7311a 2953 #elif (QS_OBJ_PTR_SIZE == 2)
QL 0:064c79e7311a 2954 #define QS_OBJ_(obj_) QS::u16_((uint16_t)(obj_))
QL 0:064c79e7311a 2955 #elif (QS_OBJ_PTR_SIZE == 4)
QL 0:064c79e7311a 2956 #define QS_OBJ_(obj_) QS::u32_((uint32_t)(obj_))
QL 6:01d57c81e96a 2957 #elif (QS_OBJ_PTR_SIZE == 8)
QL 6:01d57c81e96a 2958 #define QS_OBJ_(obj_) QS::u64_((uint64_t)(obj_))
QL 0:064c79e7311a 2959 #else
QL 0:064c79e7311a 2960
QL 0:064c79e7311a 2961 /// \brief Internal QS macro to output an unformatted object pointer
QL 0:064c79e7311a 2962 /// data element
QL 0:064c79e7311a 2963 /// \note the size of the pointer depends on the macro #QS_OBJ_PTR_SIZE.
QL 0:064c79e7311a 2964 /// If the size is not defined the size of pointer is assumed 4-bytes.
QL 0:064c79e7311a 2965 #define QS_OBJ_(obj_) QS::u32_((uint32_t)(obj_))
QL 0:064c79e7311a 2966 #endif
QL 0:064c79e7311a 2967
QL 0:064c79e7311a 2968
QL 0:064c79e7311a 2969 #if (QS_FUN_PTR_SIZE == 1)
QL 0:064c79e7311a 2970 #define QS_FUN_(fun_) QS::u8_((uint8_t)(fun_))
QL 0:064c79e7311a 2971 #elif (QS_FUN_PTR_SIZE == 2)
QL 0:064c79e7311a 2972 #define QS_FUN_(fun_) QS::u16_((uint16_t)(fun_))
QL 0:064c79e7311a 2973 #elif (QS_FUN_PTR_SIZE == 4)
QL 0:064c79e7311a 2974 #define QS_FUN_(fun_) QS::u32_((uint32_t)(fun_))
QL 6:01d57c81e96a 2975 #elif (QS_FUN_PTR_SIZE == 8)
QL 6:01d57c81e96a 2976 #define QS_FUN_(fun_) QS::u64_((uint64_t)(fun_))
QL 0:064c79e7311a 2977 #else
QL 0:064c79e7311a 2978
QL 0:064c79e7311a 2979 /// \brief Internal QS macro to output an unformatted function pointer
QL 0:064c79e7311a 2980 /// data element
QL 0:064c79e7311a 2981 /// \note the size of the pointer depends on the macro #QS_FUN_PTR_SIZE.
QL 0:064c79e7311a 2982 /// If the size is not defined the size of pointer is assumed 4-bytes.
QL 0:064c79e7311a 2983 #define QS_FUN_(fun_) QS::u32_((uint32_t)(fun_))
QL 0:064c79e7311a 2984 #endif
QL 0:064c79e7311a 2985
QL 0:064c79e7311a 2986 /// \brief Internal QS macro to output a zero-terminated ASCII string
QL 0:064c79e7311a 2987 /// data element
QL 0:064c79e7311a 2988 #define QS_STR_(msg_) QS::str_(msg_)
QL 0:064c79e7311a 2989
QL 0:064c79e7311a 2990 /// \brief Internal QS macro to output a zero-terminated ASCII string
QL 0:064c79e7311a 2991 /// allocated in ROM data element
QL 0:064c79e7311a 2992 #define QS_STR_ROM_(msg_) QS::str_ROM_(msg_)
QL 0:064c79e7311a 2993
QL 0:064c79e7311a 2994 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 2995 // Macros for use in the client code
QL 0:064c79e7311a 2996
QL 0:064c79e7311a 2997 /// \brief Enumerates data formats recognized by QS
QL 0:064c79e7311a 2998 ///
QL 0:064c79e7311a 2999 /// QS uses this enumeration is used only internally for the formatted user
QL 0:064c79e7311a 3000 /// data elements.
QL 0:064c79e7311a 3001 enum QSType {
QL 0:064c79e7311a 3002 QS_I8_T, ///< signed 8-bit integer format
QL 0:064c79e7311a 3003 QS_U8_T, ///< unsigned 8-bit integer format
QL 0:064c79e7311a 3004 QS_I16_T, ///< signed 16-bit integer format
QL 0:064c79e7311a 3005 QS_U16_T, ///< unsigned 16-bit integer format
QL 0:064c79e7311a 3006 QS_I32_T, ///< signed 32-bit integer format
QL 0:064c79e7311a 3007 QS_U32_T, ///< unsigned 32-bit integer format
QL 0:064c79e7311a 3008 QS_F32_T, ///< 32-bit floating point format
QL 0:064c79e7311a 3009 QS_F64_T, ///< 64-bit floating point format
QL 0:064c79e7311a 3010 QS_STR_T, ///< zero-terminated ASCII string format
QL 0:064c79e7311a 3011 QS_MEM_T, ///< up to 255-bytes memory block format
QL 0:064c79e7311a 3012 QS_SIG_T, ///< event signal format
QL 0:064c79e7311a 3013 QS_OBJ_T, ///< object pointer format
QL 6:01d57c81e96a 3014 QS_FUN_T, ///< function pointer format
QL 6:01d57c81e96a 3015 QS_I64_T, ///< signed 64-bit integer format
QL 6:01d57c81e96a 3016 QS_U64_T, ///< unsigned 64-bit integer format
QL 6:01d57c81e96a 3017 QS_U32_HEX_T ///< unsigned 32-bit integer in hex format
QL 0:064c79e7311a 3018 };
QL 0:064c79e7311a 3019
QL 0:064c79e7311a 3020 /// \brief Output formatted int8_t to the QS record
QL 0:064c79e7311a 3021 #define QS_I8(width_, data_) \
QL 0:064c79e7311a 3022 QS::u8((uint8_t)(((width_) << 4)) | QS_I8_T, (data_))
QL 0:064c79e7311a 3023
QL 0:064c79e7311a 3024 /// \brief Output formatted uint8_t to the QS record
QL 0:064c79e7311a 3025 #define QS_U8(width_, data_) \
QL 0:064c79e7311a 3026 QS::u8((uint8_t)(((width_) << 4)) | QS_U8_T, (data_))
QL 0:064c79e7311a 3027
QL 0:064c79e7311a 3028 /// \brief Output formatted int16_t to the QS record
QL 0:064c79e7311a 3029 #define QS_I16(width_, data_) \
QL 0:064c79e7311a 3030 QS::u16((uint8_t)(((width_) << 4)) | QS_I16_T, (data_))
QL 0:064c79e7311a 3031
QL 0:064c79e7311a 3032 /// \brief Output formatted uint16_t to the QS record
QL 0:064c79e7311a 3033 #define QS_U16(width_, data_) \
QL 0:064c79e7311a 3034 QS::u16((uint8_t)(((width_) << 4)) | QS_U16_T, (data_))
QL 0:064c79e7311a 3035
QL 0:064c79e7311a 3036 /// \brief Output formatted int32_t to the QS record
QL 0:064c79e7311a 3037 #define QS_I32(width_, data_) \
QL 0:064c79e7311a 3038 QS::u32((uint8_t)(((width_) << 4)) | QS_I32_T, (data_))
QL 0:064c79e7311a 3039
QL 0:064c79e7311a 3040 /// \brief Output formatted uint32_t to the QS record
QL 0:064c79e7311a 3041 #define QS_U32(width_, data_) \
QL 0:064c79e7311a 3042 QS::u32((uint8_t)(((width_) << 4)) | QS_U32_T, (data_))
QL 0:064c79e7311a 3043
QL 0:064c79e7311a 3044 /// \brief Output formatted 32-bit floating point number to the QS record
QL 0:064c79e7311a 3045 #define QS_F32(width_, data_) \
QL 0:064c79e7311a 3046 QS::f32((uint8_t)(((width_) << 4)) | QS_F32_T, (data_))
QL 0:064c79e7311a 3047
QL 0:064c79e7311a 3048 /// \brief Output formatted 64-bit floating point number to the QS record
QL 0:064c79e7311a 3049 #define QS_F64(width_, data_) \
QL 0:064c79e7311a 3050 QS::f64((uint8_t)(((width_) << 4)) | QS_F64_T, (data_))
QL 0:064c79e7311a 3051
QL 6:01d57c81e96a 3052 /// \brief Output formatted int64_t to the QS record
QL 6:01d57c81e96a 3053 #define QS_I64(width_, data_) \
QL 6:01d57c81e96a 3054 QS::u64((uint8_t)(((width_) << 4)) | QS_I64_T, (data_))
QL 6:01d57c81e96a 3055
QL 6:01d57c81e96a 3056 /// \brief Output formatted uint64_t to the QS record
QL 6:01d57c81e96a 3057 #define QS_U64(width_, data_) \
QL 6:01d57c81e96a 3058 QS::u64((uint8_t)(((width_) << 4)) | QS_U64_T, (data_))
QL 6:01d57c81e96a 3059
QL 6:01d57c81e96a 3060 /// \brief Output formatted uint32_t to the QS record
QL 6:01d57c81e96a 3061 #define QS_U32_HEX(width_, data_) \
QL 6:01d57c81e96a 3062 QS::u32((uint8_t)(((width_) << 4)) | QS_U32_HEX_T, (data_))
QL 6:01d57c81e96a 3063
QL 0:064c79e7311a 3064 /// \brief Output formatted zero-terminated ASCII string to the QS record
QL 0:064c79e7311a 3065 #define QS_STR(str_) QS::str(str_)
QL 0:064c79e7311a 3066
QL 0:064c79e7311a 3067 /// \brief Output formatted zero-terminated ASCII string from ROM
QL 0:064c79e7311a 3068 /// to the QS record
QL 0:064c79e7311a 3069 #define QS_STR_ROM(str_) QS::str_ROM(str_)
QL 0:064c79e7311a 3070
QL 0:064c79e7311a 3071 /// \brief Output formatted memory block of up to 255 bytes to the QS
QL 0:064c79e7311a 3072 /// record
QL 0:064c79e7311a 3073 #define QS_MEM(mem_, size_) QS::mem((mem_), (size_))
QL 0:064c79e7311a 3074
QL 0:064c79e7311a 3075
QL 0:064c79e7311a 3076 #if (QS_OBJ_PTR_SIZE == 1)
QL 0:064c79e7311a 3077 #define QS_OBJ(obj_) QS::u8(QS_OBJ_T, (uint8_t)(obj_))
QL 0:064c79e7311a 3078 #elif (QS_OBJ_PTR_SIZE == 2)
QL 0:064c79e7311a 3079 #define QS_OBJ(obj_) QS::u16(QS_OBJ_T, (uint16_t)(obj_))
QL 0:064c79e7311a 3080 #elif (QS_OBJ_PTR_SIZE == 4)
QL 0:064c79e7311a 3081 #define QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_))
QL 6:01d57c81e96a 3082 #elif (QS_OBJ_PTR_SIZE == 8)
QL 6:01d57c81e96a 3083 #define QS_OBJ(obj_) QS::u64(QS_OBJ_T, (uint64_t)(obj_))
QL 0:064c79e7311a 3084 #else
QL 0:064c79e7311a 3085 /// \brief Output formatted object pointer to the QS record
QL 0:064c79e7311a 3086 #define QS_OBJ(obj_) QS::u32(QS_OBJ_T, (uint32_t)(obj_))
QL 0:064c79e7311a 3087 #endif
QL 0:064c79e7311a 3088
QL 0:064c79e7311a 3089
QL 0:064c79e7311a 3090 #if (QS_FUN_PTR_SIZE == 1)
QL 0:064c79e7311a 3091 #define QS_FUN(fun_) QS::u8(QS_FUN_T, (uint8_t)(fun_))
QL 0:064c79e7311a 3092 #elif (QS_FUN_PTR_SIZE == 2)
QL 0:064c79e7311a 3093 #define QS_FUN(fun_) QS::u16(QS_FUN_T, (uint16_t)(fun_))
QL 0:064c79e7311a 3094 #elif (QS_FUN_PTR_SIZE == 4)
QL 0:064c79e7311a 3095 #define QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_))
QL 6:01d57c81e96a 3096 #elif (QS_FUN_PTR_SIZE == 8)
QL 6:01d57c81e96a 3097 #define QS_FUN(fun_) QS::u64(QS_FUN_T, (uint64_t)(fun_))
QL 0:064c79e7311a 3098 #else
QL 0:064c79e7311a 3099 /// \brief Output formatted function pointer to the QS record
QL 0:064c79e7311a 3100 #define QS_FUN(fun_) QS::u32(QS_FUN_T, (uint32_t)(fun_))
QL 0:064c79e7311a 3101 #endif
QL 0:064c79e7311a 3102
QL 0:064c79e7311a 3103
QL 0:064c79e7311a 3104 /// \brief Output signal dictionary record
QL 0:064c79e7311a 3105 ///
QL 0:064c79e7311a 3106 /// A signal dictionary record associates the numerical value of the signal
QL 0:064c79e7311a 3107 /// and the binary address of the state machine that consumes that signal
QL 0:064c79e7311a 3108 /// with the human-readable name of the signal.
QL 0:064c79e7311a 3109 ///
QL 0:064c79e7311a 3110 /// Providing a signal dictionary QS record can vastly improve readability of
QL 0:064c79e7311a 3111 /// the QS log, because instead of dealing with cryptic machine addresses the
QL 0:064c79e7311a 3112 /// QSpy host utility can display human-readable names.
QL 0:064c79e7311a 3113 ///
QL 0:064c79e7311a 3114 /// A signal dictionary entry is associated with both the signal value \a sig_
QL 0:064c79e7311a 3115 /// and the state machine \a obj_, because signals are required to be unique
QL 0:064c79e7311a 3116 /// only within a given state machine and therefore the same numerical values
QL 0:064c79e7311a 3117 /// can represent different signals in different state machines.
QL 0:064c79e7311a 3118 ///
QL 0:064c79e7311a 3119 /// For the "global" signals that have the same meaning in all state machines
QL 0:064c79e7311a 3120 /// (such as globally published signals), you can specify a signal dictionary
QL 0:064c79e7311a 3121 /// entry with the \a obj_ parameter set to NULL.
QL 0:064c79e7311a 3122 ///
QL 0:064c79e7311a 3123 /// The following example shows the definition of signal dictionary entries
QL 0:064c79e7311a 3124 /// in the initial transition of the Table active object. Please note that
QL 0:064c79e7311a 3125 /// signals HUNGRY_SIG and DONE_SIG are associated with the Table state
QL 0:064c79e7311a 3126 /// machine only ("me" \a obj_ pointer). The EAT_SIG signal, on the other
QL 0:064c79e7311a 3127 /// hand, is global (0 \a obj_ pointer):
QL 0:064c79e7311a 3128 /// \include qs_sigDic.cpp
QL 0:064c79e7311a 3129 ///
QL 0:064c79e7311a 3130 /// \note The QSpy log utility must capture the signal dictionary record
QL 0:064c79e7311a 3131 /// in order to use the human-readable information. You need to connect to
QL 0:064c79e7311a 3132 /// the target before the dictionary entries have been transmitted.
QL 0:064c79e7311a 3133 ///
QL 0:064c79e7311a 3134 /// The following QSpy log example shows the signal dictionary records
QL 0:064c79e7311a 3135 /// generated from the Table initial transition and subsequent records that
QL 0:064c79e7311a 3136 /// show human-readable names of the signals:
QL 0:064c79e7311a 3137 /// \include qs_sigLog.txt
QL 0:064c79e7311a 3138 ///
QL 0:064c79e7311a 3139 /// The following QSpy log example shows the same sequence of records, but
QL 0:064c79e7311a 3140 /// with dictionary records removed. The human-readable signal names are not
QL 0:064c79e7311a 3141 /// available.
QL 0:064c79e7311a 3142 /// \include qs_sigLog0.txt
QL 0:064c79e7311a 3143 #define QS_SIG_DICTIONARY(sig_, obj_) \
QL 0:064c79e7311a 3144 if (((QS::glbFilter_[(uint8_t)QS_SIG_DICTIONARY >> 3U] \
QL 0:064c79e7311a 3145 & (1U << ((uint8_t)QS_SIG_DICTIONARY & 7U))) != 0U)) \
QL 0:064c79e7311a 3146 { \
QL 0:064c79e7311a 3147 static char const Q_ROM Q_ROM_VAR sig_name__[] = #sig_; \
QL 0:064c79e7311a 3148 QS_INT_LOCK_KEY_ \
QL 0:064c79e7311a 3149 QS_INT_LOCK_(); \
QL 0:064c79e7311a 3150 QS::begin((uint8_t)QS_SIG_DICTIONARY); \
QL 0:064c79e7311a 3151 QS_SIG_(sig_); \
QL 0:064c79e7311a 3152 QS_OBJ_(obj_); \
QL 0:064c79e7311a 3153 QS_STR_ROM_(sig_name__); \
QL 0:064c79e7311a 3154 QS::end(); \
QL 0:064c79e7311a 3155 QS_INT_UNLOCK_(); \
QL 0:064c79e7311a 3156 QS::onFlush(); \
QL 0:064c79e7311a 3157 } else ((void)0)
QL 0:064c79e7311a 3158
QL 0:064c79e7311a 3159 /// \brief Output object dictionary record
QL 0:064c79e7311a 3160 ///
QL 0:064c79e7311a 3161 /// An object dictionary record associates the binary address of an object
QL 0:064c79e7311a 3162 /// in the target's memory with the human-readable name of the object.
QL 0:064c79e7311a 3163 ///
QL 0:064c79e7311a 3164 /// Providing an object dictionary QS record can vastly improve readability of
QL 0:064c79e7311a 3165 /// the QS log, because instead of dealing with cryptic machine addresses the
QL 0:064c79e7311a 3166 /// QSpy host utility can display human-readable object names.
QL 0:064c79e7311a 3167 ///
QL 0:064c79e7311a 3168 /// The following example shows the definition of object dictionary entry
QL 0:064c79e7311a 3169 /// for the Table active object:
QL 0:064c79e7311a 3170 /// \include qs_objDic.cpp
QL 0:064c79e7311a 3171 #define QS_OBJ_DICTIONARY(obj_) \
QL 0:064c79e7311a 3172 if (((QS::glbFilter_[(uint8_t)QS_OBJ_DICTIONARY >> 3U] \
QL 0:064c79e7311a 3173 & (1U << ((uint8_t)QS_OBJ_DICTIONARY & 7U))) != 0U)) \
QL 0:064c79e7311a 3174 { \
QL 0:064c79e7311a 3175 static char const Q_ROM Q_ROM_VAR obj_name__[] = #obj_; \
QL 0:064c79e7311a 3176 QS_INT_LOCK_KEY_ \
QL 0:064c79e7311a 3177 QS_INT_LOCK_(); \
QL 0:064c79e7311a 3178 QS::begin((uint8_t)QS_OBJ_DICTIONARY); \
QL 0:064c79e7311a 3179 QS_OBJ_(obj_); \
QL 0:064c79e7311a 3180 QS_STR_ROM_(obj_name__); \
QL 0:064c79e7311a 3181 QS::end(); \
QL 0:064c79e7311a 3182 QS_INT_UNLOCK_(); \
QL 0:064c79e7311a 3183 QS::onFlush(); \
QL 0:064c79e7311a 3184 } else ((void)0)
QL 0:064c79e7311a 3185
QL 0:064c79e7311a 3186 /// \brief Output function dictionary record
QL 0:064c79e7311a 3187 ///
QL 0:064c79e7311a 3188 /// A function dictionary record associates the binary address of a function
QL 0:064c79e7311a 3189 /// in the target's memory with the human-readable name of the function.
QL 0:064c79e7311a 3190 ///
QL 0:064c79e7311a 3191 /// Providing a function dictionary QS record can vastly improve readability
QL 0:064c79e7311a 3192 /// of the QS log, because instead of dealing with cryptic machine addresses
QL 0:064c79e7311a 3193 /// the QSpy host utility can display human-readable function names.
QL 0:064c79e7311a 3194 ///
QL 0:064c79e7311a 3195 /// The example from #QS_SIG_DICTIONARY shows the definition of a function
QL 0:064c79e7311a 3196 /// dictionary.
QL 0:064c79e7311a 3197 #define QS_FUN_DICTIONARY(fun_) \
QL 0:064c79e7311a 3198 if (((QS::glbFilter_[(uint8_t)QS_FUN_DICTIONARY >> 3U] \
QL 0:064c79e7311a 3199 & (1U << ((uint8_t)QS_FUN_DICTIONARY & 7U))) != 0U)) \
QL 0:064c79e7311a 3200 { \
QL 0:064c79e7311a 3201 static char const Q_ROM Q_ROM_VAR fun_name__[] = #fun_; \
QL 0:064c79e7311a 3202 QS_INT_LOCK_KEY_ \
QL 0:064c79e7311a 3203 QS_INT_LOCK_(); \
QL 0:064c79e7311a 3204 QS::begin((uint8_t)QS_FUN_DICTIONARY); \
QL 0:064c79e7311a 3205 QS_FUN_(fun_); \
QL 0:064c79e7311a 3206 QS_STR_ROM_(fun_name__); \
QL 0:064c79e7311a 3207 QS::end(); \
QL 0:064c79e7311a 3208 QS_INT_UNLOCK_(); \
QL 0:064c79e7311a 3209 QS::onFlush(); \
QL 0:064c79e7311a 3210 } else ((void)0)
QL 0:064c79e7311a 3211
QL 0:064c79e7311a 3212 /// \brief Flush the QS trace data to the host
QL 0:064c79e7311a 3213 ///
QL 0:064c79e7311a 3214 /// This macro invokes the QS::flush() platform-dependent callback function
QL 0:064c79e7311a 3215 /// to flush the QS trace buffer to the host. The function typically
QL 0:064c79e7311a 3216 /// busy-waits until all the data in the buffer is sent to the host.
QL 0:064c79e7311a 3217 /// This is acceptable only in the initial transient.
QL 0:064c79e7311a 3218 #define QS_FLUSH() QS::onFlush()
QL 0:064c79e7311a 3219
QL 0:064c79e7311a 3220
QL 0:064c79e7311a 3221 /// \brief Output the interrupt lock record
QL 0:064c79e7311a 3222 #define QF_QS_INT_LOCK() \
QL 0:064c79e7311a 3223 QS_BEGIN_NOLOCK_(QS_QF_INT_LOCK, (void *)0, (void *)0); \
QL 0:064c79e7311a 3224 QS_TIME_(); \
QL 0:064c79e7311a 3225 QS_U8_((uint8_t)(++QF_intLockNest_)); \
QL 0:064c79e7311a 3226 QS_END_NOLOCK_()
QL 0:064c79e7311a 3227
QL 0:064c79e7311a 3228 /// \brief Output the interrupt unlock record
QL 0:064c79e7311a 3229 #define QF_QS_INT_UNLOCK() \
QL 0:064c79e7311a 3230 QS_BEGIN_NOLOCK_(QS_QF_INT_UNLOCK, (void *)0, (void *)0); \
QL 0:064c79e7311a 3231 QS_TIME_(); \
QL 0:064c79e7311a 3232 QS_U8_((uint8_t)(QF_intLockNest_--)); \
QL 0:064c79e7311a 3233 QS_END_NOLOCK_()
QL 0:064c79e7311a 3234
QL 0:064c79e7311a 3235 /// \brief Output the interrupt entry record
QL 0:064c79e7311a 3236 #define QF_QS_ISR_ENTRY(isrnest_, prio_) \
QL 0:064c79e7311a 3237 QS_BEGIN_NOLOCK_(QS_QF_ISR_ENTRY, (void *)0, (void *)0); \
QL 0:064c79e7311a 3238 QS_TIME_(); \
QL 0:064c79e7311a 3239 QS_U8_(isrnest_); \
QL 0:064c79e7311a 3240 QS_U8_(prio_); \
QL 0:064c79e7311a 3241 QS_END_NOLOCK_()
QL 0:064c79e7311a 3242
QL 0:064c79e7311a 3243 /// \brief Output the interrupt exit record
QL 0:064c79e7311a 3244 #define QF_QS_ISR_EXIT(isrnest_, prio_) \
QL 0:064c79e7311a 3245 QS_BEGIN_NOLOCK_(QS_QF_ISR_EXIT, (void *)0, (void *)0); \
QL 0:064c79e7311a 3246 QS_TIME_(); \
QL 0:064c79e7311a 3247 QS_U8_(isrnest_); \
QL 0:064c79e7311a 3248 QS_U8_(prio_); \
QL 0:064c79e7311a 3249 QS_END_NOLOCK_()
QL 0:064c79e7311a 3250
QL 0:064c79e7311a 3251 /// \brief Execute an action that is only necessary for QS output
QL 0:064c79e7311a 3252 #define QF_QS_ACTION(act_) (act_)
QL 0:064c79e7311a 3253
QL 0:064c79e7311a 3254 /// \brief interrupt-lock nesting level
QL 0:064c79e7311a 3255 ///
QL 0:064c79e7311a 3256 /// \note Not to be used by Clients directly, only in ports of QF
QL 0:064c79e7311a 3257 extern uint8_t QF_intLockNest_;
QL 0:064c79e7311a 3258
QL 0:064c79e7311a 3259 // from "qep.h" --------------------------------------------------------------
QL 0:064c79e7311a 3260 #if (Q_SIGNAL_SIZE == 1)
QL 0:064c79e7311a 3261
QL 0:064c79e7311a 3262 /// \brief Internal QS macro to output an unformatted event signal
QL 0:064c79e7311a 3263 /// data element
QL 0:064c79e7311a 3264 /// \note the size of the pointer depends on the macro #Q_SIGNAL_SIZE.
QL 0:064c79e7311a 3265 #define QS_SIG_(sig_) QS::u8_(sig_)
QL 0:064c79e7311a 3266 #elif (Q_SIGNAL_SIZE == 2)
QL 0:064c79e7311a 3267 #define QS_SIG_(sig_) QS::u16_(sig_)
QL 0:064c79e7311a 3268 #elif (Q_SIGNAL_SIZE == 4)
QL 0:064c79e7311a 3269 #define QS_SIG_(sig_) QS::u32_(sig_)
QL 0:064c79e7311a 3270 #endif
QL 0:064c79e7311a 3271
QL 0:064c79e7311a 3272 // from "qf.h" ---------------------------------------------------------------
QL 0:064c79e7311a 3273 #if (QF_EQUEUE_CTR_SIZE == 1)
QL 0:064c79e7311a 3274
QL 0:064c79e7311a 3275 /// \brief Internal QS macro to output an unformatted event queue
QL 0:064c79e7311a 3276 /// counter data element
QL 0:064c79e7311a 3277 /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE.
QL 0:064c79e7311a 3278 #define QS_EQC_(ctr_) QS::u8_(ctr_)
QL 0:064c79e7311a 3279 #elif (QF_EQUEUE_CTR_SIZE == 2)
QL 0:064c79e7311a 3280 #define QS_EQC_(ctr_) QS::u16_(ctr_)
QL 0:064c79e7311a 3281 #elif (QF_EQUEUE_CTR_SIZE == 4)
QL 0:064c79e7311a 3282 #define QS_EQC_(ctr_) QS::u32_(ctr_)
QL 0:064c79e7311a 3283 #else
QL 0:064c79e7311a 3284 #error "QF_EQUEUE_CTR_SIZE not defined"
QL 0:064c79e7311a 3285 #endif
QL 0:064c79e7311a 3286
QL 0:064c79e7311a 3287
QL 0:064c79e7311a 3288 #if (QF_EVENT_SIZ_SIZE == 1)
QL 0:064c79e7311a 3289
QL 0:064c79e7311a 3290 /// \brief Internal QS macro to output an unformatted event size
QL 0:064c79e7311a 3291 /// data element
QL 0:064c79e7311a 3292 /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE.
QL 0:064c79e7311a 3293 #define QS_EVS_(size_) QS::u8_(size_)
QL 0:064c79e7311a 3294 #elif (QF_EVENT_SIZ_SIZE == 2)
QL 0:064c79e7311a 3295 #define QS_EVS_(size_) QS::u16_(size_)
QL 0:064c79e7311a 3296 #elif (QF_EVENT_SIZ_SIZE == 4)
QL 0:064c79e7311a 3297 #define QS_EVS_(size_) QS::u32_(size_)
QL 0:064c79e7311a 3298 #endif
QL 0:064c79e7311a 3299
QL 0:064c79e7311a 3300
QL 0:064c79e7311a 3301 #if (QF_MPOOL_SIZ_SIZE == 1)
QL 0:064c79e7311a 3302
QL 0:064c79e7311a 3303 /// \brief Internal QS macro to output an unformatted memory pool
QL 0:064c79e7311a 3304 /// block-size data element
QL 0:064c79e7311a 3305 /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE.
QL 0:064c79e7311a 3306 #define QS_MPS_(size_) QS::u8_(size_)
QL 0:064c79e7311a 3307 #elif (QF_MPOOL_SIZ_SIZE == 2)
QL 0:064c79e7311a 3308 #define QS_MPS_(size_) QS::u16_(size_)
QL 0:064c79e7311a 3309 #elif (QF_MPOOL_SIZ_SIZE == 4)
QL 0:064c79e7311a 3310 #define QS_MPS_(size_) QS::u32_(size_)
QL 0:064c79e7311a 3311 #endif
QL 0:064c79e7311a 3312
QL 0:064c79e7311a 3313 #if (QF_MPOOL_CTR_SIZE == 1)
QL 0:064c79e7311a 3314
QL 0:064c79e7311a 3315 /// \brief Internal QS macro to output an unformatted memory pool
QL 0:064c79e7311a 3316 /// block-counter data element
QL 0:064c79e7311a 3317 /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE.
QL 0:064c79e7311a 3318 #define QS_MPC_(ctr_) QS::u8_(ctr_)
QL 0:064c79e7311a 3319 #elif (QF_MPOOL_CTR_SIZE == 2)
QL 0:064c79e7311a 3320 #define QS_MPC_(ctr_) QS::u16_(ctr_)
QL 0:064c79e7311a 3321 #elif (QF_MPOOL_CTR_SIZE == 4)
QL 0:064c79e7311a 3322 #define QS_MPC_(ctr_) QS::u32_(ctr_)
QL 0:064c79e7311a 3323 #endif
QL 0:064c79e7311a 3324
QL 0:064c79e7311a 3325
QL 0:064c79e7311a 3326 #if (QF_TIMEEVT_CTR_SIZE == 1)
QL 0:064c79e7311a 3327
QL 0:064c79e7311a 3328 /// \brief Internal QS macro to output an unformatted time event
QL 0:064c79e7311a 3329 /// tick-counter data element
QL 0:064c79e7311a 3330 /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE.
QL 0:064c79e7311a 3331 #define QS_TEC_(ctr_) QS::u8_(ctr_)
QL 0:064c79e7311a 3332 #elif (QF_TIMEEVT_CTR_SIZE == 2)
QL 0:064c79e7311a 3333 #define QS_TEC_(ctr_) QS::u16_(ctr_)
QL 0:064c79e7311a 3334 #elif (QF_TIMEEVT_CTR_SIZE == 4)
QL 0:064c79e7311a 3335 #define QS_TEC_(ctr_) QS::u32_(ctr_)
QL 0:064c79e7311a 3336 #endif
QL 0:064c79e7311a 3337
QL 0:064c79e7311a 3338 #else // Q_SPY
QL 0:064c79e7311a 3339
QL 0:064c79e7311a 3340 // qs_dummy.h ================================================================
QL 0:064c79e7311a 3341
QL 0:064c79e7311a 3342 #define QS_INIT(arg_) ((uint8_t)1)
QL 0:064c79e7311a 3343 #define QS_EXIT() ((void)0)
QL 0:064c79e7311a 3344 #define QS_DUMP() ((void)0)
QL 0:064c79e7311a 3345 #define QS_FILTER_ON(rec_) ((void)0)
QL 0:064c79e7311a 3346 #define QS_FILTER_OFF(rec_) ((void)0)
QL 0:064c79e7311a 3347 #define QS_FILTER_SM_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3348 #define QS_FILTER_AO_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3349 #define QS_FILTER_MP_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3350 #define QS_FILTER_EQ_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3351 #define QS_FILTER_TE_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3352 #define QS_FILTER_AP_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3353
QL 0:064c79e7311a 3354 #define QS_GET_BYTE(pByte_) ((uint16_t)0xFFFF)
QL 0:064c79e7311a 3355 #define QS_GET_BLOCK(pSize_) ((uint8_t *)0)
QL 0:064c79e7311a 3356
QL 0:064c79e7311a 3357 #define QS_BEGIN(rec_, obj_) if (0) {
QL 0:064c79e7311a 3358 #define QS_END() }
QL 0:064c79e7311a 3359 #define QS_BEGIN_NOLOCK(rec_, obj_) if (0) {
QL 0:064c79e7311a 3360 #define QS_END_NOLOCK() }
QL 0:064c79e7311a 3361
QL 0:064c79e7311a 3362 #define QS_I8(width_, data_) ((void)0)
QL 0:064c79e7311a 3363 #define QS_U8(width_, data_) ((void)0)
QL 0:064c79e7311a 3364 #define QS_I16(width_, data_) ((void)0)
QL 0:064c79e7311a 3365 #define QS_U16(width_, data_) ((void)0)
QL 0:064c79e7311a 3366 #define QS_I32(width_, data_) ((void)0)
QL 0:064c79e7311a 3367 #define QS_U32(width_, data_) ((void)0)
QL 0:064c79e7311a 3368 #define QS_F32(width_, data_) ((void)0)
QL 0:064c79e7311a 3369 #define QS_F64(width_, data_) ((void)0)
QL 6:01d57c81e96a 3370 #define QS_U64(width_, data_) ((void)0)
QL 0:064c79e7311a 3371 #define QS_STR(str_) ((void)0)
QL 6:01d57c81e96a 3372 #define QS_U32_HEX(width_, data_) ((void)0)
QL 0:064c79e7311a 3373 #define QS_STR_ROM(str_) ((void)0)
QL 0:064c79e7311a 3374 #define QS_MEM(mem_, size_) ((void)0)
QL 0:064c79e7311a 3375 #define QS_SIG(sig_, obj_) ((void)0)
QL 0:064c79e7311a 3376 #define QS_OBJ(obj_) ((void)0)
QL 0:064c79e7311a 3377 #define QS_FUN(fun_) ((void)0)
QL 0:064c79e7311a 3378
QL 0:064c79e7311a 3379 #define QS_SIG_DICTIONARY(sig_, obj_) ((void)0)
QL 0:064c79e7311a 3380 #define QS_OBJ_DICTIONARY(obj_) ((void)0)
QL 0:064c79e7311a 3381 #define QS_FUN_DICTIONARY(fun_) ((void)0)
QL 0:064c79e7311a 3382 #define QS_FLUSH() ((void)0)
QL 0:064c79e7311a 3383
QL 0:064c79e7311a 3384 // internal QS macros used only in the QP components .........................
QL 0:064c79e7311a 3385 #define QS_INT_LOCK_KEY_
QL 0:064c79e7311a 3386 #define QS_BEGIN_(rec_, refObj_, obj_) if (0) {
QL 0:064c79e7311a 3387 #define QS_END_() }
QL 0:064c79e7311a 3388 #define QS_BEGIN_NOLOCK_(rec_, refObj_, obj_) if (0) {
QL 0:064c79e7311a 3389 #define QS_END_NOLOCK_() }
QL 0:064c79e7311a 3390 #define QS_U8_(data_) ((void)0)
QL 0:064c79e7311a 3391 #define QS_U16_(data_) ((void)0)
QL 0:064c79e7311a 3392 #define QS_U32_(data_) ((void)0)
QL 6:01d57c81e96a 3393 #define QS_U64_(data_) ((void)0)
QL 0:064c79e7311a 3394 #define QS_TIME_() ((void)0)
QL 0:064c79e7311a 3395 #define QS_SIG_(sig_) ((void)0)
QL 0:064c79e7311a 3396 #define QS_EVS_(size_) ((void)0)
QL 0:064c79e7311a 3397 #define QS_OBJ_(obj_) ((void)0)
QL 0:064c79e7311a 3398 #define QS_FUN_(fun_) ((void)0)
QL 0:064c79e7311a 3399 #define QS_EQC_(ctr_) ((void)0)
QL 0:064c79e7311a 3400 #define QS_MPC_(ctr_) ((void)0)
QL 0:064c79e7311a 3401 #define QS_MPS_(size_) ((void)0)
QL 0:064c79e7311a 3402 #define QS_TEC_(ctr_) ((void)0)
QL 0:064c79e7311a 3403
QL 0:064c79e7311a 3404 #define QF_QS_INT_LOCK() ((void)0)
QL 0:064c79e7311a 3405 #define QF_QS_INT_UNLOCK() ((void)0)
QL 0:064c79e7311a 3406 #define QF_QS_ISR_ENTRY(isrnest_, prio_) ((void)0)
QL 0:064c79e7311a 3407 #define QF_QS_ISR_EXIT(isrnest_, prio_) ((void)0)
QL 0:064c79e7311a 3408 #define QF_QS_ACTION(act_) ((void)0)
QL 0:064c79e7311a 3409
QL 0:064c79e7311a 3410 #endif // Q_SPY
QL 0:064c79e7311a 3411
QL 6:01d57c81e96a 3412 #ifdef Q_USE_NAMESPACE
QL 6:01d57c81e96a 3413 } // namespace QP
QL 6:01d57c81e96a 3414 #endif
QL 6:01d57c81e96a 3415
QL 0:064c79e7311a 3416 //////////////////////////////////////////////////////////////////////////////
QL 0:064c79e7311a 3417 /**
QL 0:064c79e7311a 3418 * \brief Customizable QP assertions.
QL 0:064c79e7311a 3419 *
QL 0:064c79e7311a 3420 * Defines customizable and memory-efficient assertions applicable to
QL 0:064c79e7311a 3421 * embedded systems. This header file can be used in C, C++, and mixed C/C++
QL 0:064c79e7311a 3422 * programs.
QL 0:064c79e7311a 3423 *
QL 0:064c79e7311a 3424 * \note The preprocessor switch Q_NASSERT disables checking assertions.
QL 6:01d57c81e96a 3425 * In particular macros #Q_ASSERT, #Q_REQUIRE, #Q_ENSURE, #Q_INVARIANT,
QL 6:01d57c81e96a 3426 * #Q_ERROR as well as #Q_ASSERT_ID, #Q_REQUIRE_ID, #Q_ENSURE_ID,
QL 6:01d57c81e96a 3427 * #Q_INVARIANT_ID, and #Q_ERROR_ID do NOT evaluate the test condition
QL 0:064c79e7311a 3428 * passed as the argument to these macros. One notable exception is the
QL 6:01d57c81e96a 3429 * macro #Q_ALLEGE, that still evaluates the test condition, but does
QL 0:064c79e7311a 3430 * not report assertion failures when the switch Q_NASSERT is defined.
QL 0:064c79e7311a 3431 */
QL 0:064c79e7311a 3432 #ifdef Q_NASSERT /* Q_NASSERT defined--assertion checking disabled */
QL 0:064c79e7311a 3433
QL 0:064c79e7311a 3434 #define Q_DEFINE_THIS_FILE
QL 0:064c79e7311a 3435 #define Q_DEFINE_THIS_MODULE(name_)
QL 6:01d57c81e96a 3436 #define Q_ASSERT(test_) ((void)0)
QL 6:01d57c81e96a 3437 #define Q_ASSERT_ID(id_, test_) ((void)0)
QL 6:01d57c81e96a 3438 #define Q_ALLEGE(test_) ((void)(test_))
QL 6:01d57c81e96a 3439 #define Q_ALLEGE_ID(id_, test_) ((void)(test_))
QL 6:01d57c81e96a 3440 #define Q_ERROR() ((void)0)
QL 6:01d57c81e96a 3441 #define Q_ERROR_ID(id_) ((void)0)
QL 0:064c79e7311a 3442
QL 0:064c79e7311a 3443 #else /* Q_NASSERT not defined--assertion checking enabled */
QL 0:064c79e7311a 3444
QL 0:064c79e7311a 3445 #ifdef __cplusplus
QL 0:064c79e7311a 3446 extern "C" {
QL 0:064c79e7311a 3447 #endif
QL 0:064c79e7311a 3448
QL 6:01d57c81e96a 3449 /** callback invoked in case the condition passed to #Q_ASSERT,
QL 6:01d57c81e96a 3450 * #Q_REQUIRE, #Q_ENSURE, #Q_ERROR, #Q_ALLEGE as well as #Q_ASSERT_ID,
QL 6:01d57c81e96a 3451 * #Q_REQUIRE_ID, #Q_ENSURE_ID, #Q_ERROR_ID, and #Q_ALLEGE_ID evaluates
QL 6:01d57c81e96a 3452 * to FALSE.
QL 0:064c79e7311a 3453 *
QL 0:064c79e7311a 3454 * \param file file name where the assertion failed
QL 0:064c79e7311a 3455 * \param line line number at which the assertion failed
QL 0:064c79e7311a 3456 */
QL 0:064c79e7311a 3457 /*lint -sem(Q_onAssert, r_no) Q_onAssert() never returns */
QL 0:064c79e7311a 3458 void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line);
QL 0:064c79e7311a 3459
QL 0:064c79e7311a 3460 #ifdef __cplusplus
QL 0:064c79e7311a 3461 }
QL 0:064c79e7311a 3462 #endif
QL 0:064c79e7311a 3463
QL 0:064c79e7311a 3464 /** Place this macro at the top of each C/C++ module to define the file
QL 0:064c79e7311a 3465 * name string using __FILE__ (NOTE: __FILE__ might contain lengthy path
QL 0:064c79e7311a 3466 * name). This file name will be used in reporting assertions in this file.
QL 0:064c79e7311a 3467 */
QL 0:064c79e7311a 3468 #define Q_DEFINE_THIS_FILE \
QL 0:064c79e7311a 3469 static char const Q_ROM Q_ROM_VAR l_this_file[] = __FILE__;
QL 0:064c79e7311a 3470
QL 0:064c79e7311a 3471 /** Place this macro at the top of each C/C++ module to define the module
QL 0:064c79e7311a 3472 * name as the argument \a name_. This file name will be used in reporting
QL 0:064c79e7311a 3473 * assertions in this file.
QL 0:064c79e7311a 3474 */
QL 0:064c79e7311a 3475 #define Q_DEFINE_THIS_MODULE(name_) \
QL 0:064c79e7311a 3476 static char const Q_ROM Q_ROM_VAR l_this_file[] = #name_;
QL 0:064c79e7311a 3477
QL 0:064c79e7311a 3478 /** General purpose assertion that makes sure the \a test_ argument is
QL 0:064c79e7311a 3479 * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates
QL 0:064c79e7311a 3480 * to FALSE.
QL 6:01d57c81e96a 3481 * \note the \a test_ is NOT evaluated if assertions are disabled with
QL 6:01d57c81e96a 3482 * the Q_NASSERT switch.
QL 6:01d57c81e96a 3483 * \sa #Q_ASSERT_ID
QL 0:064c79e7311a 3484 */
QL 0:064c79e7311a 3485 #define Q_ASSERT(test_) \
QL 0:064c79e7311a 3486 if (test_) { \
QL 0:064c79e7311a 3487 } \
QL 6:01d57c81e96a 3488 else (Q_onAssert(&l_this_file[0], __LINE__))
QL 6:01d57c81e96a 3489
QL 6:01d57c81e96a 3490 /** General purpose assertion that makes sure the \a test_ argument is
QL 6:01d57c81e96a 3491 * TRUE. Calls the Q_onAssert() callback if the \a test_ evaluates
QL 6:01d57c81e96a 3492 * to FALSE. The argument \a id_ is the ID number (unique within
QL 6:01d57c81e96a 3493 * the file) of the assertion. This assertion style is better suited
QL 6:01d57c81e96a 3494 * for unit testig, because it avoids the volatility of line numbers
QL 6:01d57c81e96a 3495 * for indentifying assertions.
QL 6:01d57c81e96a 3496 * \note the \a test_ is NOT evaluated if assertions are disabled with
QL 6:01d57c81e96a 3497 * the Q_NASSERT switch.
QL 6:01d57c81e96a 3498 * \sa #Q_ASSERT
QL 6:01d57c81e96a 3499 */
QL 6:01d57c81e96a 3500 #define Q_ASSERT_ID(id_, test_) \
QL 6:01d57c81e96a 3501 if (test_) { \
QL 6:01d57c81e96a 3502 } \
QL 6:01d57c81e96a 3503 else (Q_onAssert(&l_this_file[0], (id_)))
QL 0:064c79e7311a 3504
QL 0:064c79e7311a 3505 /** General purpose assertion that ALWAYS evaluates the \a test_
QL 0:064c79e7311a 3506 * argument and calls the Q_onAssert() callback if the \a test_
QL 0:064c79e7311a 3507 * evaluates to FALSE.
QL 6:01d57c81e96a 3508 * \note the \a test_ argument IS always evaluated even when assertions
QL 6:01d57c81e96a 3509 * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is
QL 0:064c79e7311a 3510 * defined, the Q_onAssert() callback is NOT called, even if the
QL 0:064c79e7311a 3511 * \a test_ evaluates to FALSE.
QL 6:01d57c81e96a 3512 * \sa #Q_ALLEGE_ID
QL 0:064c79e7311a 3513 */
QL 0:064c79e7311a 3514 #define Q_ALLEGE(test_) Q_ASSERT(test_)
QL 0:064c79e7311a 3515
QL 6:01d57c81e96a 3516 /** General purpose assertion that ALWAYS evaluates the \a test_
QL 6:01d57c81e96a 3517 * argument and calls the Q_onAssert() callback if the \a test_
QL 6:01d57c81e96a 3518 * evaluates to FALSE. This assertion style is better suited
QL 6:01d57c81e96a 3519 * for unit testig, because it avoids the volatility of line numbers
QL 6:01d57c81e96a 3520 * for indentifying assertions.
QL 6:01d57c81e96a 3521 * \note the \a test_ argument IS always evaluated even when assertions
QL 6:01d57c81e96a 3522 * are disabled with the Q_NASSERT macro. When the Q_NASSERT macro is
QL 6:01d57c81e96a 3523 * defined, the Q_onAssert() callback is NOT called, even if the
QL 6:01d57c81e96a 3524 * \a test_ evaluates to FALSE.
QL 6:01d57c81e96a 3525 * \sa #Q_ALLEGE
QL 6:01d57c81e96a 3526 */
QL 6:01d57c81e96a 3527 #define Q_ALLEGE_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 6:01d57c81e96a 3528
QL 0:064c79e7311a 3529 /** Assertion that always calls the Q_onAssert() callback if
QL 0:064c79e7311a 3530 * ever executed.
QL 0:064c79e7311a 3531 * \note can be disabled with the Q_NASSERT switch.
QL 6:01d57c81e96a 3532 * \sa #Q_ERROR_ID
QL 0:064c79e7311a 3533 */
QL 0:064c79e7311a 3534 #define Q_ERROR() \
QL 0:064c79e7311a 3535 (Q_onAssert(l_this_file, __LINE__))
QL 0:064c79e7311a 3536
QL 6:01d57c81e96a 3537 /** Assertion that always calls the Q_onAssert() callback if
QL 6:01d57c81e96a 3538 * ever executed. This assertion style is better suited for unit
QL 6:01d57c81e96a 3539 * testig, because it avoids the volatility of line numbers for
QL 6:01d57c81e96a 3540 * indentifying assertions.
QL 6:01d57c81e96a 3541 * \note can be disabled with the Q_NASSERT switch.
QL 6:01d57c81e96a 3542 * \sa #Q_ERROR
QL 6:01d57c81e96a 3543 */
QL 6:01d57c81e96a 3544 #define Q_ERROR_ID(id_) \
QL 6:01d57c81e96a 3545 (Q_onAssert(l_this_file, (id_)))
QL 6:01d57c81e96a 3546
QL 6:01d57c81e96a 3547
QL 0:064c79e7311a 3548 #endif /* Q_NASSERT */
QL 0:064c79e7311a 3549
QL 0:064c79e7311a 3550 /** Assertion that checks for a precondition. This macro is equivalent to
QL 6:01d57c81e96a 3551 * #Q_ASSERT, except the name provides a better documentation of the
QL 0:064c79e7311a 3552 * intention of this assertion.
QL 6:01d57c81e96a 3553 * \sa #Q_REQUIRE_ID
QL 0:064c79e7311a 3554 */
QL 6:01d57c81e96a 3555 #define Q_REQUIRE(test_) Q_ASSERT(test_)
QL 6:01d57c81e96a 3556
QL 6:01d57c81e96a 3557 /** Assertion that checks for a precondition. This macro is equivalent to
QL 6:01d57c81e96a 3558 * #Q_ASSERT_ID, except the name provides a better documentation of the
QL 6:01d57c81e96a 3559 * intention of this assertion.
QL 6:01d57c81e96a 3560 * \sa #Q_REQUIRE
QL 6:01d57c81e96a 3561 */
QL 6:01d57c81e96a 3562 #define Q_REQUIRE_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 0:064c79e7311a 3563
QL 0:064c79e7311a 3564 /** Assertion that checks for a postcondition. This macro is equivalent to
QL 6:01d57c81e96a 3565 * #Q_ASSERT, except the name provides a better documentation of the
QL 0:064c79e7311a 3566 * intention of this assertion.
QL 6:01d57c81e96a 3567 * \sa #Q_ENSURE_ID
QL 0:064c79e7311a 3568 */
QL 6:01d57c81e96a 3569 #define Q_ENSURE(test_) Q_ASSERT(test_)
QL 6:01d57c81e96a 3570
QL 6:01d57c81e96a 3571 /** Assertion that checks for a postcondition. This macro is equivalent to
QL 6:01d57c81e96a 3572 * #Q_ASSERT_ID, except the name provides a better documentation of the
QL 6:01d57c81e96a 3573 * intention of this assertion.
QL 6:01d57c81e96a 3574 * \sa #Q_ENSURE
QL 6:01d57c81e96a 3575 */
QL 6:01d57c81e96a 3576 #define Q_ENSURE_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 0:064c79e7311a 3577
QL 0:064c79e7311a 3578 /** Assertion that checks for an invariant. This macro is equivalent to
QL 6:01d57c81e96a 3579 * #Q_ASSERT, except the name provides a better documentation of the
QL 0:064c79e7311a 3580 * intention of this assertion.
QL 6:01d57c81e96a 3581 * \sa #Q_INVARIANT_ID
QL 0:064c79e7311a 3582 */
QL 6:01d57c81e96a 3583 #define Q_INVARIANT(test_) Q_ASSERT(test_)
QL 6:01d57c81e96a 3584
QL 6:01d57c81e96a 3585 /** Assertion that checks for an invariant. This macro is equivalent to
QL 6:01d57c81e96a 3586 * #Q_ASSERT_ID, except the name provides a better documentation of the
QL 6:01d57c81e96a 3587 * intention of this assertion.
QL 6:01d57c81e96a 3588 * \sa #Q_INVARIANT
QL 6:01d57c81e96a 3589 */
QL 6:01d57c81e96a 3590 #define Q_INVARIANT_ID(id_, test_) Q_ASSERT_ID(id_, test_)
QL 0:064c79e7311a 3591
QL 0:064c79e7311a 3592 /** Compile-time assertion exploits the fact that in C/C++ a dimension of
QL 0:064c79e7311a 3593 * an array cannot be negative. The following declaration causes a compilation
QL 0:064c79e7311a 3594 * error if the compile-time expression (\a test_) is not TRUE. The assertion
QL 0:064c79e7311a 3595 * has no runtime side effects.
QL 0:064c79e7311a 3596 */
QL 0:064c79e7311a 3597 #define Q_ASSERT_COMPILE(test_) \
QL 0:064c79e7311a 3598 extern char Q_assert_compile[(test_) ? 1 : -1]
QL 0:064c79e7311a 3599
QL 0:064c79e7311a 3600 #endif // qp_h