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

Last change on this file since 10273 was 10273, checked in by tbretz, 10 years ago
Adapted to new interface of Converter class, added the possibility to run a dummy loop.
File size: 8.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 "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::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);
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=false);
96
97    /// Request to stop the mainloop
98    void Stop(int code=1);
99
100    /// Used to check if the main loop is already running or still running
101    bool IsRunning() const { return fRunning; }
102
103    /// Post an event to the event queue
104    bool PostEvent(std::ostream &lout, const std::string &str);
105    bool PostEvent(const std::string &evt) { return PostEvent(std::cout, evt); }
106    bool PostEvent(const EventImp &evt);
107    bool PostEvent(const EventImp &evt, const char *ptr, size_t siz);
108
109    // Event handling
110    bool HasEvent(const EventImp *cmd) const;
111    EventImp *FindEvent(const std::string &evt) const;
112
113    bool IsQueueEmpty() const { return fEventQueue.size()==0; }
114
115    const std::vector<EventImp*> &GetListOfEvents() const { return fListOfEvents; }
116    const std::vector<std::string> GetEventNames() const;
117
118    void PrintListOfEvents(std::ostream &out);
119    void PrintListOfEvents();
120
121
122    const std::string GetStateName(int state) /*const*/;
123    const std::string GetStateName() { return GetStateName(fCurrentState); }
124
125    const std::string GetStateDescription(int state) /*const*/;
126    const std::string GetStateDescription() { return GetStateDescription(fCurrentState); }
127};
128
129#endif
130
131// ***************************************************************************
132/** @fn StateMachineImp::Execute()
133
134This is what the state machine is doing in a certain state
135continously. In an idle state this might just be doing nothing.
136
137In the tracking state of the drive system this might be sending
138new command values to the drive based on its current position.
139
140The current state of the state machine can be accessed by GetCurrentState()
141
142@returns
143   Usually it should just return the current state. However, sometimes
144   execution might lead to a new state, e.g. when a hardware error
145   is detected. In this case a new state can be returned to put the state
146   machine into a different state. Note, that the function is responsible
147   of doing all actions connected with the state change itself.
148   If not overwritten it returns the current status.
149
150**/
151// ***************************************************************************
152/** @fn StateMachineImp::Configure(const Event &evt)
153
154This function is called when a configuration event is to be processed.
155
156The current state of the state machine is accessible via GetCurrentState().
157
158The issued event and its corresponding data is accessible through
159evn. (see Event and DimEvent for details) Usually such an event
160will not change the state. In this case fCurrentState will be returned.
161However, to allow the machine to go into an error state it is possible
162to change the state by giving a different return value. When the
163Configure function is called the validity of the state transition has
164already been checked.
165
166@param evt
167   A reference to an Event object with the event which should
168   be processed. Note that the cmd-object will get deleted after the
169   function has returned.
170
171@returns
172   Usually it should just return the current state. However, sometimes
173   a configuration command which was not intended to change the state
174   has to change the state, e.g. to go to an error state. Return any
175   other state than GetCurrentState() can put the state machine into
176   a different state.  Note, that the function is responsible
177   of doing all actions connected with the state change itself.
178   If not overwritten it returns kSM_FatalError.
179
180**/
181// ***************************************************************************
182/** @fn StateMachineImp::Transition(const Event &evt)
183
184This function is called if a state transision was requested.
185
186The current state of the state machine is accessible via GetCurrentState().
187
188The new state is accessible via evt.GetTargetState().
189
190The event and its corresponding data is accessible through evt.
191(see DimCommand and DimEvent for details) If the transition was
192successfull the new status should be returned. If it was unsuccessfull
193either the old or any other new status will be returned.
194
195When the Transition function is called the validity of the state
196transition has already been checked.
197
198@param evt
199   A reference to an Event object with the event which should
200   be processed. Note that the cmd-object will get deleted after the
201   function has returned.
202
203@returns
204   Usually it should return the new state. However, sometimes
205   a transition command might has to change the state to a different
206   state than the one requested (e.g. an error has occured) In this
207   case it is also allowed to return a different state.  Note, that the
208   function is responsible of doing all actions connected with the
209   state change itself.
210   If not overwritten it returns kSM_FatalError.
211
212**/
213// ***************************************************************************
Note: See TracBrowser for help on using the repository browser.