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 03:27:09 2011 +0000
Revision:
8:934bb9eea80b
Parent:
7:bf92d3a6625e
Child:
9:ca2e6010d9e2
4.2.04

Who changed what in which revision?

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