2012-08-14 18:07:04 -04:00
|
|
|
/*****************************************************************************
|
|
|
|
* Product: QEP/C
|
2013-12-30 17:37:40 -05:00
|
|
|
* Last Updated for Version: 5.2.0
|
|
|
|
* Date of the Last Update: Dec 19, 2013
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
|
|
|
* Q u a n t u m L e a P s
|
|
|
|
* ---------------------------
|
|
|
|
* innovating embedded systems
|
|
|
|
*
|
2013-02-12 10:04:39 -05:00
|
|
|
* Copyright (C) 2002-2013 Quantum Leaps, LLC. All rights reserved.
|
2012-08-14 18:07:04 -04:00
|
|
|
*
|
|
|
|
* This program is open source software: you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as published
|
2013-10-16 16:44:03 -04:00
|
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
2012-08-14 18:07:04 -04:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Alternatively, this program may be distributed and modified under the
|
|
|
|
* terms of Quantum Leaps commercial licenses, which expressly supersede
|
|
|
|
* the GNU General Public License and are specifically designed for
|
|
|
|
* licensees interested in retaining the proprietary status of their code.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Contact information:
|
|
|
|
* Quantum Leaps Web sites: http://www.quantum-leaps.com
|
|
|
|
* http://www.state-machine.com
|
|
|
|
* e-mail: info@quantum-leaps.com
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "qep_pkg.h"
|
|
|
|
#include "qassert.h"
|
|
|
|
|
|
|
|
Q_DEFINE_THIS_MODULE("qhsm_dis")
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
* \ingroup qep
|
2013-12-30 17:37:40 -05:00
|
|
|
* \brief QHsm_dispatch_() implementation.
|
2012-08-14 18:07:04 -04:00
|
|
|
*/
|
|
|
|
|
2013-12-30 17:37:40 -05:00
|
|
|
|
|
|
|
static int_t QHsm_tran_(QHsm * const me,
|
|
|
|
QStateHandler path[QEP_MAX_NEST_DEPTH_]);
|
|
|
|
|
2012-08-14 18:07:04 -04:00
|
|
|
/*..........................................................................*/
|
2013-12-30 17:37:40 -05:00
|
|
|
void QHsm_dispatch_(QHsm * const me, QEvt const * const e) {
|
2013-09-23 14:34:35 -04:00
|
|
|
QStateHandler t = me->state.fun;
|
2012-08-14 18:07:04 -04:00
|
|
|
QStateHandler s;
|
|
|
|
QState r;
|
|
|
|
QS_CRIT_STAT_
|
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
Q_REQUIRE(t == me->temp.fun); /* the state configuration must be stable */
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_BEGIN_(QS_QEP_DISPATCH, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_TIME_(); /* time stamp */
|
|
|
|
QS_SIG_(e->sig); /* the signal of the event */
|
|
|
|
QS_OBJ_(me); /* this state machine object */
|
|
|
|
QS_FUN_(t); /* the current state */
|
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
do { /* process the event hierarchically... */
|
2013-09-23 14:34:35 -04:00
|
|
|
s = me->temp.fun;
|
2012-08-14 18:07:04 -04:00
|
|
|
r = (*s)(me, e); /* invoke state handler s */
|
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
if (r == (QState)Q_RET_UNHANDLED) { /* unhandled due to a guard? */
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_BEGIN_(QS_QEP_UNHANDLED, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_SIG_(e->sig); /* the signal of the event */
|
|
|
|
QS_OBJ_(me); /* this state machine object */
|
|
|
|
QS_FUN_(s); /* the current state */
|
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
r = QEP_TRIG_(s, QEP_EMPTY_SIG_); /* find superstate of s */
|
|
|
|
}
|
2013-09-23 14:34:35 -04:00
|
|
|
} while (r == (QState)Q_RET_SUPER);
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
if (r == (QState)Q_RET_TRAN) { /* transition taken? */
|
2012-08-14 18:07:04 -04:00
|
|
|
QStateHandler path[QEP_MAX_NEST_DEPTH_];
|
2013-12-30 17:37:40 -05:00
|
|
|
int_t ip;
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
path[0] = me->temp.fun; /* save the target of the transition */
|
2012-08-14 18:07:04 -04:00
|
|
|
path[1] = t;
|
2013-12-30 17:37:40 -05:00
|
|
|
path[2] = s;
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
while (t != s) { /* exit current state to transition source s... */
|
2013-09-23 14:34:35 -04:00
|
|
|
if (QEP_TRIG_(t, Q_EXIT_SIG) == (QState)Q_RET_HANDLED) {
|
|
|
|
QS_BEGIN_(QS_QEP_STATE_EXIT, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_OBJ_(me); /* this state machine object */
|
|
|
|
QS_FUN_(t); /* the exited state */
|
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
(void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* find superstate of t */
|
|
|
|
}
|
2013-09-23 14:34:35 -04:00
|
|
|
t = me->temp.fun; /* me->temp holds the superstate */
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
|
2013-12-30 17:37:40 -05:00
|
|
|
ip = QHsm_tran_(me, path);
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
/* retrace the entry path in reverse (desired) order... */
|
2013-09-23 14:34:35 -04:00
|
|
|
for (; ip >= (int_t)0; --ip) {
|
2013-02-12 10:04:39 -05:00
|
|
|
QEP_ENTER_(path[ip]); /* enter path[ip] */
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
|
|
|
t = path[0]; /* stick the target into register */
|
2013-09-23 14:34:35 -04:00
|
|
|
me->temp.fun = t; /* update the next state */
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
/* drill into the target hierarchy... */
|
2013-09-23 14:34:35 -04:00
|
|
|
while (QEP_TRIG_(t, Q_INIT_SIG) == (QState)Q_RET_TRAN) {
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_BEGIN_(QS_QEP_STATE_INIT, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_OBJ_(me); /* this state machine object */
|
|
|
|
QS_FUN_(t); /* the source (pseudo)state */
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_FUN_(me->temp.fun); /* the target of the transition */
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_END_()
|
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
ip = (int_t)0;
|
|
|
|
path[0] = me->temp.fun;
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
(void)QEP_TRIG_(me->temp.fun, QEP_EMPTY_SIG_);/*find superstate */
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
while (me->temp.fun != t) {
|
2012-08-14 18:07:04 -04:00
|
|
|
++ip;
|
2013-09-23 14:34:35 -04:00
|
|
|
path[ip] = me->temp.fun;
|
|
|
|
(void)QEP_TRIG_(me->temp.fun, QEP_EMPTY_SIG_);/* find super */
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
2013-09-23 14:34:35 -04:00
|
|
|
me->temp.fun = path[0];
|
2012-08-14 18:07:04 -04:00
|
|
|
/* entry path must not overflow */
|
2013-09-23 14:34:35 -04:00
|
|
|
Q_ASSERT(ip < (int_t)QEP_MAX_NEST_DEPTH_);
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
do { /* retrace the entry path in reverse (correct) order... */
|
2013-02-12 10:04:39 -05:00
|
|
|
QEP_ENTER_(path[ip]); /* enter path[ip] */
|
2012-08-14 18:07:04 -04:00
|
|
|
--ip;
|
2013-09-23 14:34:35 -04:00
|
|
|
} while (ip >= (int_t)0);
|
2012-08-14 18:07:04 -04:00
|
|
|
|
|
|
|
t = path[0];
|
|
|
|
}
|
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_BEGIN_(QS_QEP_TRAN, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_TIME_(); /* time stamp */
|
|
|
|
QS_SIG_(e->sig); /* the signal of the event */
|
|
|
|
QS_OBJ_(me); /* this state machine object */
|
2013-12-30 17:37:40 -05:00
|
|
|
QS_FUN_(s); /* the source of the transition */
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_FUN_(t); /* the new active state */
|
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
}
|
|
|
|
else { /* transition not taken */
|
|
|
|
#ifdef Q_SPY
|
2013-09-23 14:34:35 -04:00
|
|
|
if (r == (QState)Q_RET_HANDLED) {
|
2012-08-14 18:07:04 -04:00
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_BEGIN_(QS_QEP_INTERN_TRAN, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_TIME_(); /* time stamp */
|
|
|
|
QS_SIG_(e->sig); /* the signal of the event */
|
|
|
|
QS_OBJ_(me); /* this state machine object */
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_FUN_(s); /* the source state */
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_BEGIN_(QS_QEP_IGNORED, QS_priv_.smObjFilter, me)
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_TIME_(); /* time stamp */
|
|
|
|
QS_SIG_(e->sig); /* the signal of the event */
|
|
|
|
QS_OBJ_(me); /* this state machine object */
|
2013-09-23 14:34:35 -04:00
|
|
|
QS_FUN_(me->state.fun); /* the current state */
|
2012-08-14 18:07:04 -04:00
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-09-23 14:34:35 -04:00
|
|
|
me->state.fun = t; /* change the current active state */
|
|
|
|
me->temp.fun = t; /* mark the configuration as stable */
|
2012-08-14 18:07:04 -04:00
|
|
|
}
|
2013-12-30 17:37:40 -05:00
|
|
|
|
|
|
|
/*..........................................................................*/
|
|
|
|
static int_t QHsm_tran_(QHsm * const me,
|
|
|
|
QStateHandler path[QEP_MAX_NEST_DEPTH_])
|
|
|
|
{
|
|
|
|
int_t ip = (int_t)(-1); /* transition entry path index */
|
|
|
|
int_t iq; /* helper transition entry path index */
|
|
|
|
QStateHandler t = path[0];
|
|
|
|
QStateHandler s = path[2];
|
|
|
|
QState r;
|
|
|
|
QS_CRIT_STAT_
|
|
|
|
|
|
|
|
if (s == t) { /* (a) check source==target (transition to self) */
|
|
|
|
QEP_EXIT_(s); /* exit the source */
|
|
|
|
ip = (int_t)0; /* enter the target */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
(void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* superstate of target */
|
|
|
|
|
|
|
|
t = me->temp.fun;
|
|
|
|
if (s == t) { /* (b) check source==target->super */
|
|
|
|
ip = (int_t)0; /* enter the target */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
(void)QEP_TRIG_(s, QEP_EMPTY_SIG_); /* superstate of src */
|
|
|
|
|
|
|
|
/* (c) check source->super==target->super */
|
|
|
|
if (me->temp.fun == t) {
|
|
|
|
QEP_EXIT_(s); /* exit the source */
|
|
|
|
ip = (int_t)0; /* enter the target */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* (d) check source->super==target */
|
|
|
|
if (me->temp.fun == path[0]) {
|
|
|
|
QEP_EXIT_(s); /* exit the source */
|
|
|
|
}
|
|
|
|
else { /* (e) check rest of source==target->super->super..
|
|
|
|
* and store the entry path along the way
|
|
|
|
*/
|
|
|
|
iq = (int_t)0; /* indicate that LCA not found */
|
|
|
|
ip = (int_t)1; /* enter target and its superstate */
|
|
|
|
path[1] = t; /* save the superstate of target */
|
|
|
|
t = me->temp.fun; /* save source->super */
|
|
|
|
/* find target->super->super */
|
|
|
|
r = QEP_TRIG_(path[1], QEP_EMPTY_SIG_);
|
|
|
|
while (r == (QState)Q_RET_SUPER) {
|
|
|
|
++ip;
|
|
|
|
path[ip] = me->temp.fun; /* store the entry path */
|
|
|
|
if (me->temp.fun == s) { /* is it the source? */
|
|
|
|
iq = (int_t)1; /* indicate that LCA found */
|
|
|
|
/* entry path must not overflow */
|
|
|
|
Q_ASSERT(ip < (int_t)QEP_MAX_NEST_DEPTH_);
|
|
|
|
--ip; /* do not enter the source */
|
|
|
|
r = (QState)Q_RET_HANDLED; /* terminate loop */
|
|
|
|
}
|
|
|
|
else { /* it is not the source, keep going up */
|
|
|
|
r = QEP_TRIG_(me->temp.fun, QEP_EMPTY_SIG_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iq == (int_t)0) { /* the LCA not found yet? */
|
|
|
|
|
|
|
|
/* entry path must not overflow */
|
|
|
|
Q_ASSERT(ip < (int_t)QEP_MAX_NEST_DEPTH_);
|
|
|
|
|
|
|
|
QEP_EXIT_(s); /* exit the source */
|
|
|
|
|
|
|
|
/* (f) check the rest of source->super
|
|
|
|
* == target->super->super...
|
|
|
|
*/
|
|
|
|
iq = ip;
|
|
|
|
r = (QState)Q_RET_IGNORED; /* LCA NOT found */
|
|
|
|
do {
|
|
|
|
if (t == path[iq]) { /* is this the LCA? */
|
|
|
|
r = (QState)Q_RET_HANDLED; /* LCA found */
|
|
|
|
/* do not enter LCA */
|
|
|
|
ip = (int_t)(iq - (int_t)1);
|
|
|
|
iq = (int_t)(-1); /* terminate the loop */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
--iq; /* try lower superstate of target */
|
|
|
|
}
|
|
|
|
} while (iq >= (int_t)0);
|
|
|
|
|
|
|
|
if (r != (QState)Q_RET_HANDLED) { /* not found? */
|
|
|
|
/* (g) check each source->super->...
|
|
|
|
* for each target->super...
|
|
|
|
*/
|
|
|
|
r = (QState)Q_RET_IGNORED; /* keep looping */
|
|
|
|
do {
|
|
|
|
/* exit t unhandled? */
|
|
|
|
if (QEP_TRIG_(t, Q_EXIT_SIG)
|
|
|
|
== (QState)Q_RET_HANDLED)
|
|
|
|
{
|
|
|
|
QS_BEGIN_(QS_QEP_STATE_EXIT,
|
|
|
|
QS_priv_.smObjFilter, me)
|
|
|
|
QS_OBJ_(me);
|
|
|
|
QS_FUN_(t);
|
|
|
|
QS_END_()
|
|
|
|
|
|
|
|
(void)QEP_TRIG_(t, QEP_EMPTY_SIG_);
|
|
|
|
}
|
|
|
|
t = me->temp.fun; /* set to super of t */
|
|
|
|
iq = ip;
|
|
|
|
do {
|
|
|
|
if (t == path[iq]) {/* is this LCA? */
|
|
|
|
/* do not enter LCA */
|
|
|
|
ip = (int_t)(iq - (int_t)1);
|
|
|
|
iq = (int_t)(-1); /* break inner */
|
|
|
|
r = (QState)Q_RET_HANDLED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
--iq;
|
|
|
|
}
|
|
|
|
} while (iq >= (int_t)0);
|
|
|
|
} while (r != (QState)Q_RET_HANDLED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ip;
|
|
|
|
}
|