QP/C++
qhsm_dis.cpp
Go to the documentation of this file.
00001 
00002 // Product: QEP/C++
00003 // Last Updated for Version: 4.3.00
00004 // Date of the Last Update:  Nov 01, 2011
00005 //
00006 //                    Q u a n t u m     L e a P s
00007 //                    ---------------------------
00008 //                    innovating embedded systems
00009 //
00010 // Copyright (C) 2002-2011 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
00028 #include "qep_pkg.h"
00029 #include "qassert.h"
00030 
00034 
00035 #ifdef Q_USE_NAMESPACE
00036 namespace QP {
00037 #endif
00038 
00039 Q_DEFINE_THIS_MODULE(qhsm_dis)
00040 
00041 //............................................................................
00042 void QHsm::dispatch(QEvent const *e) {
00043     QStateHandler path[QEP_MAX_NEST_DEPTH_];
00044     QStateHandler s;
00045     QStateHandler t;
00046     QState r;
00047     QS_CRIT_STAT_
00048 
00049     t = m_state;                                     // save the current state
00050 
00051     QS_BEGIN_(QS_QEP_DISPATCH, QS::smObj_, this)
00052         QS_TIME_();                                              // time stamp
00053         QS_SIG_(e->sig);                            // the signal of the event
00054         QS_OBJ_(this);                            // this state machine object
00055         QS_FUN_(t);                                       // the current state
00056     QS_END_()
00057 
00058     do {                                // process the event hierarchically...
00059         s = m_state;
00060         r = (*s)(this, e);                           // invoke state handler s
00061     } while (r == Q_RET_SUPER);
00062 
00063     if (r == Q_RET_TRAN) {                                // transition taken?
00064 #ifdef Q_SPY
00065         QStateHandler src = s;       // save the transition source for tracing
00066 #endif
00067         int8_t ip = (int8_t)(-1);               // transition entry path index
00068         int8_t iq;                       // helper transition entry path index
00069 
00070         path[0] = m_state;                // save the target of the transition
00071         path[1] = t;
00072 
00073         while (t != s) {       // exit current state to transition source s...
00074             if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {   //exit handled?
00075                 QS_BEGIN_(QS_QEP_STATE_EXIT, QS::smObj_, this)
00076                     QS_OBJ_(this);                // this state machine object
00077                     QS_FUN_(t);                            // the exited state
00078                 QS_END_()
00079 
00080                 (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);    // find superstate of t
00081             }
00082             t = m_state;                       // m_state holds the superstate
00083         }
00084 
00085         t = path[0];                               // target of the transition
00086 
00087         if (s == t) {         // (a) check source==target (transition to self)
00088             QEP_EXIT_(s)                                    // exit the source
00089             ip = (int8_t)0;                                // enter the target
00090         }
00091         else {
00092             (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);        // superstate of target
00093             t = m_state;
00094             if (s == t) {                   // (b) check source==target->super
00095                 ip = (int8_t)0;                            // enter the target
00096             }
00097             else {
00098                 (void)QEP_TRIG_(s, QEP_EMPTY_SIG_);       // superstate of src
00099                                      // (c) check source->super==target->super
00100                 if (m_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 (m_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 = m_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] = m_state;        // store the entry path
00121                             if (m_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_(m_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                                     ip = (int8_t)(iq - 1); // do not enter LCA
00148                                     iq = (int8_t)(-1);   // terminate the loop
00149                                 }
00150                                 else {
00151                                     --iq;    // try lower superstate of target
00152                                 }
00153                             } while (iq >= (int8_t)0);
00154 
00155                             if (r != Q_RET_HANDLED) {    // LCA not found yet?
00156                                 // (g) check each source->super->...
00157                                 // for each target->super...
00158                                 //
00159                                 r = Q_RET_IGNORED;             // keep looping
00160                                 do {
00161                                                           // exit t unhandled?
00162                                     if (QEP_TRIG_(t, Q_EXIT_SIG)
00163                                         == Q_RET_HANDLED)
00164                                     {
00165                                         QS_BEGIN_(QS_QEP_STATE_EXIT,
00166                                                   QS::smObj_, this)
00167                                             QS_OBJ_(this);
00168                                             QS_FUN_(t);
00169                                         QS_END_()
00170 
00171                                         (void)QEP_TRIG_(t, QEP_EMPTY_SIG_);
00172                                     }
00173                                     t = m_state;         //  set to super of t
00174                                     iq = ip;
00175                                     do {
00176                                         if (t == path[iq]) {   // is this LCA?
00177                                                            // do not enter LCA
00178                                             ip = (int8_t)(iq - 1);
00179                                             iq = (int8_t)(-1);   //break inner
00180                                             r = Q_RET_HANDLED;   //break outer
00181                                         }
00182                                         else {
00183                                             --iq;
00184                                         }
00185                                     } while (iq >= (int8_t)0);
00186                                 } while (r != Q_RET_HANDLED);
00187                             }
00188                         }
00189                     }
00190                 }
00191             }
00192         }
00193                        // retrace the entry path in reverse (desired) order...
00194         for (; ip >= (int8_t)0; --ip) {
00195             QEP_ENTER_(path[ip])                             // enter path[ip]
00196         }
00197         t = path[0];                         // stick the target into register
00198         m_state = t;                               // update the current state
00199 
00200                                          // drill into the target hierarchy...
00201         while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN) {
00202 
00203             QS_BEGIN_(QS_QEP_STATE_INIT, QS::smObj_, this)
00204                 QS_OBJ_(this);                    // this state machine object
00205                 QS_FUN_(t);                        // the source (pseudo)state
00206                 QS_FUN_(m_state);              // the target of the transition
00207             QS_END_()
00208 
00209             ip = (int8_t)0;
00210             path[0] = m_state;
00211             (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);       // find superstate
00212             while (m_state != t) {
00213                 ++ip;
00214                 path[ip] = m_state;
00215                 (void)QEP_TRIG_(m_state, QEP_EMPTY_SIG_);   // find superstate
00216             }
00217             m_state = path[0];
00218                                                // entry path must not overflow
00219             Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
00220 
00221             do {       // retrace the entry path in reverse (correct) order...
00222                 QEP_ENTER_(path[ip])                         // enter path[ip]
00223                 --ip;
00224             } while (ip >= (int8_t)0);
00225 
00226             t = path[0];
00227         }
00228 
00229         QS_BEGIN_(QS_QEP_TRAN, QS::smObj_, this)
00230             QS_TIME_();                                          // time stamp
00231             QS_SIG_(e->sig);                        // the signal of the event
00232             QS_OBJ_(this);                        // this state machine object
00233             QS_FUN_(src);                      // the source of the transition
00234             QS_FUN_(t);                                // the new active state
00235         QS_END_()
00236 
00237     }
00238     else {                                             // transition not taken
00239 #ifdef Q_SPY
00240         if (r == Q_RET_IGNORED) {                            // event ignored?
00241 
00242             QS_BEGIN_(QS_QEP_IGNORED, QS::smObj_, this)
00243                 QS_TIME_();                                      // time stamp
00244                 QS_SIG_(e->sig);                    // the signal of the event
00245                 QS_OBJ_(this);                    // this state machine object
00246                 QS_FUN_(t);                               // the current state
00247             QS_END_()
00248 
00249         }
00250         else {                                                // event handled
00251 
00252             QS_BEGIN_(QS_QEP_INTERN_TRAN, QS::smObj_, this)
00253                 QS_TIME_();                                      // time stamp
00254                 QS_SIG_(e->sig);                    // the signal of the event
00255                 QS_OBJ_(this);                    // this state machine object
00256                 QS_FUN_(s);                // the state that handled the event
00257             QS_END_()
00258 
00259         }
00260 #endif
00261     }
00262     m_state = t;                 // set new state or restore the current state
00263 }
00264 
00265 #ifdef Q_USE_NAMESPACE
00266 }                                                              // namespace QP
00267 #endif