QP/C++  7.3.3
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qf_actq.cpp
Go to the documentation of this file.
1//$file${src::qf::qf_actq.cpp} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpcpp.qm
4// File: ${src::qf::qf_actq.cpp}
5//
6// This code has been generated by QM 6.1.1 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// This code is covered by the following QP license:
10// License # : LicenseRef-QL-dual
11// Issued to : Any user of the QP/C++ real-time embedded framework
12// Framework(s) : qpcpp
13// Support ends : 2024-12-31
14// License scope:
15//
16// Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
17//
18// Q u a n t u m L e a P s
19// ------------------------
20// Modern Embedded Software
21//
22// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
23//
24// This software is dual-licensed under the terms of the open source GNU
25// General Public License version 3 (or any later version), or alternatively,
26// under the terms of one of the closed source Quantum Leaps commercial
27// licenses.
28//
29// The terms of the open source GNU General Public License version 3
30// can be found at: <www.gnu.org/licenses/gpl-3.0>
31//
32// The terms of the closed source Quantum Leaps commercial licenses
33// can be found at: <www.state-machine.com/licensing>
34//
35// Redistributions in source code must retain this top-level comment block.
36// Plagiarizing this software to sidestep the license obligations is illegal.
37//
38// Contact information:
39// <www.state-machine.com/licensing>
40// <info@state-machine.com>
41//
42//$endhead${src::qf::qf_actq.cpp} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43#define QP_IMPL // this is QP implementation
44#include "qp_port.hpp" // QP port
45#include "qp_pkg.hpp" // QP package-scope interface
46#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
47#ifdef Q_SPY // QS software tracing enabled?
48 #include "qs_port.hpp" // QS port
49 #include "qs_pkg.hpp" // QS facilities for pre-defined trace records
50#else
51 #include "qs_dummy.hpp" // disable the QS software tracing
52#endif // Q_SPY
53
54//============================================================================
55// unnamed namespace for local definitions with internal linkage
56namespace {
57Q_DEFINE_THIS_MODULE("qf_actq")
58} // unnamed namespace
59
60//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
61// Check for the minimum required QP version
62#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U) % 0x3E8U))
63#error qpcpp version 7.3.0 or higher required
64#endif
65//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
67//$define${QF::QActive::post_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
68namespace QP {
69
70//${QF::QActive::post_} ......................................................
72 QEvt const * const e,
73 std::uint_fast16_t const margin,
74 void const * const sender) noexcept
75{
76 #ifndef Q_SPY
77 Q_UNUSED_PAR(sender);
78 #endif
79
80 #ifdef Q_UTEST // test?
81 #if Q_UTEST != 0 // testing QP-stub?
82 if (m_temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
83 return static_cast<QActiveDummy *>(this)->fakePost(e, margin, sender);
84 }
85 #endif
86 #endif
87
90 QF_MEM_SYS();
91
92 #ifndef Q_UNSAFE
93 std::uint8_t const pcopy = static_cast<std::uint8_t>(~m_prio_dis);
94 Q_REQUIRE_INCRIT(102, (QEvt::verify_(e)) && (m_prio == pcopy));
95 #endif
96
97 QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary
98
99 // test-probe#1 for faking queue overflow
102 nFree = 0U;
103 )
104
105 bool status;
106 if (margin == QF::NO_MARGIN) {
107 if (nFree > 0U) {
108 status = true; // can post
109 }
110 else {
111 status = false; // cannot post
112 Q_ERROR_INCRIT(190); // must be able to post the event
113 }
114 }
115 else if (nFree > static_cast<QEQueueCtr>(margin)) {
116 status = true; // can post
117 }
118 else {
119 status = false; // cannot post, but don't assert
120 }
121
122 // is it a mutable event?
123 if (e->getPoolNum_() != 0U) {
124 QEvt_refCtr_inc_(e); // increment the reference counter
125 }
126
127 if (status) { // can post the event?
128
129 --nFree; // one free entry just used up
130 m_eQueue.m_nFree = nFree; // update the original
131 if (m_eQueue.m_nMin > nFree) {
132 m_eQueue.m_nMin = nFree; // update minimum so far
133 }
134
135 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST, m_prio)
136 QS_TIME_PRE_(); // timestamp
137 QS_OBJ_PRE_(sender); // the sender object
138 QS_SIG_PRE_(e->sig); // the signal of the event
139 QS_OBJ_PRE_(this); // this active object
140 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
141 QS_EQC_PRE_(nFree); // # free entries
142 QS_EQC_PRE_(m_eQueue.m_nMin); // min # free entries
143 QS_END_PRE_()
144
145 #ifdef Q_UTEST
146 // callback to examine the posted event under the same conditions
147 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
148 // the local filter for this AO ('m_prio') is set
149 if (QS_LOC_CHECK_(m_prio)) {
150 QS::onTestPost(sender, this, e, status);
151 }
152 #endif
153
154 if (m_eQueue.m_frontEvt == nullptr) { // empty queue?
155 m_eQueue.m_frontEvt = e; // deliver event directly
156 #ifdef QXK_HPP_
157 if (m_state.act == Q_ACTION_CAST(0)) { // eXtended thread?
158 QXTHREAD_EQUEUE_SIGNAL_(this); // signal the event queue
159 }
160 else {
161 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
162 }
163 #else
164 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
165 #endif
166 }
167 // queue is not empty, insert event into the ring-buffer
168 else {
169 // insert event into the ring buffer (FIFO)
170 m_eQueue.m_ring[m_eQueue.m_head] = e;
171
172 if (m_eQueue.m_head == 0U) { // need to wrap head?
173 m_eQueue.m_head = m_eQueue.m_end; // wrap around
174 }
175 // advance the head (counter clockwise)
176 m_eQueue.m_head = (m_eQueue.m_head - 1U);
177 }
178
179 QF_MEM_APP();
180 QF_CRIT_EXIT();
181 }
182 else { // cannot post the event
183
184 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST_ATTEMPT, m_prio)
185 QS_TIME_PRE_(); // timestamp
186 QS_OBJ_PRE_(sender); // the sender object
187 QS_SIG_PRE_(e->sig); // the signal of the event
188 QS_OBJ_PRE_(this); // this active object
189 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
190 QS_EQC_PRE_(nFree); // # free entries
191 QS_EQC_PRE_(margin); // margin requested
192 QS_END_PRE_()
193
194 #ifdef Q_UTEST
195 // callback to examine the posted event under the same conditions
196 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
197 // the local filter for this AO ('m_prio') is set
198 if (QS_LOC_CHECK_(m_prio)) {
199 QS::onTestPost(sender, this, e, status);
200 }
201 #endif
202
203 QF_MEM_APP();
204 QF_CRIT_EXIT();
205
206 #if (QF_MAX_EPOOL > 0U)
207 QF::gc(e); // recycle the event to avoid a leak
208 #endif
209 }
210
211 return status;
212}
213
214} // namespace QP
215//$enddef${QF::QActive::post_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
216
217//$define${QF::QActive::postLIFO} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
218namespace QP {
219
220//${QF::QActive::postLIFO} ...................................................
221void QActive::postLIFO(QEvt const * const e) noexcept {
222 #ifdef Q_UTEST // test?
223 #if Q_UTEST != 0 // testing QP-stub?
224 if (m_temp.fun == Q_STATE_CAST(0)) { // QActiveDummy?
225 static_cast<QActiveDummy *>(this)->QActiveDummy::fakePostLIFO(e);
226 return;
227 }
228 #endif
229 #endif
230
233 QF_MEM_SYS();
234
235 #ifndef Q_UNSAFE
236 std::uint8_t const pcopy = static_cast<std::uint8_t>(~m_prio_dis);
237 Q_REQUIRE_INCRIT(202, (QEvt::verify_(e)) && (m_prio == pcopy));
238 #endif
239
240 #ifdef QXK_HPP_
241 Q_REQUIRE_INCRIT(200, m_state.act != Q_ACTION_CAST(0));
242 #endif
243
244 QEQueueCtr nFree = m_eQueue.m_nFree; // get volatile into temporary
245
246 // test-probe#1 for faking queue overflow
249 nFree = 0U;
250 )
251
252 Q_REQUIRE_INCRIT(201, nFree != 0U);
253
254 if (e->getPoolNum_() != 0U) { // is it a mutable event?
255 QEvt_refCtr_inc_(e); // increment the reference counter
256 }
257
258 --nFree; // one free entry just used up
259 m_eQueue.m_nFree = nFree; // update the original
260 if (m_eQueue.m_nMin > nFree) {
261 m_eQueue.m_nMin = nFree; // update minimum so far
262 }
263
264 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST_LIFO, m_prio)
265 QS_TIME_PRE_(); // timestamp
266 QS_SIG_PRE_(e->sig); // the signal of this event
267 QS_OBJ_PRE_(this); // this active object
268 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
269 QS_EQC_PRE_(nFree); // # free entries
270 QS_EQC_PRE_(m_eQueue.m_nMin); // min # free entries
271 QS_END_PRE_()
272
273 #ifdef Q_UTEST
274 // callback to examine the posted event under the same conditions
275 // as producing the #QS_QF_ACTIVE_POST trace record, which are:
276 // the local filter for this AO ('m_prio') is set
277 if (QS_LOC_CHECK_(m_prio)) {
278 QS::onTestPost(nullptr, this, e, true);
279 }
280 #endif
281
282 QEvt const * const frontEvt = m_eQueue.m_frontEvt;
283 m_eQueue.m_frontEvt = e; // deliver the event directly to the front
284
285 if (frontEvt == nullptr) { // was the queue empty?
286 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
287 }
288 else { // queue was not empty, leave the event in the ring-buffer
289 m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
290 if (m_eQueue.m_tail == m_eQueue.m_end) { // need to wrap the tail?
291 m_eQueue.m_tail = 0U; // wrap around
292 }
293
294 m_eQueue.m_ring[m_eQueue.m_tail] = frontEvt;
295 }
296
297 QF_MEM_APP();
298 QF_CRIT_EXIT();
299}
300
301} // namespace QP
302//$enddef${QF::QActive::postLIFO} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
303
304//$define${QF::QActive::get_} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
305namespace QP {
306
307//${QF::QActive::get_} .......................................................
308QEvt const * QActive::get_() noexcept {
311 QF_MEM_SYS();
312
313 QACTIVE_EQUEUE_WAIT_(this); // wait for event to arrive directly
314
315 // always remove evt from the front
316 QEvt const * const e = m_eQueue.m_frontEvt;
317 QEQueueCtr const nFree = m_eQueue.m_nFree + 1U; // get volatile into tmp
318 m_eQueue.m_nFree = nFree; // update the # free
319
320 if (nFree <= m_eQueue.m_end) { // any events in the ring buffer?
321 // remove event from the tail
322 m_eQueue.m_frontEvt = m_eQueue.m_ring[m_eQueue.m_tail];
323 if (m_eQueue.m_tail == 0U) { // need to wrap the tail?
324 m_eQueue.m_tail = m_eQueue.m_end; // wrap around
325 }
326 m_eQueue.m_tail = (m_eQueue.m_tail - 1U);
327
328 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET, m_prio)
329 QS_TIME_PRE_(); // timestamp
330 QS_SIG_PRE_(e->sig); // the signal of this event
331 QS_OBJ_PRE_(this); // this active object
332 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
333 QS_EQC_PRE_(nFree); // # free entries
334 QS_END_PRE_()
335 }
336 else {
337 m_eQueue.m_frontEvt = nullptr; // the queue becomes empty
338
339 // all entries in the queue must be free (+1 for fronEvt)
340 Q_ASSERT_INCRIT(310, nFree == (m_eQueue.m_end + 1U));
341
342 QS_BEGIN_PRE_(QS_QF_ACTIVE_GET_LAST, m_prio)
343 QS_TIME_PRE_(); // timestamp
344 QS_SIG_PRE_(e->sig); // the signal of this event
345 QS_OBJ_PRE_(this); // this active object
346 QS_2U8_PRE_(e->getPoolNum_(), e->refCtr_); // poolNum & refCtr
347 QS_END_PRE_()
348 }
349
350 QF_MEM_APP();
351 QF_CRIT_EXIT();
352
353 return e;
354}
355
356} // namespace QP
357//$enddef${QF::QActive::get_} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
358
359//$define${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
360namespace QP {
361
362//${QF::QTicker} .............................................................
363
364//${QF::QTicker::QTicker} ....................................................
365QTicker::QTicker(std::uint_fast8_t const tickRate) noexcept
366: QActive(nullptr)
367{
368 // reuse m_head for tick-rate
369 m_eQueue.m_head = static_cast<QEQueueCtr>(tickRate);
370}
371
372//${QF::QTicker::init} .......................................................
374 void const * const e,
375 std::uint_fast8_t const qsId)
376{
377 Q_UNUSED_PAR(e);
378 Q_UNUSED_PAR(qsId);
379
382 QF_MEM_SYS();
383
384 m_eQueue.m_tail = 0U;
385
386 QF_MEM_APP();
387 QF_CRIT_EXIT();
388}
389
390//${QF::QTicker::dispatch} ...................................................
392 QEvt const * const e,
393 std::uint_fast8_t const qsId)
394{
395 Q_UNUSED_PAR(e);
396 Q_UNUSED_PAR(qsId);
397
400 QF_MEM_SYS();
401
402 QEQueueCtr nTicks = m_eQueue.m_tail; // save # of ticks
403 m_eQueue.m_tail = 0U; // clear the # ticks
404
405 QF_MEM_APP();
406 QF_CRIT_EXIT();
407
408 for (; nTicks > 0U; --nTicks) {
409 QTimeEvt::tick(static_cast<std::uint_fast8_t>(m_eQueue.m_head),
410 this);
411 }
412}
413
414//${QF::QTicker::trig_} ......................................................
415void QTicker::trig_(void const * const sender) noexcept {
416 #ifndef Q_SPY
417 Q_UNUSED_PAR(sender);
418 #endif
419
422 QF_MEM_SYS();
423
424 if (m_eQueue.m_frontEvt == nullptr) {
425
426 static QEvt const tickEvt(0U); // immutable event
427
428 m_eQueue.m_frontEvt = &tickEvt; // deliver event directly
429 m_eQueue.m_nFree = (m_eQueue.m_nFree - 1U); // one less free event
430
431 QACTIVE_EQUEUE_SIGNAL_(this); // signal the event queue
432 }
433
434 // account for one more tick event
435 m_eQueue.m_tail = (m_eQueue.m_tail + 1U);
436
437 QS_BEGIN_PRE_(QS_QF_ACTIVE_POST, m_prio)
438 QS_TIME_PRE_(); // timestamp
439 QS_OBJ_PRE_(sender); // the sender object
440 QS_SIG_PRE_(0U); // the signal of the event
441 QS_OBJ_PRE_(this); // this active object
442 QS_2U8_PRE_(0U, 0U); // poolNum & refCtr
443 QS_EQC_PRE_(0U); // # free entries
444 QS_EQC_PRE_(0U); // min # free entries
445 QS_END_PRE_()
446
447 QF_MEM_APP();
448 QF_CRIT_EXIT();
449}
450
451} // namespace QP
452//$enddef${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dummy Active Object for testing.
Definition qs.hpp:844
void fakePostLIFO(QEvt const *const e) noexcept
Definition qutest.cpp:543
Active object class (based on the QHsm implementation strategy)
Definition qp.hpp:724
friend class QTicker
Definition qp.hpp:756
QEvt const * get_() noexcept
Definition qf_actq.cpp:308
QACTIVE_EQUEUE_TYPE m_eQueue
Definition qp.hpp:738
void postLIFO(QEvt const *const e) noexcept
Definition qf_actq.cpp:221
std::uint8_t m_prio
Definition qp.hpp:726
bool post_(QEvt const *const e, std::uint_fast16_t const margin, void const *const sender) noexcept
Definition qf_actq.cpp:71
Event class.
Definition qp.hpp:139
std::uint_fast8_t getPoolNum_() const noexcept
Definition qp.hpp:167
std::uint8_t volatile refCtr_
Definition qp.hpp:142
static bool verify_(QEvt const *const e) noexcept
Definition qp.hpp:163
QSignal sig
Definition qp.hpp:141
void dispatch(QEvt const *const e, std::uint_fast8_t const qsId) override
Definition qf_actq.cpp:391
void init(void const *const e, std::uint_fast8_t const qsId) override
Definition qf_actq.cpp:373
void trig_(void const *const sender) noexcept
Definition qf_actq.cpp:415
static void tick(std::uint_fast8_t const tickRate, void const *const sender) noexcept
Definition qf_time.cpp:280
constexpr std::uint_fast16_t NO_MARGIN
Definition qp.hpp:1101
void gc(QEvt const *const e) noexcept
Definition qf_dyn.cpp:236
void onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status)
QP/C++ framework.
Definition qequeue.hpp:50
std::uint16_t QEQueueCtr
Definition qequeue.hpp:55
void QEvt_refCtr_inc_(QEvt const *const e) noexcept
Definition qp_pkg.hpp:92
@ QS_QF_ACTIVE_GET_LAST
AO got an event and its queue is empty.
Definition qs.hpp:92
@ QS_QF_ACTIVE_POST_ATTEMPT
attempt to post an evt to AO failed
Definition qs.hpp:134
@ QS_QF_ACTIVE_POST_LIFO
an event was posted (LIFO) directly to AO
Definition qs.hpp:90
@ QS_QF_ACTIVE_GET
AO got an event and its queue is not empty.
Definition qs.hpp:91
@ QS_QF_ACTIVE_POST
an event was posted (FIFO) directly to AO
Definition qs.hpp:89
#define QACTIVE_EQUEUE_SIGNAL_(me_)
Definition qk.hpp:148
#define QACTIVE_EQUEUE_WAIT_(me_)
Definition qk.hpp:143
#define QF_MEM_APP()
Definition qp.hpp:1276
#define Q_UNUSED_PAR(par_)
Definition qp.hpp:541
#define Q_STATE_CAST(handler_)
Definition qp.hpp:493
#define QF_MEM_SYS()
Definition qp.hpp:1271
Internal (package scope) QP/C++ interface.
#define Q_ACTION_CAST(act_)
Definition qp_pkg.hpp:82
Sample QP/C++ port.
#define QS_TIME_PRE_()
Definition qs.hpp:473
#define QS_TEST_PROBE_DEF(fun_)
Definition qs.hpp:870
#define QS_TEST_PROBE_ID(id_, code_)
Definition qs.hpp:877
#define QS_LOC_CHECK_(qsId_)
Definition qs.hpp:384
QS/C++ package-scope interface.
QS/C++ port to a 32-bit CPU, generic C++ compiler.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:58
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:72
#define QF_CRIT_EXIT()
Definition qsafe.h:62
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:136
#define Q_ERROR_INCRIT(id_)
Definition qsafe.h:76
#define QF_CRIT_STAT
Definition qsafe.h:54
#define QXTHREAD_EQUEUE_SIGNAL_(me_)
Definition qxk.hpp:277