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

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