QP/C++ 8.1.1
Real-Time Event Framework
Loading...
Searching...
No Matches
qf_qact.cpp
Go to the documentation of this file.
1//============================================================================
2// QP/C++ Real-Time Event Framework (RTEF)
3//
4// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
5//
6// Q u a n t u m L e a P s
7// ------------------------
8// Modern Embedded Software
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
11//
12// This software is dual-licensed under the terms of the open-source GNU
13// General Public License (GPL) or under the terms of one of the closed-
14// source Quantum Leaps commercial licenses.
15//
16// Redistributions in source code must retain this top-level comment block.
17// Plagiarizing this software to sidestep the license obligations is illegal.
18//
19// NOTE:
20// The GPL does NOT permit the incorporation of this code into proprietary
21// programs. Please contact Quantum Leaps for commercial licensing options,
22// which expressly supersede the GPL and are designed explicitly for
23// closed-source distribution.
24//
25// Quantum Leaps contact information:
26// <www.state-machine.com/licensing>
27// <info@state-machine.com>
28//============================================================================
29#define QP_IMPL // this is QP implementation
30#include "qp_port.hpp" // QP port
31#include "qp_pkg.hpp" // QP package-scope interface
32#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
33#ifdef Q_SPY // QS software tracing enabled?
34 #include "qs_port.hpp" // QS port
35 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
36#else
37 #include "qs_dummy.hpp" // disable the QS software tracing
38#endif // Q_SPY
39
40// unnamed namespace for local definitions with internal linkage
41namespace {
42Q_DEFINE_THIS_MODULE("qf_qact")
43} // unnamed namespace
44
45namespace QP {
46
47std::array<QActive*, QF_MAX_ACTIVE + 1U> QActive_registry_;
48
49//----------------------------------------------------------------------------
50namespace QF {
52} // namespace QF
53
54//----------------------------------------------------------------------------
55QActive::QActive(QStateHandler const initial) noexcept
56 : QAsm(),
57 m_prio(0U),
58 m_pthre(0U)
59{
60 // NOTE: QActive indirectly inherits the abstract QAsm base class,
61 // but it will delegate the state machine behavior to the QHsm class,
62 // so the following initiaization is identical as in QHsm ctor:
63 m_state.fun = Q_STATE_CAST(&top);
64 m_temp.fun = initial;
65}
66
67//............................................................................
68void QActive::register_() noexcept {
71
72 if (m_pthre == 0U) { // preemption-threshold not defined?
73 m_pthre = m_prio; // apply the default
74 }
75
76 // AO's prio. must be in range
77 Q_REQUIRE_INCRIT(100, (0U < m_prio) && (m_prio <= QF_MAX_ACTIVE));
78
79 // the AO must NOT be registered already
81
82 // the AO's prio. must not exceed the preemption threshold
84
85#ifndef Q_UNSAFE
86 std::uint8_t prev_thre = m_pthre;
87 std::uint8_t next_thre = m_pthre;
88
89 for (std::uint8_t p = m_prio - 1U; p > 0U; --p) {
90 if (QActive_registry_[p] != nullptr) {
91 prev_thre = QActive_registry_[p]->m_pthre;
92 break;
93 }
94 }
95 for (std::uint8_t p = m_prio + 1U; p <= QF_MAX_ACTIVE; ++p) {
96 if (QActive_registry_[p] != nullptr) {
97 next_thre = QActive_registry_[p]->m_pthre;
98 break;
99 }
100 }
101
102 // the preemption threshold of this AO must be between
103 // preemption threshold of the previous AO and next AO
104 Q_ASSERT_INCRIT(160,
105 (prev_thre <= m_pthre) && (m_pthre <= next_thre));
106
107#endif // Q_UNSAFE
108
109 // register the AO at the QF-prio.
111
112 QF_CRIT_EXIT();
113}
114
115//............................................................................
116void QActive::unregister_() noexcept {
119
120 std::uint8_t const p = m_prio; // put AO's prio. in a temporary
121
122 // AO's prio. must be in range
123 Q_REQUIRE_INCRIT(210, (0U < p) && (p <= QF_MAX_ACTIVE));
124
125 // this AO must be registered at prio. p
126 Q_REQUIRE_INCRIT(230, QActive_registry_[p] == this);
127
128 m_state.fun = nullptr; // invalidate the state
129 QActive_registry_[p] = nullptr; // free-up the prio. level
130
131 QF_CRIT_EXIT();
132}
133//............................................................................
135 void const * const e,
136 std::uint_fast8_t const qsId)
137{
138 // delegate to the QHsm class
139 reinterpret_cast<QHsm *>(this)->QHsm::init(e, qsId);
140}
141//............................................................................
143 QEvt const * const e,
144 std::uint_fast8_t const qsId)
145{
146 // delegate to the QHsm class
147 reinterpret_cast<QHsm *>(this)->QHsm::dispatch(e, qsId);
148}
149//............................................................................
150bool QActive::isIn(QStateHandler const stateHndl) noexcept {
151 // delegate to the QHsm class
152 return reinterpret_cast<QHsm *>(this)->QHsm::isIn(stateHndl);
153}
154//............................................................................
155QStateHandler QActive::childState(QStateHandler const parentHandler) noexcept {
156 // delegate to the QHsm class
157 return reinterpret_cast<QHsm *>(this)->QHsm::childState(parentHandler);
158}
159//............................................................................
160QActive* QActive::fromRegistry(std::uint_fast8_t const prio) {
161 // return the hidden (package scope) registry entry
162 return QActive_registry_[prio];
163}
164//............................................................................
166 // delegate to the QHsm class
167 return reinterpret_cast<QHsm const *>(this)->QHsm::getStateHandler();
168}
169
170//----------------------------------------------------------------------------
171#ifndef QF_LOG2
172std::uint_fast8_t QF_LOG2(QP::QPSetBits const bitmask) noexcept {
173 // look-up table for log2(0..15)
174 static constexpr std::array<std::uint8_t, 16> log2LUT = {
175 0U, 1U, 2U, 2U, 3U, 3U, 3U, 3U,
176 4U, 4U, 4U, 4U, 4U, 4U, 4U, 4U
177 };
178 std::uint_fast8_t n = 0U;
179 QP::QPSetBits x = bitmask;
180 QP::QPSetBits tmp; // temporary for modified bitmask parameter
181
182#if (QF_MAX_ACTIVE > 16U)
183 tmp = static_cast<QP::QPSetBits>(x >> 16U);
184 if (tmp != 0U) { // x > 2^16?
185 n += 16U;
186 x = tmp;
187 }
188#endif
189#if (QF_MAX_ACTIVE > 8U)
190 tmp = (x >> 8U);
191 if (tmp != 0U) { // x > 2^8?
192 n += 8U;
193 x = tmp;
194 }
195#endif
196 tmp = (x >> 4U);
197 if (tmp != 0U) { // x > 2^4?
198 n += 4U;
199 x = tmp;
200 }
201 // x is guaranteed to be in the 0..15 range for the look-up
202 return static_cast<std::uint_fast8_t>(n + log2LUT[x]);
203}
204#endif // ndef QF_LOG2
205
206//----------------------------------------------------------------------------
207void QPSet::setEmpty() noexcept {
208 m_bits0 = 0U; // clear bitmask for elements 1..32
209#if (QF_MAX_ACTIVE > 32U)
210 m_bits1 = 0U; // clear bitmask for elements 33..64
211#endif
212}
213//............................................................................
214bool QPSet::isEmpty() const noexcept {
215#if (QF_MAX_ACTIVE <= 32U)
216 return (m_bits0 == 0U); // check only bitmask for elements 1..32
217#else
218 return (m_bits0 == 0U) // bitmask for elements 1..32 empty?
219 ? (m_bits1 == 0U) // check bitmask for for elements 33..64
220 : false; // the set is NOT empty
221#endif
222}
223//............................................................................
224bool QPSet::notEmpty() const noexcept {
225#if (QF_MAX_ACTIVE <= 32U)
226 return (m_bits0 != 0U); // check only bitmask for elements 1..32
227#else
228 return (m_bits0 != 0U) // bitmask for elements 1..32 empty?
229 ? true // the set is NOT empty
230 : (m_bits1 != 0U); // check bitmask for for elements 33..64
231#endif
232}
233//............................................................................
234bool QPSet::hasElement(std::uint_fast8_t const n) const noexcept {
235#if (QF_MAX_ACTIVE <= 32U)
236 // check the bit only in bitmask for elements 1..32
237 return (m_bits0 & (static_cast<QPSetBits>(1U) << (n - 1U))) != 0U;
238#else
239 return (n <= 32U) // which group of elements (1..32 or 33..64)?
240 ? ((m_bits0 & (static_cast<QPSetBits>(1U) << (n - 1U))) != 0U)
241 : ((m_bits1 & (static_cast<QPSetBits>(1U) << (n - 33U))) != 0U);
242#endif
243}
244//............................................................................
245void QPSet::insert(std::uint_fast8_t const n) noexcept {
246#if (QF_MAX_ACTIVE <= 32U)
247 // set the bit only in bitmask for elements 1..32
248 m_bits0 = (m_bits0 | (static_cast<QPSetBits>(1U) << (n - 1U)));
249#else
250 if (n <= 32U) { // set the bit in the bitmask for elements 1..32?
251 m_bits0 = (m_bits0 | (static_cast<QPSetBits>(1U) << (n - 1U)));
252 }
253 else { // set the bit in the bitmask for for elements 33..64
254 m_bits1 = (m_bits1 | (static_cast<QPSetBits>(1U) << (n - 33U)));
255 }
256#endif
257}
258//............................................................................
259void QPSet::remove(std::uint_fast8_t const n) noexcept {
260#if (QF_MAX_ACTIVE <= 32U)
261 // clear the bit only in bitmask for elements 1..32
262 m_bits0 = (m_bits0 & static_cast<QPSetBits>(~(1U << (n - 1U))));
263#else
264 if (n <= 32U) { // clear the bit in the bitmask for elements 1..32?
265 (m_bits0 = (m_bits0 & ~(static_cast<QPSetBits>(1U) << (n - 1U))));
266 }
267 else { // clear the bit in the bitmask for for elements 33..64
268 (m_bits1 = (m_bits1 & ~(static_cast<QPSetBits>(1U) << (n - 33U))));
269 }
270#endif
271}
272//............................................................................
273std::uint_fast8_t QPSet::findMax() const noexcept {
274#if (QF_MAX_ACTIVE <= 32U)
275 // check only the bitmask for elements 1..32
276 return QF_LOG2(m_bits0);
277#else
278 return (m_bits1 != 0U) // bitmask for elements 32..64 not empty?
279 ? (32U + QF_LOG2(m_bits1)) // 32 + log2(bits 33..64)
280 : (QF_LOG2(m_bits0)); // log2(bits 1..32)
281#endif
282}
283
284} // namespace QP
void unregister_() noexcept
Un-register the active object from the framework.
Definition qf_qact.cpp:116
void register_() noexcept
Register this active object to be managed by the framework.
Definition qf_qact.cpp:68
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Virtual function to dispatch an event to the state machine.
Definition qf_qact.cpp:142
friend void QF::init()
bool isIn(QStateHandler const stateHndl) noexcept override
Virtual function to check whether the state machine is in a given state.
Definition qf_qact.cpp:150
static QActive * fromRegistry(std::uint_fast8_t const prio)
Definition qf_qact.cpp:160
QActive(QStateHandler const initial) noexcept
QActive constructor (abstract base class).
Definition qf_qact.cpp:55
QStateHandler childState(QStateHandler const parentHandler) noexcept
Definition qf_qact.cpp:155
QStateHandler getStateHandler() const noexcept override
Virtual method for getting the current state handler.
Definition qf_qact.cpp:165
std::uint8_t m_pthre
Preemption-threshold [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:491
std::uint8_t m_prio
QF-priority [1..QF_MAX_ACTIVE] of this AO.
Definition qp.hpp:490
QAsm() noexcept
Constructor of the QP::QAsm base class.
Definition qf_act.cpp:75
QAsmAttr m_temp
Temporary storage for target/act-table etc.
Definition qp.hpp:170
QAsmAttr m_state
Current state (pointer to the current state-handler function).
Definition qp.hpp:169
static QState top(void *const me, QEvt const *const e) noexcept
Top state handler that ignores all events.
Definition qf_act.cpp:80
Event class.
Definition qp.hpp:101
Private attributes of the QF framework.
Definition qp_pkg.hpp:79
Hierarchical State Machine class (QHsm-style state machine implementation strategy).
Definition qp.hpp:299
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Virtual function to dispatch an event to the state machine.
Definition qep_hsm.cpp:230
QStateHandler childState(QStateHandler const parentHndl) noexcept
Obtain the current active child state of a given parent in QP::QMsm.
Definition qep_hsm.cpp:572
void init(void const *const e, std::uint_fast8_t const qsId) override
Virtual function to take the top-most initial transition in the state machine.
Definition qep_hsm.cpp:154
bool isIn(QStateHandler const stateHndl) noexcept override
Check whether the HSM is in a given state.
Definition qep_hsm.cpp:542
QStateHandler getStateHandler() const noexcept override
Virtual method for getting the current state handler.
Definition qep_hsm.cpp:603
std::uint_fast8_t findMax() const noexcept
Find the maximum element in the set.
Definition qf_qact.cpp:273
void remove(std::uint_fast8_t const n) noexcept
Remove element n from the priority-set (n = 1..QF_MAX_ACTIVE).
Definition qf_qact.cpp:259
QPSetBits m_bits1
Bitmask for elements 33..64.
Definition qp.hpp:447
bool notEmpty() const noexcept
Find out whether the priority-set is NOT empty.
Definition qf_qact.cpp:224
bool hasElement(std::uint_fast8_t const n) const noexcept
Find out whether the priority-set has element n.
Definition qf_qact.cpp:234
QPSetBits m_bits0
Bitmask for elements 1..32.
Definition qp.hpp:445
void setEmpty() noexcept
Make the priority set empty.
Definition qf_qact.cpp:207
bool isEmpty() const noexcept
Find out whether the priority-set is empty.
Definition qf_qact.cpp:214
void insert(std::uint_fast8_t const n) noexcept
Insert element n into the priority-set (n = 1..QF_MAX_ACTIVE).
Definition qf_qact.cpp:245
QF Active Object Framework namespace.
Definition qp.hpp:476
QF::Attr priv_
Definition qf_qact.cpp:51
QP/C++ Framework namespace.
Definition qequeue.hpp:36
std::uint_fast8_t QF_LOG2(QP::QPSetBits const bitmask) noexcept
Definition qf_qact.cpp:172
QState(*)(void *const me, QEvt const *const e) QStateHandler
Pointer to a state-handler function.
Definition qp.hpp:138
std::array< QActive *, QF_MAX_ACTIVE+1U > QActive_registry_
Internal array of pointers to the registered Active Objects.
Definition qf_qact.cpp:47
std::uint32_t QPSetBits
Bitmask for the internal representation of QPSet elements.
Definition qp.hpp:435
#define Q_STATE_CAST(handler_)
Perform cast to QP::QStateHandler.
Definition qp.hpp:385
#define QF_MAX_ACTIVE
Maximum # Active Objects in the system (1..64).
Definition qp_config.hpp:98
QP Framework in C++ internal (package-scope) interface
Sample QP/C++ port.
QS (QP/Spy software tracing) internal (package-scope) interface.
Sample QS/C++ port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:40
#define Q_ASSERT_INCRIT(id_, expr_)
General-purpose assertion with user-specified ID number (in critical section).
Definition qsafe.h:54
#define QF_CRIT_EXIT()
Definition qsafe.h:44
#define Q_REQUIRE_INCRIT(id_, expr_)
Assertion for checking a precondition (in critical section).
Definition qsafe.h:98
#define QF_CRIT_STAT
Definition qsafe.h:36