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

Dependents:   qp_hangman qp_dpp qp_blinky

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

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

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

Committer:
QL
Date:
Tue Feb 22 15:35:14 2011 +0000
Revision:
4:156463fbfae6
Parent:
0:064c79e7311a
Child:
5:949864ba515c
4.1.06b

Who changed what in which revision?

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