QP/C  8.0.0
Real-Time Embedded Framework
Loading...
Searching...
No Matches
qep_hsm.c
Go to the documentation of this file.
1//$file${src::qf::qep_hsm.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2//
3// Model: qpc.qm
4// File: ${src::qf::qep_hsm.c}
5//
6// This code has been generated by QM 7.0.0 <www.state-machine.com/qm>.
7// DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
8//
9// Copyright (C) 2005 Quantum Leaps, LLC. All rights reserved.
10//
11// Q u a n t u m L e a P s
12// ------------------------
13// Modern Embedded Software
14//
15// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
16//
17// The QP/C software is dual-licensed under the terms of the open-source GNU
18// General Public License (GPL) or under the terms of one of the closed-
19// source Quantum Leaps commercial licenses.
20//
21// Redistributions in source code must retain this top-level comment block.
22// Plagiarizing this software to sidestep the license obligations is illegal.
23//
24// NOTE:
25// The GPL does NOT permit the incorporation of this code into proprietary
26// programs. Please contact Quantum Leaps for commercial licensing options,
27// which expressly supersede the GPL and are designed explicitly for
28// closed-source distribution.
29//
30// Quantum Leaps contact information:
31// <www.state-machine.com/licensing>
32// <info@state-machine.com>
33//
34//$endhead${src::qf::qep_hsm.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35#define QP_IMPL // this is QP implementation
36#include "qp_port.h" // QP port
37#include "qp_pkg.h" // QP package-scope interface
38#include "qsafe.h" // QP Functional Safety (FuSa) Subsystem
39#ifdef Q_SPY // QS software tracing enabled?
40 #include "qs_port.h" // QS port
41 #include "qs_pkg.h" // QS facilities for pre-defined trace records
42#else
43 #include "qs_dummy.h" // disable the QS software tracing
44#endif // Q_SPY
45
46Q_DEFINE_THIS_MODULE("qep_hsm")
47
48//$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
49// Check for the minimum required QP version
50#if (QP_VERSION < 730U) || (QP_VERSION != ((QP_RELEASE^4294967295U)%0x2710U))
51#error qpc version 7.3.0 or higher required
52#endif
53//$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54//$define${QEP::QP_versionStr[16]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
55
56//${QEP::QP_versionStr[16]} ..................................................
57char const QP_versionStr[16] = QP_VERSION_STR;
58//$enddef${QEP::QP_versionStr[16]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
59
60//============================================================================
61//! @cond INTERNAL
62
63//$define${QEP::QEvt::reserved_[4]} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
64QEvt const QEvt_reserved_[4] = {
69};
70
71//$enddef${QEP::QEvt::reserved_[4]} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
72
73// helper macro to handle reserved event in an QHsm
74#define QHSM_RESERVED_EVT_(state_, sig_) \
75 ((*(state_))(me, &QEvt_reserved_[(sig_)]))
76
77// helper macro to trace state entry
78#define QS_STATE_ENTRY_(state_, qsId_) \
79 QS_CRIT_ENTRY(); \
80 QS_MEM_SYS(); \
81 QS_BEGIN_PRE(QS_QEP_STATE_ENTRY, (qsId_)) \
82 QS_OBJ_PRE(me); \
83 QS_FUN_PRE(state_); \
84 QS_END_PRE() \
85 QS_MEM_APP(); \
86 QS_CRIT_EXIT()
87
88// helper macro to trace state exit
89#define QS_STATE_EXIT_(state_, qsId_) \
90 QS_CRIT_ENTRY(); \
91 QS_MEM_SYS(); \
92 QS_BEGIN_PRE(QS_QEP_STATE_EXIT, (qsId_)) \
93 QS_OBJ_PRE(me); \
94 QS_FUN_PRE(state_); \
95 QS_END_PRE() \
96 QS_MEM_APP(); \
97 QS_CRIT_EXIT()
98
99//! @endcond
100
101enum {
102 // maximum depth of state nesting in a QHsm (including the top level),
103 // must be >= 3
104 QHSM_MAX_NEST_DEPTH_ = 6
105};
106
107//$define${QEP::QHsm} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
108
109//${QEP::QHsm} ...............................................................
110
111//${QEP::QHsm::ctor} .........................................................
112//! @protected @memberof QHsm
113void QHsm_ctor(QHsm * const me,
114 QStateHandler const initial)
115{
116 static struct QAsmVtable const vtable = { // QAsm virtual table
117 &QHsm_init_,
118 &QHsm_dispatch_,
119 &QHsm_isIn_
120 #ifdef Q_SPY
121 ,&QHsm_getStateHandler_
122 #endif
123 };
124 // do not call the QAsm_ctor() here
125 me->super.vptr = &vtable;
126 me->super.state.fun = Q_STATE_CAST(&QHsm_top);
127 me->super.temp.fun = initial;
128}
129
130//${QEP::QHsm::init_} ........................................................
131//! @private @memberof QHsm
132void QHsm_init_(
133 QAsm * const me,
134 void const * const e,
135 uint_fast8_t const qsId)
136{
138
139 QState r;
140
141 // produce QS dictionary for QHsm_top()
142 #ifdef Q_SPY
144 QS_MEM_SYS();
145 if ((QS_priv_.flags & 0x01U) == 0U) {
146 QS_priv_.flags |= 0x01U;
147 r = Q_RET_HANDLED;
148 }
149 else {
150 r = Q_RET_IGNORED;
151 }
152 QS_MEM_APP();
153 QS_CRIT_EXIT();
154 if (r == Q_RET_HANDLED) {
155 QS_FUN_DICTIONARY(&QHsm_top);
156 }
157 #else
158 Q_UNUSED_PAR(qsId);
159 #endif // def Q_SPY
160
161 QStateHandler t = me->state.fun;
162
164 Q_REQUIRE_INCRIT(200, (me->vptr != (struct QAsmVtable *)0)
165 && (me->temp.fun != Q_STATE_CAST(0))
166 && (t == Q_STATE_CAST(&QHsm_top)));
167 QF_CRIT_EXIT();
168
169 // execute the top-most initial tran.
170 r = (*me->temp.fun)(me, Q_EVT_CAST(QEvt));
171
173 // the top-most initial tran. must be taken
174 Q_ASSERT_INCRIT(210, r == Q_RET_TRAN);
175
176 QS_MEM_SYS();
177 QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
178 QS_OBJ_PRE(me); // this state machine object
179 QS_FUN_PRE(t); // the source state
180 QS_FUN_PRE(me->temp.fun); // the target of the initial tran.
181 QS_END_PRE()
182 QS_MEM_APP();
183
184 QF_CRIT_EXIT();
185
186 // drill down into the state hierarchy with initial transitions...
187 do {
188 QStateHandler path[QHSM_MAX_NEST_DEPTH_]; // tran. entry path array
189 int_fast8_t ip = 0; // tran. entry path index
190
191 path[0] = me->temp.fun;
192 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
193 // note: ip is the fixed upper loop bound
194 while ((me->temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
195 ++ip;
196 path[ip] = me->temp.fun;
197 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
198 }
200 // too many state nesting levels or "malformed" HSM
201 Q_ENSURE_INCRIT(220, ip < QHSM_MAX_NEST_DEPTH_);
202 QF_CRIT_EXIT();
203
204 me->temp.fun = path[0];
205
206 // retrace the entry path in reverse (desired) order...
207 // note: ip is the fixed upper loop bound
208 do {
209 // enter path[ip]
210 if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
211 == Q_RET_HANDLED)
212 {
213 QS_STATE_ENTRY_(path[ip], qsId);
214 }
215 --ip;
216 } while (ip >= 0);
217
218 t = path[0]; // current state becomes the new source
219
220 r = QHSM_RESERVED_EVT_(t, Q_INIT_SIG); // execute initial tran.
221
222 #ifdef Q_SPY
223 if (r == Q_RET_TRAN) {
225 QS_MEM_SYS();
226 QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
227 QS_OBJ_PRE(me); // this state machine object
228 QS_FUN_PRE(t); // the source state
229 QS_FUN_PRE(me->temp.fun); // the target of the initial tran.
230 QS_END_PRE()
231 QS_MEM_APP();
232 QS_CRIT_EXIT();
233 }
234 #endif // Q_SPY
235 } while (r == Q_RET_TRAN);
236
238
239 QS_MEM_SYS();
240 QS_BEGIN_PRE(QS_QEP_INIT_TRAN, qsId)
241 QS_TIME_PRE(); // time stamp
242 QS_OBJ_PRE(me); // this state machine object
243 QS_FUN_PRE(t); // the new active state
244 QS_END_PRE()
245 QS_MEM_APP();
246
247 QF_CRIT_EXIT();
248
249 me->state.fun = t; // change the current active state
250 #ifndef Q_UNSAFE
251 me->temp.uint = ~me->state.uint;
252 #endif
253}
254
255//${QEP::QHsm::dispatch_} ....................................................
256//! @private @memberof QHsm
257void QHsm_dispatch_(
258 QAsm * const me,
259 QEvt const * const e,
260 uint_fast8_t const qsId)
261{
262 #ifndef Q_SPY
263 Q_UNUSED_PAR(qsId);
264 #endif
265
266 QStateHandler s = me->state.fun;
267 QStateHandler t = s;
269
272 (e != (QEvt *)0)
273 && (s != Q_STATE_CAST(0))
274 && (me->state.uint == (uintptr_t)(~me->temp.uint)));
275 #ifndef Q_UNSAFE
276 Q_INVARIANT_INCRIT(301, QEvt_verify_(e));
277 #endif
278
279 QS_MEM_SYS();
280 QS_BEGIN_PRE(QS_QEP_DISPATCH, qsId)
281 QS_TIME_PRE(); // time stamp
282 QS_SIG_PRE(e->sig); // the signal of the event
283 QS_OBJ_PRE(me); // this state machine object
284 QS_FUN_PRE(s); // the current state
285 QS_END_PRE()
286 QS_MEM_APP();
287
288 QF_CRIT_EXIT();
289
290 // process the event hierarchically...
291 QState r;
292 me->temp.fun = s;
293 int_fast8_t ip = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
294 do {
295 s = me->temp.fun;
296 r = (*s)(me, e); // invoke state handler s
297
298 if (r == Q_RET_UNHANDLED) { // unhandled due to a guard?
299
301 QS_MEM_SYS();
302 QS_BEGIN_PRE(QS_QEP_UNHANDLED, qsId)
303 QS_SIG_PRE(e->sig); // the signal of the event
304 QS_OBJ_PRE(me); // this state machine object
305 QS_FUN_PRE(s); // the current state
306 QS_END_PRE()
307 QS_MEM_APP();
308 QS_CRIT_EXIT();
309
310 r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG); // superstate of s
311 }
312
313 --ip;
314 } while ((r == Q_RET_SUPER) && (ip > 0));
315
317 Q_ENSURE_INCRIT(310, ip > 0);
318 QF_CRIT_EXIT();
319
320 if (r >= Q_RET_TRAN) { // tran. (regular or history) taken?
321 #ifdef Q_SPY
322 if (r == Q_RET_TRAN_HIST) { // tran. to history?
324 QS_MEM_SYS();
325 QS_BEGIN_PRE(QS_QEP_TRAN_HIST, qsId)
326 QS_OBJ_PRE(me); // this state machine object
327 QS_FUN_PRE(s); // tran. to history source
328 QS_FUN_PRE(me->temp.fun); // tran. to history target
329 QS_END_PRE()
330 QS_MEM_APP();
331 QS_CRIT_EXIT();
332 }
333 #endif // Q_SPY
334
335 QStateHandler path[QHSM_MAX_NEST_DEPTH_];
336 path[0] = me->temp.fun; // tran. target
337 path[1] = t; // current state
338 path[2] = s; // tran. source
339
340 // exit current state to tran. source s...
341 ip = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
342 for (; (t != s) && (ip > 0); t = me->temp.fun) {
343 // exit from t
344 if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {
345 QS_STATE_EXIT_(t, qsId);
346 // find superstate of t
347 (void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
348 }
349 --ip;
350 }
352 Q_ENSURE_INCRIT(320, ip > 0);
353 QF_CRIT_EXIT();
354
355 ip = QHsm_tran_(me, path, qsId); // take the tran.
356
357 // execute state entry actions in the desired order...
358 // note: ip is the fixed upper loop bound
359 for (; ip >= 0; --ip) {
360 // enter path[ip]
361 if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
362 == Q_RET_HANDLED)
363 {
364 QS_STATE_ENTRY_(path[ip], qsId);
365 }
366 }
367 t = path[0]; // stick the target into register
368 me->temp.fun = t; // update the next state
369
370 // drill into the target hierarchy...
371 while (QHSM_RESERVED_EVT_(t, Q_INIT_SIG) == Q_RET_TRAN) {
372
374 QS_MEM_SYS();
375 QS_BEGIN_PRE(QS_QEP_STATE_INIT, qsId)
376 QS_OBJ_PRE(me); // this state machine object
377 QS_FUN_PRE(t); // the source (pseudo)state
378 QS_FUN_PRE(me->temp.fun); // the target of the tran.
379 QS_END_PRE()
380 QS_MEM_APP();
381 QS_CRIT_EXIT();
382
383 ip = 0;
384 path[0] = me->temp.fun;
385
386 // find superstate
387 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
388
389 // note: ip is the fixed upper loop bound
390 while ((me->temp.fun != t) && (ip < (QHSM_MAX_NEST_DEPTH_ - 1))) {
391 ++ip;
392 path[ip] = me->temp.fun;
393 // find superstate
394 (void)QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
395 }
397 // too many state nesting levels or "malformed" HSM
398 Q_ENSURE_INCRIT(330, ip < QHSM_MAX_NEST_DEPTH_);
399 QF_CRIT_EXIT();
400
401 me->temp.fun = path[0];
402
403 // retrace the entry path in reverse (correct) order...
404 // note: ip is the fixed upper loop bound
405 do {
406 // enter path[ip]
407 if (QHSM_RESERVED_EVT_(path[ip], Q_ENTRY_SIG)
408 == Q_RET_HANDLED)
409 {
410 QS_STATE_ENTRY_(path[ip], qsId);
411 }
412 --ip;
413 } while (ip >= 0);
414
415 t = path[0]; // current state becomes the new source
416 }
417
419 QS_MEM_SYS();
420 QS_BEGIN_PRE(QS_QEP_TRAN, qsId)
421 QS_TIME_PRE(); // time stamp
422 QS_SIG_PRE(e->sig); // the signal of the event
423 QS_OBJ_PRE(me); // this state machine object
424 QS_FUN_PRE(s); // the source of the tran.
425 QS_FUN_PRE(t); // the new active state
426 QS_END_PRE()
427 QS_MEM_APP();
428 QS_CRIT_EXIT();
429 }
430
431 #ifdef Q_SPY
432 else if (r == Q_RET_HANDLED) {
434 QS_MEM_SYS();
435 QS_BEGIN_PRE(QS_QEP_INTERN_TRAN, qsId)
436 QS_TIME_PRE(); // time stamp
437 QS_SIG_PRE(e->sig); // the signal of the event
438 QS_OBJ_PRE(me); // this state machine object
439 QS_FUN_PRE(s); // the source state
440 QS_END_PRE()
441 QS_MEM_APP();
442 QS_CRIT_EXIT();
443 }
444 else {
446 QS_MEM_SYS();
447 QS_BEGIN_PRE(QS_QEP_IGNORED, qsId)
448 QS_TIME_PRE(); // time stamp
449 QS_SIG_PRE(e->sig); // the signal of the event
450 QS_OBJ_PRE(me); // this state machine object
451 QS_FUN_PRE(me->state.fun); // the current state
452 QS_END_PRE()
453 QS_MEM_APP();
454 QS_CRIT_EXIT();
455 }
456 #endif // Q_SPY
457
458 me->state.fun = t; // change the current active state
459 #ifndef Q_UNSAFE
460 me->temp.uint = ~me->state.uint;
461 #endif
462}
463
464//${QEP::QHsm::getStateHandler_} .............................................
465#ifdef Q_SPY
466//! @private @memberof QHsm
467QStateHandler QHsm_getStateHandler_(QAsm * const me) {
468 return me->state.fun;
469}
470#endif // def Q_SPY
471
472//${QEP::QHsm::isIn_} ........................................................
473//! @private @memberof QHsm
474bool QHsm_isIn_(
475 QAsm * const me,
476 QStateHandler const state)
477{
481 me->state.uint == (uintptr_t)(~me->temp.uint));
482 QF_CRIT_EXIT();
483
484 bool inState = false; // assume that this HSM is not in 'state'
485
486 // scan the state hierarchy bottom-up
487 QStateHandler s = me->state.fun;
488 int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_ + 1; // fixed upper loop bound
490 for (; (r != Q_RET_IGNORED) && (lbound > 0); --lbound) {
491 if (s == state) { // do the states match?
492 inState = true; // 'true' means that match found
493 break; // break out of the for-loop
494 }
495 else {
496 r = QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
497 s = me->temp.fun;
498 }
499 }
500
502 Q_ENSURE_INCRIT(690, lbound > 0);
503 QF_CRIT_EXIT();
504
505 #ifndef Q_UNSAFE
506 me->temp.uint = ~me->state.uint;
507 #endif
508
509 return inState; // return the status
510}
511
512//${QEP::QHsm::childState} ...................................................
513//! @public @memberof QHsm
514QStateHandler QHsm_childState(QHsm * const me,
515 QStateHandler const parent)
516{
517 QStateHandler child = me->super.state.fun; // start with current state
518 bool isFound = false; // start with the child not found
519
520 // establish stable state configuration
521 me->super.temp.fun = child;
522 QState r;
523 int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_; // fixed upper loop bound
524 do {
525 // is this the parent of the current child?
526 if (me->super.temp.fun == parent) {
527 isFound = true; // child is found
528 r = Q_RET_IGNORED; // break out of the loop
529 }
530 else {
531 child = me->super.temp.fun;
532 r = QHSM_RESERVED_EVT_(me->super.temp.fun, Q_EMPTY_SIG);
533 }
534 --lbound;
535 } while ((r != Q_RET_IGNORED) // the top state not reached
536 && (lbound > 0));
537
538 #ifndef Q_UNSAFE
539 me->super.temp.uint = ~me->super.state.uint;
540 #else
541 Q_UNUSED_PAR(isFound);
542 #endif
543
546 // NOTE: the following postcondition can only succeed when
547 // (lbound > 0), so no extra check is necessary.
548 Q_ENSURE_INCRIT(890, isFound);
549 QF_CRIT_EXIT();
550
551 return child;
552}
553
554//${QEP::QHsm::tran_} ........................................................
555//! @private @memberof QHsm
556int_fast8_t QHsm_tran_(
557 QAsm * const me,
558 QStateHandler * const path,
559 uint_fast8_t const qsId)
560{
561 #ifndef Q_SPY
562 Q_UNUSED_PAR(qsId);
563 #endif
564
565 int_fast8_t ip = -1; // tran. entry path index
566 QStateHandler t = path[0];
567 QStateHandler const s = path[2];
569
570 // (a) check source==target (tran. to self)...
571 if (s == t) {
572 // exit source s
573 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
574 QS_STATE_EXIT_(s, qsId);
575 }
576 ip = 0; // enter the target
577 }
578 else {
579 // find superstate of target
580 (void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
581
582 t = me->temp.fun;
583
584 // (b) check source==target->super...
585 if (s == t) {
586 ip = 0; // enter the target
587 }
588 else {
589 // find superstate of src
590 (void)QHSM_RESERVED_EVT_(s, Q_EMPTY_SIG);
591
592 // (c) check source->super==target->super...
593 if (me->temp.fun == t) {
594 // exit source s
595 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
596 QS_STATE_EXIT_(s, qsId);
597 }
598 ip = 0; // enter the target
599 }
600 else {
601 // (d) check source->super==target...
602 if (me->temp.fun == path[0]) {
603 // exit source s
604 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG) == Q_RET_HANDLED) {
605 QS_STATE_EXIT_(s, qsId);
606 }
607 }
608 else {
609 // (e) check rest of source==target->super->super..
610 // and store the entry path along the way
611 int_fast8_t iq = 0; // indicate that LCA was found
612 ip = 1; // enter target and its superstate
613 path[1] = t; // save the superstate of target
614 t = me->temp.fun; // save source->super
615
616 // find target->super->super...
617 // note: ip is the fixed upper loop bound
618 QState r = QHSM_RESERVED_EVT_(path[1], Q_EMPTY_SIG);
619 while ((r == Q_RET_SUPER)
620 && (ip < (QHSM_MAX_NEST_DEPTH_ - 1)))
621 {
622 ++ip;
623 path[ip] = me->temp.fun; // store the entry path
624 if (me->temp.fun == s) { // is it the source?
625 iq = 1; // indicate that the LCA found
626 --ip; // do not enter the source
627 r = Q_RET_HANDLED; // terminate the loop
628 }
629 else { // it is not the source, keep going up
630 r = QHSM_RESERVED_EVT_(me->temp.fun, Q_EMPTY_SIG);
631 }
632 }
634 // NOTE: The following postcondition succeeds only when
635 // ip < QHSM_MAX_NEST_DEPTH, so no additional check is necessary
636 // too many state nesting levels or "malformed" HSM.
637 Q_ENSURE_INCRIT(510, r != Q_RET_SUPER);
638 QF_CRIT_EXIT();
639
640 // the LCA not found yet?
641 if (iq == 0) {
642 // exit source s
643 if (QHSM_RESERVED_EVT_(s, Q_EXIT_SIG)
644 == Q_RET_HANDLED)
645 {
646 QS_STATE_EXIT_(s, qsId);
647 }
648
649 // (f) check the rest of source->super
650 // == target->super->super...
651 iq = ip;
652 r = Q_RET_IGNORED; // indicate that the LCA NOT found
653 // note: iq is the fixed upper loop bound
654 do {
655 if (t == path[iq]) { // is this the LCA?
656 r = Q_RET_HANDLED; // indicate the LCA found
657 ip = iq - 1; // do not enter the LCA
658 iq = -1; // cause termination of the loop
659 }
660 else {
661 --iq; // try lower superstate of target
662 }
663 } while (iq >= 0);
664
665 // the LCA not found yet?
666 if (r != Q_RET_HANDLED) {
667 // (g) check each source->super->...
668 // for each target->super...
669 r = Q_RET_IGNORED; // keep looping
670 int_fast8_t lbound = QHSM_MAX_NEST_DEPTH_;
671 do {
672 // exit from t
673 if (QHSM_RESERVED_EVT_(t, Q_EXIT_SIG)
674 == Q_RET_HANDLED)
675 {
676 QS_STATE_EXIT_(t, qsId);
677 // find superstate of t
678 (void)QHSM_RESERVED_EVT_(t, Q_EMPTY_SIG);
679 }
680 t = me->temp.fun; // set to super of t
681 iq = ip;
682 do {
683 // is this the LCA?
684 if (t == path[iq]) {
685 ip = iq - 1; // do not enter the LCA
686 iq = -1; // break out of inner loop
687 r = Q_RET_HANDLED; // break outer loop
688 }
689 else {
690 --iq;
691 }
692 } while (iq >= 0);
693
694 --lbound;
695 } while ((r != Q_RET_HANDLED) && (lbound > 0));
697 Q_ENSURE_INCRIT(530, lbound > 0);
698 QF_CRIT_EXIT();
699 }
700 }
701 }
702 }
703 }
704 }
706 Q_ENSURE_INCRIT(590, ip < QHSM_MAX_NEST_DEPTH_);
707 QF_CRIT_EXIT();
708 return ip;
709}
710
711//${QEP::QHsm::top} ..........................................................
712//! @protected @memberof QAsm
713QState QHsm_top(QHsm const * const me,
714 QEvt const * const e)
715{
716 Q_UNUSED_PAR(me);
717 Q_UNUSED_PAR(e);
718 return Q_RET_IGNORED; // the top state ignores all events
719}
720//$enddef${QEP::QHsm} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ Q_RET_HANDLED
event handled (internal transition)
Definition qp.h:193
@ Q_RET_IGNORED
event silently ignored (bubbled up to top)
Definition qp.h:194
@ Q_RET_TRAN
regular transition
Definition qp.h:204
@ Q_RET_UNHANDLED
event unhandled due to guard
Definition qp.h:190
@ Q_RET_SUPER
event passed to superstate to handle
Definition qp.h:189
@ Q_RET_TRAN_HIST
transition to history of a given state
Definition qp.h:208
QEvt const QEvt_reserved_[4]
char const QP_versionStr[16]
the current QP version number string in ROM, based on QP_VERSION_STR
#define Q_UNUSED_PAR(par_)
Helper macro to clearly mark unused parameters of functions.
Definition qp.h:521
#define QP_VERSION_STR
Version string complying with Semantic Versioning
Definition qp.h:39
#define Q_STATE_CAST(handler_)
Perform cast to QStateHandler.
Definition qp.h:515
#define Q_EXIT_SIG
reserved signal sent to state handler to execute the exit case)
Definition qp.h:479
QState(* QStateHandler)(void *const me, QEvt const *const e)
Pointer to a state-handler function.
Definition qp.h:215
enum QStateRet QState
Type returned from state-handler functions.
Definition qp.h:212
#define Q_EVT_CAST(class_)
Perform downcast of an event onto a subclass of QEvt class_
Definition qp.h:512
#define Q_ENTRY_SIG
reserved signal sent to state handler to execute the entry case)
Definition qp.h:476
#define Q_INIT_SIG
reserved signal sent to state handler to execute the initial transition)
Definition qp.h:482
#define Q_EMPTY_SIG
reserved signal sent to state handler to execute the default case)
Definition qp.h:473
#define QEVT_INITIALIZER(sig_)
Initializer for immutable (constant) QEvt instances.
Definition qp.h:430
Internal (package scope) QP/C interface.
Sample QP/C port.
#define QS_OBJ_PRE(obj_)
Definition qs_dummy.h:150
#define QS_FUN_DICTIONARY(fun_)
Definition qs_dummy.h:72
#define QS_SIG_PRE(sig_)
Definition qs_dummy.h:148
#define QS_TIME_PRE()
Definition qs_dummy.h:147
#define QS_MEM_APP()
Definition qs_dummy.h:162
#define QS_FUN_PRE(fun_)
Definition qs_dummy.h:151
#define QS_CRIT_EXIT()
Definition qs_dummy.h:159
#define QS_MEM_SYS()
Definition qs_dummy.h:161
#define QS_END_PRE()
Definition qs_dummy.h:142
#define QS_CRIT_ENTRY()
Definition qs_dummy.h:158
#define QS_BEGIN_PRE(rec_, qsId_)
Definition qs_dummy.h:141
Sample QS/C port.
QP Functional Safety (FuSa) Subsystem.
#define QF_CRIT_ENTRY()
Definition qsafe.h:50
#define Q_ASSERT_INCRIT(id_, expr_)
Definition qsafe.h:64
#define Q_INVARIANT_INCRIT(id_, expr_)
Definition qsafe.h:146
#define Q_ENSURE_INCRIT(id_, expr_)
Definition qsafe.h:137
#define QF_CRIT_EXIT()
Definition qsafe.h:54
#define Q_REQUIRE_INCRIT(id_, expr_)
Definition qsafe.h:128
#define QF_CRIT_STAT
Definition qsafe.h:46
Abstract State Machine class (state machine interface)
Definition qp.h:256
struct QAsmVtable const * vptr
Virtual pointer inherited by all QAsm subclasses (see also Object Orientation)
Definition qp.h:260
union QAsmAttr state
Current state (pointer to the current state-handler function)
Definition qp.h:265
union QAsmAttr temp
Temporary storage for target/act-table etc.
Definition qp.h:268
Virtual table for the QAsm class.
Definition qp.h:277
Event class.
Definition qp.h:131
QSignal sig
Signal of the event (see Event Signal)
Definition qp.h:135
Hierarchical State Machine class (QHsm-style state machine implementation strategy)
Definition qp.h:292
QAsm super
Definition qp.h:294
uintptr_t uint
Definition qp.h:250
QStateHandler fun
Definition qp.h:244