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

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