FSMA.h

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Andras Varga and Levente Meszaros
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00016 //
00017 
00018 #ifndef __INET_FSMA_H
00019 #define __INET_FSMA_H
00020 
00021 #include "INETDefs.h"
00022 
00023 /*
00024     This is an alternative FSM implementation.
00025 
00026     Here is an example:
00027 
00028     FSMA_Switch(fsm)
00029     {
00030         FSMA_State(X)
00031         {
00032             FSMA_Event_Transition(XY, isFoo, Y,
00033                 doFoo);
00034             FSMA_No_Event_Transition(XZ, isFooBar, Z,
00035                 doFooBar);
00036         }
00037         FSMA_State(Y)
00038         {
00039             FSMA_Event_Transition(YX, isBar, X,
00040                 doBar);
00041         }
00042         FSMA_State(Z)
00043         {
00044             FSMA_Event_Transition(ZX, isBaz, X,
00045                 doBaz);
00046         }
00047     }
00048 
00049     After macro expansion, a state machine code looks like something along
00050     these lines:
00051 
00052     bool ___is_event = true;
00053     bool ___exit = false;
00054     int ___c = 0;
00055     cFSM ___fsm = fsm;
00056     while (!___exit && (___c++ < FSM_MAXT || opp_error(eINFLOOP, ___fsm->getStateName()))
00057     {
00058         if (condition_seen = false, ___exit = true, ___fsm->getState() == X)
00059         {
00060             if (!___is_event)
00061             {
00062                 if (condition_seen)
00063                     error("...");
00064                 // enter code
00065             }
00066             condition_seen = true; if (isFoo && ___is_event)
00067             {
00068                 EV << "firing " << XY << " transition for " << ___fsm->getName() << endl;
00069                 doFoo;
00070                 ___fsm->setState(Y, "Y");
00071                 ___is_event = false;
00072                 ___exit = false;
00073                 continue;
00074             }
00075             condition_seen = true; if (isFooBar && !___is_event)
00076             {
00077                 EV << "firing " << XZ << " transition for " << ___fsm->getName() << endl;
00078                 doFooBar;
00079                 ___fsm->setState(Z, "Z");
00080                 ___exit = false;
00081                 continue;
00082             }
00083         }
00084         if (condition_seen = false, ___exit = true, ___fsm->getState() == Y)
00085         {
00086             condition_seen = true; if (isBar && ___is_event)
00087             {
00088                 EV << "firing " << YX << " transition for " << ___fsm->getName() << endl;
00089                 doVar;
00090                 ___fsm->setState(X, "X");
00091                 ___is_event = false;
00092                 ___exit = false;
00093                 continue;
00094             }
00095         }
00096     }
00097 */
00098 
00099 #define FSMA_Switch(fsm)                                               \
00100     bool ___is_event = true;                                           \
00101     bool ___exit = false;                                              \
00102     bool ___condition_seen = false;                                    \
00103     int ___c = 0;                                                      \
00104     cFSM *___fsm = &fsm;                                               \
00105     EV << "processing event in state machine " << (fsm).getName() << endl;  \
00106     while (!___exit && (___c++ < FSM_MAXT || (opp_error(eINFLOOP, (fsm).getStateName()), 0)))
00107 
00108 #define FSMA_Print(exiting)                                            \
00109     (ev << "FSM " << ___fsm->getName()                                    \
00110         << ((exiting) ? ": leaving state  " : ": entering state ")     \
00111         << ___fsm->getStateName() << endl)
00112 
00113 #define FSMA_State(s)  if (___condition_seen = false, ___exit = true, ___fsm->getState() == (s))
00114 
00115 #define FSMA_Event_Transition(transition, condition, target, action)                    \
00116     ___condition_seen = true; if ((condition) && ___is_event)                             \
00117     {                                                                                   \
00118         ___is_event = false;                                                            \
00119         FSMA_Transition(transition, (condition), target, action)
00120 
00121 #define FSMA_No_Event_Transition(transition, condition, target, action)                 \
00122     ___condition_seen = true; if ((condition) && !___is_event)                            \
00123     {                                                                                   \
00124         FSMA_Transition(transition, (condition), target, action)
00125 
00126 #define FSMA_Transition(transition, condition, target, action)                          \
00127         FSMA_Print(true);                                                               \
00128         EV << "firing " << #transition << " transition for " << ___fsm->getName() << endl; \
00129         action;                                                                         \
00130         ___fsm->setState(target, #target);                                              \
00131         FSMA_Print(false);                                                              \
00132         ___exit = false;                                                                \
00133         continue;                                                                       \
00134     }
00135 
00136 #define FSMA_Enter(action)                                                              \
00137     if (!___is_event)                                                                   \
00138     {                                                                                   \
00139         if (___condition_seen)                                                          \
00140             error("FSMA_Enter() must precede all FSMA_*_Transition()'s in the code");   \
00141         action;                                                                         \
00142     }
00143 
00144 #endif
00145