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

Last change on this file since 14037 was 14008, checked in by tbretz, 12 years ago
If no exit code is given explicitly, assume that everything was ok.
File size: 9.4 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 bool fBufferEvents; /// Flag if events should be buffered outside the event loop
47 int fExitRequested; /// This is a flag which is set true if the main loop should stop
48
49 /// Push a command into the fifo. The fifo takes over ownership
50 void PushEvent(Event *cmd);
51 /// Pop a command from the fifo. You take over owenership
52 Event *PopEvent();
53
54 bool HandleNewState(int newstate, const EventImp *evt, const char *txt);
55
56 virtual EventImp *CreateEvent(const std::string &name, const std::string &fmt) = 0;
57 virtual EventImp *CreateService(const std::string &);
58
59 /// Is called continously to execute actions in the current state
60 virtual int Execute() { return fCurrentState; }
61 /// Is called when a configuration event is to be processed (no transition of state)
62 //virtual int Configure(const Event &) { return kSM_FatalError; }
63 /// Is called when a transition change event is to be processed (from one state to another) is received
64 //virtual int Transition(const Event &) { return kSM_FatalError; }
65
66 virtual void Lock() { }
67 virtual void UnLock() { }
68
69 int Wrapper(const std::function<void(const EventImp &)> &f, const EventImp &imp)
70 {
71 f(imp);
72 return GetCurrentState();
73 }
74
75protected:
76
77 bool HandleEvent(const EventImp &evt);
78
79 /// This is an internal function to do some action in case of
80 /// a state change, like updating the corresponding service.
81 virtual std::string SetCurrentState(int state, const char *txt="", const std::string &cmd="");
82
83 EventImp &AddEvent(const std::string &name, const std::string &states, const std::string &fmt);
84 EventImp &AddEvent(const std::string &name, int s1=-1, int s2=-1, int s3=-1, int s4=-1, int s5=-1);
85 EventImp &AddEvent(const std::string &name, const std::string &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 std::function<int(const EventImp &)> Wrap(const std::function<void(const EventImp &)> &func)
96 {
97 return bind(&StateMachineImp::Wrapper, this, func, std::placeholders::_1);
98 }
99
100 const std::string &GetName() const { return fName; }
101
102 EventImp &Subscribe(const std::string &name);
103
104 /// return the current state of the machine
105 int GetCurrentState() const { return fCurrentState; }
106
107 void SetReady() { SetCurrentState(kSM_Ready, "set manually"); }
108 void SetNotReady() { SetCurrentState(kSM_NotReady, "set manually"); }
109
110 /// Start the mainloop
111 int Run(bool dummy);
112 int Run() { return Run(false); }
113
114 /// Request to stop the mainloop
115 void Stop(int code=0);
116
117 /// Used to check if the main loop is already running or still running
118 bool IsRunning() const { return fRunning; }
119
120 /// Used to enable or disable buffering of events outside of the main loop
121 void EnableBuffer(bool b=true) { fBufferEvents=b; }
122
123 /// Post an event to the event queue
124 bool PostEvent(std::ostream &lout, const std::string &str);
125 bool PostEvent(const std::string &evt) { return PostEvent(std::cout, evt); }
126 bool PostEvent(const EventImp &evt);
127 bool PostEvent(const EventImp &evt, const char *ptr, size_t siz);
128
129 // Event handling
130 bool HasEvent(const EventImp *cmd) const;
131 EventImp *FindEvent(const std::string &evt) const;
132
133 bool IsQueueEmpty() const { return fEventQueue.size()==0; }
134
135 const std::vector<EventImp*> &GetListOfEvents() const { return fListOfEvents; }
136 const std::vector<std::string> GetEventNames() const;
137
138 void PrintListOfEvents(std::ostream &out, const std::string &evt="") const;
139 void PrintListOfEvents(const std::string &str="") const;
140
141 void PrintListOfAllowedEvents(std::ostream &out) const;
142 void PrintListOfAllowedEvents() const;
143
144 void PrintListOfStates(std::ostream &out) const;
145 void PrintListOfStates() const;
146
147
148 const std::string GetStateName(int state) const;
149 const std::string GetStateName() const { return GetStateName(fCurrentState); }
150
151 const std::string GetStateDesc(int state) const;
152 const std::string GetStateDesc() const { return GetStateDesc(fCurrentState); }
153
154 const std::string GetStateDescription(int state) const;
155 const std::string GetStateDescription() const { return GetStateDescription(fCurrentState); }
156};
157
158#endif
159
160// ***************************************************************************
161/** @fn StateMachineImp::Execute()
162
163This is what the state machine is doing in a certain state
164continously. In an idle state this might just be doing nothing.
165
166In the tracking state of the drive system this might be sending
167new command values to the drive based on its current position.
168
169The current state of the state machine can be accessed by GetCurrentState()
170
171@returns
172 Usually it should just return the current state. However, sometimes
173 execution might lead to a new state, e.g. when a hardware error
174 is detected. In this case a new state can be returned to put the state
175 machine into a different state. Note, that the function is responsible
176 of doing all actions connected with the state change itself.
177 If not overwritten it returns the current status.
178
179**/
180// ***************************************************************************
181/** @fn StateMachineImp::Configure(const Event &evt)
182
183This function is called when a configuration event is to be processed.
184
185The current state of the state machine is accessible via GetCurrentState().
186
187The issued event and its corresponding data is accessible through
188evn. (see Event and DimEvent for details) Usually such an event
189will not change the state. In this case fCurrentState will be returned.
190However, to allow the machine to go into an error state it is possible
191to change the state by giving a different return value. When the
192Configure function is called the validity of the state transition has
193already been checked.
194
195@param evt
196 A reference to an Event object with the event which should
197 be processed. Note that the cmd-object will get deleted after the
198 function has returned.
199
200@returns
201 Usually it should just return the current state. However, sometimes
202 a configuration command which was not intended to change the state
203 has to change the state, e.g. to go to an error state. Return any
204 other state than GetCurrentState() can put the state machine into
205 a different state. Note, that the function is responsible
206 of doing all actions connected with the state change itself.
207 If not overwritten it returns kSM_FatalError.
208
209**/
210// ***************************************************************************
211/** @fn StateMachineImp::Transition(const Event &evt)
212
213This function is called if a state transision was requested.
214
215The current state of the state machine is accessible via GetCurrentState().
216
217The new state is accessible via evt.GetTargetState().
218
219The event and its corresponding data is accessible through evt.
220(see DimCommand and DimEvent for details) If the transition was
221successfull the new status should be returned. If it was unsuccessfull
222either the old or any other new status will be returned.
223
224When the Transition function is called the validity of the state
225transition has already been checked.
226
227@param evt
228 A reference to an Event object with the event which should
229 be processed. Note that the cmd-object will get deleted after the
230 function has returned.
231
232@returns
233 Usually it should return the new state. However, sometimes
234 a transition command might has to change the state to a different
235 state than the one requested (e.g. an error has occured) In this
236 case it is also allowed to return a different state. Note, that the
237 function is responsible of doing all actions connected with the
238 state change itself.
239 If not overwritten it returns kSM_FatalError.
240
241**/
242// ***************************************************************************
Note: See TracBrowser for help on using the repository browser.