Statistics
| Branch: | Revision:

root / include / cfsm.h @ ffa9279f

History | View | Annotate | Download (7.55 KB)

1
//==========================================================================
2
//   CFSM.H  -  header for
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
//  Contents:
7
//    FSM building macros
8
//    class cFSM: stores the state of an FSM
9
//
10
//==========================================================================
11

    
12
/*--------------------------------------------------------------*
13
  Copyright (C) 1992-2008 Andras Varga
14
  Copyright (C) 2006-2008 OpenSim Ltd.
15

16
  This file is distributed WITHOUT ANY WARRANTY. See the file
17
  `license' for details on this and other legal matters.
18
*--------------------------------------------------------------*/
19

    
20
#ifndef __CFSM_H
21
#define __CFSM_H
22

    
23
#include "cownedobject.h"
24

    
25
NAMESPACE_BEGIN
26

    
27
/**
28
 * @ingroup Macros
29
 * @defgroup MacrosFSM Final State Machine macros
30
 */
31
//@{
32

    
33
/**
34
 * After this many transitions without reaching a steady state
35
 * we assume the FSM is in an infinite loop.
36
 */
37
#define FSM_MAXT  64
38

    
39
/**
40
 * Implements a Finite State Machine. FSM state is stored in
41
 * an object of type cFSM.
42
 *
43
 * There are two kinds of states: transient and steady. At each
44
 * execution of the FSM_Switch() statement, the FSM transitions out
45
 * of the current (steady) state, potentially undergoes a series of
46
 * state changes to transient states, and arrives at another
47
 * steady state.
48
 *
49
 * The actual FSM is embedded in an FSM_Switch(), which has cases for
50
 * entering and leaving each state:
51
 *
52
 * <PRE>
53
 * FSM_Switch(fsm)
54
 * {
55
 *     case FSM_Exit(state1):
56
 *         //...
57
 *         break;
58
 *     case FSM_Enter(state1):
59
 *         //...
60
 *         break;
61
 *     case FSM_Exit(state2):
62
 *         //...
63
 *         break;
64
 *     case FSM_Enter(state2):
65
 *         //...
66
 *         break;
67
 *     //...
68
 * }
69
 * </PRE>
70
 *
71
 * States are declared in enums, using the FSM_Transient() and FSM_Steady() macros.
72
 *
73
 * State transitions are done via calls to FSM_Goto(), which simply stores the
74
 * new state in the cFSM object.
75
 *
76
 * @hideinitializer
77
 * @see cFSM, FSM_Transient, FSM_Steady, FSM_Goto, FSM_Debug, FSM_Print
78
 */
79
//
80
// operation:
81
// - __i counts up (starting from 1) until the FSM reaches a steady state.
82
// - at __i=1,3,5,7,etc, FSM_Exit code is executed
83
// - at __i=2,4,6,8,etc, FSM_Enter code is executed
84
// - FSM_Enter code must not contain state change (this is verified)
85
// - state changes should be encoded in FSM_Exit code
86
// - infinite loops (when control never reaches steady state) are detected (FSM_MAXT)
87
//
88
#define FSM_Switch(fsm)  \
89
   for (int __i=1, __savedstate;  \
90
        (__i<3 || (__i&1)==0 || (fsm).isInTransientState()) &&  \
91
        (__i<2*FSM_MAXT || (opp_error(eINFLOOP,(fsm).getStateName()),0));  \
92
        ((__i&1)==0 && __savedstate!=(fsm).getState() &&  \
93
         (opp_error(eSTATECHG,(fsm).getStateName()),0)),  \
94
         __savedstate=(fsm).getState(),++__i)  \
95
     switch (FSM_Print(fsm,__i&1),(((fsm).getState()<<1)|(__i&1)))
96

    
97
/**
98
 * Declares a transient state; to be used in enum which declares states.
99
 * Example:
100
 *
101
 * <PRE>
102
 * enum {
103
 *    INIT = 0,
104
 *    SLEEP = FSM_Steady(1),
105
 *    ACTIVE = FSM_Steady(2),
106
 *    SEND = FSM_Transient(1),
107
 * };
108
 * </PRE>
109
 *
110
 * The numbers in parens must be unique within the state type and they are
111
 * used for constructing numeric IDs for the states.
112
 *
113
 * @hideinitializer
114
 * @see FSM_Steady, FSM_Switch
115
 */
116
#define FSM_Transient(state)   (-(state))
117

    
118
/**
119
 * Declares a steady state; to be used in enum which declares states.
120
 * See example in FSM_Transient.
121
 *
122
 * @hideinitializer
123
 * @see FSM_Transient, FSM_Switch
124
 */
125
#define FSM_Steady(state)      (state)
126

    
127
/**
128
 * Within an FSM_Switch() case branch, declares code to be executed
129
 * on entering the given state. No calls to FSM_Goto() are allowed
130
 * within a state's Enter block.
131
 *
132
 * @hideinitializer
133
 * @see FSM_Switch
134
 */
135
#define FSM_Enter(state)  ((state)<<1)
136

    
137
/**
138
 * Within an FSM_Switch() case branch, declares code to be executed
139
 * on exiting the given state.
140
 *
141
 * @hideinitializer
142
 * @see FSM_Switch
143
 */
144
#define FSM_Exit(state)   (((state)<<1)|1)
145

    
146
/**
147
 * To be used in state exit code, to transition to another state.
148
 *
149
 * Uses stringize (\#state), so it only works correctly if 'state'
150
 * is the enum name itself and not some variable that contains the
151
 * state code.
152
 *
153
 * @hideinitializer
154
 * @see FSM_Switch
155
 */
156
#define FSM_Goto(fsm,state)   (fsm).setState(state,#state)
157

    
158
#ifdef FSM_DEBUG
159
/**
160
 * #define FSM_DEBUG before #including "omnetpp.h" to enable reporting
161
 * all state changes to ev.
162
 *
163
 * @hideinitializer
164
 * @see FSM_Switch
165
 */
166
#define FSM_Print(fsm,exiting) \
167
    (ev << "FSM " << (fsm).getName() \
168
        << ((exiting) ? ": leaving state  " : ": entering state ") \
169
        << (fsm).getStateName() << endl)
170
// this may also be useful as third line:
171
//      << ((fsm).isInTransientState() ? "transient state " : "steady state ")
172
#else
173
#define FSM_Print(fsm,entering) ((void)0)
174
#endif
175

    
176
//@}
177

    
178
//-----------------------------------------------------
179

    
180
/**
181
 * Store the state of an FSM. This class is used in conjunction with
182
 * the FSM_Switch() and other FSM_ macros.
183
 *
184
 * @ingroup SimSupport
185
 * @see FSM_Switch, FSM_Transient, FSM_Steady, FSM_Enter, FSM_Exit, FSM_Goto
186
 */
187
class SIM_API cFSM : public cOwnedObject
188
{
189
  private:
190
    //
191
    // About state codes:
192
    //  initial state is number 0
193
    //  negative state codes are transient states
194
    //  positive state codes are steady states
195
    //
196
    int _state;
197
    const char *_statename;   // just a ptr to an external string
198

    
199
  public:
200
    /** @name Constructors, destructor, assignment. */
201
    //@{
202

    
203
    /**
204
     * Constructor.
205
     */
206
    explicit cFSM(const char *name=NULL);
207

    
208
    /**
209
     * Copy constructor.
210
     */
211
    cFSM(const cFSM& vs) : cOwnedObject() {setName(vs.getName());operator=(vs);}
212

    
213
    /**
214
     * Assignment operator. The name member is not copied;
215
     * see cOwnedObject's operator=() for more details.
216
     */
217
    cFSM& operator=(const cFSM& vs);
218
    //@}
219

    
220
    /** @name Redefined cObject member functions. */
221
    //@{
222

    
223
    /**
224
     * Creates and returns an exact copy of this object.
225
     * See cObject for more details.
226
     */
227
    virtual cFSM *dup() const  {return new cFSM(*this);}
228

    
229
    /**
230
     * Produces a one-line description of the object's contents.
231
     * See cObject for more details.
232
     */
233
    virtual std::string info() const;
234

    
235
    /**
236
     * Serializes the object into an MPI send buffer.
237
     * Used by the simulation kernel for parallel execution.
238
     * See cObject for more details.
239
     */
240
    virtual void parsimPack(cCommBuffer *buffer);
241

    
242
    /**
243
     * Deserializes the object from an MPI receive buffer
244
     * Used by the simulation kernel for parallel execution.
245
     * See cObject for more details.
246
     */
247
    virtual void parsimUnpack(cCommBuffer *buffer);
248
    //@}
249

    
250
    /** @name FSM functions. */
251
    //@{
252

    
253
    /**
254
     * Returns the state the FSM is currently in.
255
     */
256
    int getState() const  {return _state;}
257

    
258
    /**
259
     * Returns the name of the state the FSM is currently in.
260
     */
261
    const char *getStateName() const {return _statename?_statename:"";}
262

    
263
    /**
264
     * Returns true if the FSM is currently in a transient state.
265
     */
266
    int isInTransientState() const  {return _state<0;}
267

    
268
    /**
269
     * Sets the state of the FSM. This method is usually invoked through
270
     * the FSM_Goto() macro.
271
     *
272
     * The first arg is the state code. The second arg is the name of the state.
273
     * setState() assumes this is pointer to a string literal (the string is
274
     * not copied, only the pointer is stored).
275
     *
276
     * @see FSM_Goto
277
     */
278
    void setState(int state, const char *stn=NULL)  {_state=state;_statename=stn;}
279
    //@}
280
};
281

    
282
NAMESPACE_END
283

    
284

    
285
#endif