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

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