Linux Face / QPFramework
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers qhsm_dis.cpp Source File

qhsm_dis.cpp

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////////
00002 // Product: QEP/C++
00003 // Last Updated for Version: 4.1.00
00004 // Date of the Last Update:  Oct 09, 2009
00005 //
00006 //                    Q u a n t u m     L e a P s
00007 //                    ---------------------------
00008 //                    innovating embedded systems
00009 //
00010 // Copyright (C) 2002-2009 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 /// \file
00034 /// \ingroup qep
00035 /// \brief QHsm::dispatch() implementation.
00036 
00037 //............................................................................
00038 void QHsm::dispatch(QEvent const *e) {
00039     QStateHandler path[QEP_MAX_NEST_DEPTH_];
00040     QStateHandler s;
00041     QStateHandler t;
00042     QState r;
00043     QS_INT_LOCK_KEY_
00044 
00045     t = m_state;                                     // save the current state
00046 
00047     QS_BEGIN_(QS_QEP_DISPATCH, QS::smObj_, this)
00048         QS_TIME_();                                              // time stamp
00049         QS_SIG_(e->sig);                            // the signal of the event
00050         QS_OBJ_(this);                            // this state machine object
00051         QS_FUN_(t);                                       // the current state
00052     QS_END_()
00053 
00054     do {                                // process the event hierarchically...
00055         s = m_state;
00056         r = (*s)(this, e);                           // invoke state handler s
00057     } while (r == Q_RET_SUPER);
00058 
00059     if (r == Q_RET_TRAN) {                                // transition taken?
00060 #ifdef Q_SPY
00061         QStateHandler src = s;       // save the transition source for tracing
00062 #endif
00063         int8_t ip = (int8_t)(-1);               // transition entry path index
00064         int8_t iq;                       // helper transition entry path index
00065 
00066         path[0] = m_state;                // save the target of the transition
00067         path[1] = t;
00068 
00069         while (t != s) {       // exit current state to transition source s...
00070             if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {   //exit handled?
00071                 QS_BEGIN_(QS_QEP_STATE_EXIT, QS::smObj_, this)
00072                     QS_OBJ_(this);                // this state machine object
00073                     QS_FUN_(t);                            // the exited state
00074                 QS_END_()
00075 
00076                 (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);    // find superstate of t
00077             }
00078             t = m_state;                       // m_state holds the superstate
00079         }
00080 
00081         t = path[0];                               // target of the transition
00082 
00083         if (s == t) {         // (a) check source==target (transition to self)
00084             QEP_EXIT_(s)                                    // exit the source
00085             ip = (int8_t)0;                                // enter the target
00086         }
00087         else {
00088             (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);        // superstate of target
00089             t = m_state;
00090             if (s == t) {                   // (b) check source==target->super
00091                 ip = (int8_t)0;                            // enter the target
00092             }
00093             else {
00094                 (void)QEP_TRIG_(s, QEP_EMPTY_SIG_);       // superstate of src
00095                                      // (c) check source->super==target->super
00096                 if (m_state == t) {
00097                     QEP_EXIT_(s)                            // exit the source
00098                     ip = (int8_t)0;                        // enter the target
00099                 }
00100                 else {
00101                                             // (d) check source->super==target
00102                     if (m_state == path[0]) {
00103                         QEP_EXIT_(s)                        // exit the source
00104                     }
00105                     else { // (e) check rest of source==target->super->super..
00106                            // and store the entry path along the way
00107                            //
00108                         iq = (int8_t)0;         // indicate that LCA not found
00109                         ip = (int8_t)1;     // enter target and its superstate
00110                         path[1] = t;          // save the superstate of target
00111                         t = m_state;                     // save source->super
00112                                                   // find target->super->super
00113                         r = QEP_TRIG_(path[1], QEP_EMPTY_SIG_);
00114                         while (r == Q_RET_SUPER) {
00115                             path[++ip] = m_state;      // store the entry path
00116                             if (m_state == s) {           // is it the source?
00117                                 iq = (int8_t)1;     // indicate that LCA found
00118                                                // entry path must not overflow
00119                                 Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00120                                 --ip;               // do not enter the source
00121                                 r = Q_RET_HANDLED;       // terminate the loop
00122                             }
00123                             else {      // it is not the source, keep going up
00124                                 r = QEP_TRIG_(m_state, QEP_EMPTY_SIG_);
00125                             }
00126                         }
00127                         if (iq == (int8_t)0) {       // the LCA not found yet?
00128 
00129                                                // entry path must not overflow
00130                             Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00131 
00132                             QEP_EXIT_(s)                   // exit the source
00133 
00134                             // (f) check the rest of source->super
00135                             //                  == target->super->super...
00136                             //
00137                             iq = ip;
00138                             r = Q_RET_IGNORED;       // indicate LCA NOT found
00139                             do {
00140                                 if (t == path[iq]) {       // is this the LCA?
00141                                     r = Q_RET_HANDLED;   // indicate LCA found
00142                                     ip = (int8_t)(iq - 1); // do not enter LCA
00143                                     iq = (int8_t)(-1);   // terminate the loop
00144                                 }
00145                                 else {
00146                                     --iq;    // try lower superstate of target
00147                                 }
00148                             } while (iq >= (int8_t)0);
00149 
00150                             if (r != Q_RET_HANDLED) {    // LCA not found yet?
00151                                 // (g) check each source->super->...
00152                                 // for each target->super...
00153                                 //
00154                                 r = Q_RET_IGNORED;             // keep looping
00155                                 do {
00156                                                           // exit t unhandled?
00157                                     if (QEP_TRIG_(t, Q_EXIT_SIG)
00158                                         == Q_RET_HANDLED)
00159                                     {
00160                                         QS_BEGIN_(QS_QEP_STATE_EXIT,
00161                                                   QS::smObj_, this)
00162                                             QS_OBJ_(this);
00163                                             QS_FUN_(t);
00164                                         QS_END_()
00165 
00166                                         (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);
00167                                     }
00168                                     t = m_state;         //  set to super of t
00169                                     iq = ip;
00170                                     do {
00171                                         if (t == path[iq]) {   // is this LCA?
00172                                                            // do not enter LCA
00173                                             ip = (int8_t)(iq - 1);
00174                                             iq = (int8_t)(-1);   //break inner
00175                                             r = Q_RET_HANDLED;   //break outer
00176                                         }
00177                                         else {
00178                                             --iq;
00179                                         }
00180                                     } while (iq >= (int8_t)0);
00181                                 } while (r != Q_RET_HANDLED);
00182                             }
00183                         }
00184                     }
00185                 }
00186             }
00187         }
00188                        // retrace the entry path in reverse (desired) order...
00189         for (; ip >= (int8_t)0; --ip) {
00190             QEP_ENTER_(path[ip])                             // enter path[ip]
00191         }
00192         t = path[0];                         // stick the target into register
00193         m_state = t;                               // update the current state
00194 
00195                                          // drill into the target hierarchy...
00196         while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN) {
00197 
00198             QS_BEGIN_(QS_QEP_STATE_INIT, QS::smObj_, this)
00199                 QS_OBJ_(this);                    // this state machine object
00200                 QS_FUN_(t);                        // the source (pseudo)state
00201                 QS_FUN_(m_state);              // the target of the transition
00202             QS_END_()
00203 
00204             ip = (int8_t)0;
00205             path[0] = m_state;
00206             (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);       // find superstate
00207             while (m_state != t) {
00208                 path[++ip] = m_state;
00209                 (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);   // find superstate
00210             }
00211             m_state = path[0];
00212                                                // entry path must not overflow
00213             Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00214 
00215             do {       // retrace the entry path in reverse (correct) order...
00216                 QEP_ENTER_(path[ip])                         // enter path[ip]
00217             } while ((--ip) >= (int8_t)0);
00218 
00219             t = path[0];
00220         }
00221 
00222         QS_BEGIN_(QS_QEP_TRAN, QS::smObj_, this)
00223             QS_TIME_();                                          // time stamp
00224             QS_SIG_(e->sig);                        // the signal of the event
00225             QS_OBJ_(this);                        // this state machine object
00226             QS_FUN_(src);                      // the source of the transition
00227             QS_FUN_(t);                                // the new active state
00228         QS_END_()
00229 
00230     }
00231     else {                                             // transition not taken
00232 #ifdef Q_SPY
00233         if (r == Q_RET_IGNORED) {                            // event ignored?
00234 
00235             QS_BEGIN_(QS_QEP_IGNORED, QS::smObj_, this)
00236                 QS_TIME_();                                      // time stamp
00237                 QS_SIG_(e->sig);                    // the signal of the event
00238                 QS_OBJ_(this);                    // this state machine object
00239                 QS_FUN_(t);                               // the current state
00240             QS_END_()
00241 
00242         }
00243         else {                                                // event handled
00244 
00245             QS_BEGIN_(QS_QEP_INTERN_TRAN, QS::smObj_, this)
00246                 QS_TIME_();                                      // time stamp
00247                 QS_SIG_(e->sig);                    // the signal of the event
00248                 QS_OBJ_(this);                    // this state machine object
00249                 QS_FUN_(s);                // the state that handled the event
00250             QS_END_()
00251 
00252         }
00253 #endif
00254     }
00255     m_state = t;                 // set new state or restore the current state
00256 }