source: trunk/FACT++/src/StateMachineImp.h@ 12905

Last change on this file since 12905 was 11928, checked in by tbretz, 13 years ago
Added a enum defining the first available user state.
File size: 9.1 KB
Line 
1#ifndef FACT_StateMachineImp
2#define FACT_StateMachineImp
3
4#include <map>
5#include <queue>
6#include <mutex>
7#include <vector>
8
9#include "MessageImp.h"
10
11class Event;
12class EventImp;
13
14class StateMachineImp : public MessageImp
15{
16public:
17 /// A list of default states available to any state machine.
18 /// Derived classes must define different state-number for
19 /// their purpose
20 enum DefaultStates_t
21 {
22 kSM_NotReady = -1, ///< Mainloop not running, state machine stopped
23 kSM_Ready = 0, ///< Mainloop running, state machine in operation
24 kSM_UserMode = 1, ///< First user defined mode (to be used in derived classes' enums)
25 kSM_Error = 0x100, ///< Error states should be between 0x100 and 0xffff
26 kSM_FatalError = 0xffff, ///< Fatal error: stop program
27 };
28
29private:
30 std::string fName; /// Name of the state-machine / server (e.g. DRIVE)
31
32 int fCurrentState; /// Current state of the state machine
33
34 typedef std::map<const int, std::pair<std::string, std::string>> StateNames;
35
36 /// Human readable names associated with the states
37 StateNames fStateNames;
38
39 std::vector<EventImp*> fListOfEvents; /// List of available commands as setup by user
40 std::queue<Event*> fEventQueue; /// Event queue (fifo) for the received commands
41
42 std::mutex fMutex; /// Mutex to ensure thread-safe access to the command fifo
43
44 bool fRunning; /// Machine is in main-loop
45 int fExitRequested; /// This is a flag which is set true if the main loop should stop
46
47 /// Push a command into the fifo. The fifo takes over ownership
48 void PushEvent(Event *cmd);
49 /// Pop a command from the fifo. You take over owenership
50 Event *PopEvent();
51
52 bool HandleNewState(int newstate, const EventImp *evt, const char *txt, const char *alt=0);
53 bool HandleNewState(int newstate, const char *txt)
54 {
55 return HandleNewState(newstate, 0, txt);
56 }
57
58 virtual EventImp *CreateEvent(int targetstate, const char *name, const char *fmt);
59
60 /// Is called continously to execute actions in the current state
61 virtual int Execute() { return fCurrentState; }
62 /// Is called when a configuration event is to be processed (no transition of state)
63 virtual int Configure(const Event &) { return kSM_FatalError; }
64 /// Is called when a transition change event is to be processed (from one state to another) is received
65 virtual int Transition(const Event &) { return kSM_FatalError; }
66
67 virtual void Lock() { }
68 virtual void UnLock() { }
69
70protected:
71
72 bool HandleEvent(const EventImp &evt);
73
74 /// This is an internal function to do some action in case of
75 /// a state change, like updating the corresponding service.
76 virtual std::string SetCurrentState(int state, const char *txt="", const std::string &cmd="");
77
78 EventImp &AddEvent(int targetstate, const char *name, const char *states, const char *fmt);
79 EventImp &AddEvent(int targetstate, const char *name, int s1=-1, int s2=-1, int s3=-1, int s4=-1, int s5=-1);
80 EventImp &AddEvent(int targetstate, const char *name, const char *fmt, int s1=-1, int s2=-1, int s3=-1, int s4=-1, int s5=-1);
81
82 EventImp &AddEvent(const char *name, const char *states, const char *fmt);
83 EventImp &AddEvent(const char *name, int s1=-1, int s2=-1, int s3=-1, int s4=-1, int s5=-1);
84 EventImp &AddEvent(const char *name, const char *fmt, int s1=-1, int s2=-1, int s3=-1, int s4=-1, int s5=-1);
85
86 virtual void AddStateName(const int state, const std::string &name, const std::string &doc="");
87
88 void SetDefaultStateNames();
89
90public:
91 StateMachineImp(std::ostream &out=std::cout, const std::string &name="");
92 ~StateMachineImp();
93
94 const std::string &GetName() const { return fName; }
95
96 /// return the current state of the machine
97 int GetCurrentState() const { return fCurrentState; }
98
99 void SetReady() { SetCurrentState(kSM_Ready, "set manually"); }
100 void SetNotReady() { SetCurrentState(kSM_NotReady, "set manually"); }
101
102 /// Start the mainloop
103 int Run(bool dummy);
104 int Run() { return Run(false); }
105
106 /// Request to stop the mainloop
107 void Stop(int code=1);
108
109 /// Used to check if the main loop is already running or still running
110 bool IsRunning() const { return fRunning; }
111
112 /// Post an event to the event queue
113 bool PostEvent(std::ostream &lout, const std::string &str);
114 bool PostEvent(const std::string &evt) { return PostEvent(std::cout, evt); }
115 bool PostEvent(const EventImp &evt);
116 bool PostEvent(const EventImp &evt, const char *ptr, size_t siz);
117
118 // Event handling
119 bool HasEvent(const EventImp *cmd) const;
120 EventImp *FindEvent(const std::string &evt) const;
121
122 bool IsQueueEmpty() const { return fEventQueue.size()==0; }
123
124 const std::vector<EventImp*> &GetListOfEvents() const { return fListOfEvents; }
125 const std::vector<std::string> GetEventNames() const;
126
127 void PrintListOfEvents(std::ostream &out, const std::string &evt="") const;
128 void PrintListOfEvents(const std::string &str="") const;
129
130 void PrintListOfAllowedEvents(std::ostream &out) const;
131 void PrintListOfAllowedEvents() const;
132
133 void PrintListOfStates(std::ostream &out) const;
134 void PrintListOfStates() const;
135
136
137 const std::string GetStateName(int state) const;
138 const std::string GetStateName() const { return GetStateName(fCurrentState); }
139
140 const std::string GetStateDesc(int state) const;
141 const std::string GetStateDesc() const { return GetStateDesc(fCurrentState); }
142
143 const std::string GetStateDescription(int state) const;
144 const std::string GetStateDescription() const { return GetStateDescription(fCurrentState); }
145};
146
147#endif
148
149// ***************************************************************************
150/** @fn StateMachineImp::Execute()
151
152This is what the state machine is doing in a certain state
153continously. In an idle state this might just be doing nothing.
154
155In the tracking state of the drive system this might be sending
156new command values to the drive based on its current position.
157
158The current state of the state machine can be accessed by GetCurrentState()
159
160@returns
161 Usually it should just return the current state. However, sometimes
162 execution might lead to a new state, e.g. when a hardware error
163 is detected. In this case a new state can be returned to put the state
164 machine into a different state. Note, that the function is responsible
165 of doing all actions connected with the state change itself.
166 If not overwritten it returns the current status.
167
168**/
169// ***************************************************************************
170/** @fn StateMachineImp::Configure(const Event &evt)
171
172This function is called when a configuration event is to be processed.
173
174The current state of the state machine is accessible via GetCurrentState().
175
176The issued event and its corresponding data is accessible through
177evn. (see Event and DimEvent for details) Usually such an event
178will not change the state. In this case fCurrentState will be returned.
179However, to allow the machine to go into an error state it is possible
180to change the state by giving a different return value. When the
181Configure function is called the validity of the state transition has
182already been checked.
183
184@param evt
185 A reference to an Event object with the event which should
186 be processed. Note that the cmd-object will get deleted after the
187 function has returned.
188
189@returns
190 Usually it should just return the current state. However, sometimes
191 a configuration command which was not intended to change the state
192 has to change the state, e.g. to go to an error state. Return any
193 other state than GetCurrentState() can put the state machine into
194 a different state. Note, that the function is responsible
195 of doing all actions connected with the state change itself.
196 If not overwritten it returns kSM_FatalError.
197
198**/
199// ***************************************************************************
200/** @fn StateMachineImp::Transition(const Event &evt)
201
202This function is called if a state transision was requested.
203
204The current state of the state machine is accessible via GetCurrentState().
205
206The new state is accessible via evt.GetTargetState().
207
208The event and its corresponding data is accessible through evt.
209(see DimCommand and DimEvent for details) If the transition was
210successfull the new status should be returned. If it was unsuccessfull
211either the old or any other new status will be returned.
212
213When the Transition function is called the validity of the state
214transition has already been checked.
215
216@param evt
217 A reference to an Event object with the event which should
218 be processed. Note that the cmd-object will get deleted after the
219 function has returned.
220
221@returns
222 Usually it should return the new state. However, sometimes
223 a transition command might has to change the state to a different
224 state than the one requested (e.g. an error has occured) In this
225 case it is also allowed to return a different state. Note, that the
226 function is responsible of doing all actions connected with the
227 state change itself.
228 If not overwritten it returns kSM_FatalError.
229
230**/
231// ***************************************************************************
Note: See TracBrowser for help on using the repository browser.