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

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