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

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