QP/C
qhsm_dis.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * Product: QEP/C
00003 * Last Updated for Version: 4.4.00
00004 * Date of the Last Update:  Jan 21, 2012
00005 *
00006 *                    Q u a n t u m     L e a P s
00007 *                    ---------------------------
00008 *                    innovating embedded systems
00009 *
00010 * Copyright (C) 2002-2012 Quantum Leaps, LLC. All rights reserved.
00011 *
00012 * This software may be distributed and modified under the terms of the GNU
00013 * General Public License version 2 (GPL) as published by the Free Software
00014 * Foundation and appearing in the file GPL.TXT included in the packaging of
00015 * this file. Please note that GPL Section 2[b] requires that all works based
00016 * on this software must also be made publicly available under the terms of
00017 * the GPL ("Copyleft").
00018 *
00019 * Alternatively, this software may be distributed and modified under the
00020 * terms of Quantum Leaps commercial licenses, which expressly supersede
00021 * the GPL and are specifically designed for licensees interested in
00022 * retaining the proprietary status of their code.
00023 *
00024 * Contact information:
00025 * Quantum Leaps Web site:  http://www.quantum-leaps.com
00026 * e-mail:                  info@quantum-leaps.com
00027 *****************************************************************************/
00028 #include "qep_pkg.h"
00029 #include "qassert.h"
00030 
00031 Q_DEFINE_THIS_MODULE("qhsm_dis")
00032 
00033 
00039 /*..........................................................................*/
00040 void QHsm_dispatch(QHsm *me, QEvent const *e) {
00041     QStateHandler path[QEP_MAX_NEST_DEPTH_];
00042     QStateHandler s;
00043     QStateHandler t;
00044     QState r;
00045     QS_CRIT_STAT_
00046 
00047     t = me->state;                                /* save the current state */
00048 
00049     QS_BEGIN_(QS_QEP_DISPATCH, QS_smObj_, me)
00050         QS_TIME_();                                           /* time stamp */
00051         QS_SIG_(e->sig);                         /* the signal of the event */
00052         QS_OBJ_(me);                           /* this state machine object */
00053         QS_FUN_(t);                                    /* the current state */
00054     QS_END_()
00055 
00056     do {                             /* process the event hierarchically... */
00057         s = me->state;
00058         r = (*s)(me, e);                          /* invoke state handler s */
00059     } while (r == Q_RET_SUPER);
00060 
00061     if (r == Q_RET_TRAN) {                             /* transition taken? */
00062 #ifdef Q_SPY
00063         QStateHandler src = s;    /* save the transition source for tracing */
00064 #endif
00065         int8_t ip = (int8_t)(-1);            /* transition entry path index */
00066         int8_t iq;                    /* helper transition entry path index */
00067 
00068         path[0] = me->state;           /* save the target of the transition */
00069         path[1] = t;
00070 
00071         while (t != s) {    /* exit current state to transition source s... */
00072             if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {/*exit handled? */
00073                 QS_BEGIN_(QS_QEP_STATE_EXIT, QS_smObj_, me)
00074                     QS_OBJ_(me);               /* this state machine object */
00075                     QS_FUN_(t);                         /* the exited state */
00076                 QS_END_()
00077 
00078                 (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* find superstate of t */
00079             }
00080             t = me->state;                /* me->state holds the superstate */
00081         }
00082 
00083         t = path[0];                            /* target of the transition */
00084 
00085         if (s == t) {      /* (a) check source==target (transition to self) */
00086             QEP_EXIT_(s)                                 /* exit the source */
00087             ip = (int8_t)0;                             /* enter the target */
00088         }
00089         else {
00090             (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);     /* superstate of target */
00091 
00092             t = me->state;
00093             if (s == t) {                /* (b) check source==target->super */
00094                 ip = (int8_t)0;                         /* enter the target */
00095             }
00096             else {
00097                 (void)QEP_TRIG_(s, QEP_EMPTY_SIG_);    /* superstate of src */
00098 
00099                                   /* (c) check source->super==target->super */
00100                 if (me->state == t) {
00101                     QEP_EXIT_(s)                         /* exit the source */
00102                     ip = (int8_t)0;                     /* enter the target */
00103                 }
00104                 else {
00105                                          /* (d) check source->super==target */
00106                     if (me->state == path[0]) {
00107                         QEP_EXIT_(s)                     /* exit the source */
00108                     }
00109                     else { /* (e) check rest of source==target->super->super..
00110                             * and store the entry path along the way
00111                             */
00112                         iq = (int8_t)0;      /* indicate that LCA not found */
00113                         ip = (int8_t)1;  /* enter target and its superstate */
00114                         path[1] = t;       /* save the superstate of target */
00115                         t = me->state;                /* save source->super */
00116                                                /* find target->super->super */
00117                         r = QEP_TRIG_(path[1], QEP_EMPTY_SIG_);
00118                         while (r == Q_RET_SUPER) {
00119                             ++ip;
00120                             path[ip] = me->state;   /* store the entry path */
00121                             if (me->state == s) {      /* is it the source? */
00122                                 iq = (int8_t)1;  /* indicate that LCA found */
00123                                             /* entry path must not overflow */
00124                                 Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00125                                 --ip;            /* do not enter the source */
00126                                 r = Q_RET_HANDLED;    /* terminate the loop */
00127                             }
00128                             else {   /* it is not the source, keep going up */
00129                                 r = QEP_TRIG_(me->state, QEP_EMPTY_SIG_);
00130                             }
00131                         }
00132                         if (iq == (int8_t)0) {    /* the LCA not found yet? */
00133 
00134                                             /* entry path must not overflow */
00135                             Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00136 
00137                             QEP_EXIT_(s)                /* exit the source */
00138 
00139                                 /* (f) check the rest of source->super
00140                                  *                  == target->super->super...
00141                                  */
00142                             iq = ip;
00143                             r = Q_RET_IGNORED;    /* indicate LCA NOT found */
00144                             do {
00145                                 if (t == path[iq]) {    /* is this the LCA? */
00146                                     r = Q_RET_HANDLED;/* indicate LCA found */
00147                                                           /*do not enter LCA*/
00148                                     ip = (int8_t)(iq - (int8_t)1);
00149                                     iq = (int8_t)(-1);/* terminate the loop */
00150                                 }
00151                                 else {
00152                                     --iq; /* try lower superstate of target */
00153                                 }
00154                             } while (iq >= (int8_t)0);
00155 
00156                             if (r != Q_RET_HANDLED) { /* LCA not found yet? */
00157                                     /* (g) check each source->super->...
00158                                      * for each target->super...
00159                                      */
00160                                 r = Q_RET_IGNORED;          /* keep looping */
00161                                 do {
00162                                                        /* exit t unhandled? */
00163                                     if (QEP_TRIG_(t, Q_EXIT_SIG)
00164                                         == Q_RET_HANDLED)
00165                                     {
00166                                         QS_BEGIN_(QS_QEP_STATE_EXIT,
00167                                                   QS_smObj_, me)
00168                                             QS_OBJ_(me);
00169                                             QS_FUN_(t);
00170                                         QS_END_()
00171 
00172                                         (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);
00173                                     }
00174                                     t = me->state;    /*  set to super of t */
00175                                     iq = ip;
00176                                     do {
00177                                         if (t == path[iq]) {/* is this LCA? */
00178                                                         /* do not enter LCA */
00179                                             ip = (int8_t)(iq - (int8_t)1);
00180                                             iq = (int8_t)(-1);/*break inner */
00181                                             r = Q_RET_HANDLED;/*break outer */
00182                                         }
00183                                         else {
00184                                             --iq;
00185                                         }
00186                                     } while (iq >= (int8_t)0);
00187                                 } while (r != Q_RET_HANDLED);
00188                             }
00189                         }
00190                     }
00191                 }
00192             }
00193         }
00194                     /* retrace the entry path in reverse (desired) order... */
00195         for (; ip >= (int8_t)0; --ip) {
00196             QEP_ENTER_(path[ip])                          /* enter path[ip] */
00197         }
00198         t = path[0];                      /* stick the target into register */
00199         me->state = t;                          /* update the current state */
00200 
00201                                       /* drill into the target hierarchy... */
00202         while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN) {
00203 
00204             QS_BEGIN_(QS_QEP_STATE_INIT, QS_smObj_, me)
00205                 QS_OBJ_(me);                   /* this state machine object */
00206                 QS_FUN_(t);                     /* the source (pseudo)state */
00207                 QS_FUN_(me->state);         /* the target of the transition */
00208             QS_END_()
00209 
00210             ip = (int8_t)0;
00211             path[0] = me->state;
00212 
00213             (void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);  /* find superstate */
00214 
00215             while (me->state != t) {
00216                 ++ip;
00217                 path[ip] = me->state;
00218                                                          /* find superstate */
00219                 (void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);
00220             }
00221             me->state = path[0];
00222                                             /* entry path must not overflow */
00223             Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00224 
00225             do {    /* retrace the entry path in reverse (correct) order... */
00226                 QEP_ENTER_(path[ip])                      /* enter path[ip] */
00227                 --ip;
00228             } while (ip >= (int8_t)0);
00229 
00230             t = path[0];
00231         }
00232 
00233         QS_BEGIN_(QS_QEP_TRAN, QS_smObj_, me)
00234             QS_TIME_();                                       /* time stamp */
00235             QS_SIG_(e->sig);                     /* the signal of the event */
00236             QS_OBJ_(me);                       /* this state machine object */
00237             QS_FUN_(src);                   /* the source of the transition */
00238             QS_FUN_(t);                             /* the new active state */
00239         QS_END_()
00240 
00241     }
00242     else {                                          /* transition not taken */
00243 #ifdef Q_SPY
00244         if (r == Q_RET_IGNORED) {                         /* event ignored? */
00245 
00246             QS_BEGIN_(QS_QEP_IGNORED, QS_smObj_, me)
00247                 QS_TIME_();                                   /* time stamp */
00248                 QS_SIG_(e->sig);                 /* the signal of the event */
00249                 QS_OBJ_(me);                   /* this state machine object */
00250                 QS_FUN_(t);                            /* the current state */
00251             QS_END_()
00252 
00253         }
00254         else {                                             /* event handled */
00255 
00256             QS_BEGIN_(QS_QEP_INTERN_TRAN, QS_smObj_, me)
00257                 QS_TIME_();                                   /* time stamp */
00258                 QS_SIG_(e->sig);                 /* the signal of the event */
00259                 QS_OBJ_(me);                   /* this state machine object */
00260                 QS_FUN_(s);             /* the state that handled the event */
00261             QS_END_()
00262 
00263         }
00264 #endif
00265     }
00266     me->state = t;            /* set new state or restore the current state */
00267 }