1 | // **************************************************************************
|
---|
2 | /** @class StateMachineDim
|
---|
3 |
|
---|
4 | This class implements a StateMachine within a Dim network. It redirects
|
---|
5 | all output posted via MessageImp to a service called "NAME/MESSAGE"
|
---|
6 | while name is the name of the machine given in the constructor. In
|
---|
7 | addition two services are offered: NAME/STATE and NAME/VERSION.
|
---|
8 | NAME/STATE propagates any state change to the netork.
|
---|
9 |
|
---|
10 | When constructing the Dim network is started and while dstruction it is
|
---|
11 | stopped.
|
---|
12 |
|
---|
13 | @todo
|
---|
14 | Proper support for versioning
|
---|
15 |
|
---|
16 | */
|
---|
17 | // **************************************************************************
|
---|
18 | #include "StateMachineDim.h"
|
---|
19 |
|
---|
20 | #include <boost/lexical_cast.hpp>
|
---|
21 |
|
---|
22 | #include "tools.h"
|
---|
23 |
|
---|
24 | #include "Time.h"
|
---|
25 | #include "EventDim.h"
|
---|
26 |
|
---|
27 | using namespace std;
|
---|
28 | using boost::lexical_cast;
|
---|
29 |
|
---|
30 | const int StateMachineDim::fVersion = 42;
|
---|
31 |
|
---|
32 | // --------------------------------------------------------------------------
|
---|
33 | //
|
---|
34 | //! The constrcutor first initialized DimStart with the given machine name.
|
---|
35 | //! DimStart is just a wrapper which constructor calls DimServer::start()
|
---|
36 | //! to ensure that initializing the Dim sub-system, is the first what is
|
---|
37 | //! done.
|
---|
38 | //!
|
---|
39 | //! The second objet instantiated is the MessageDim class which offers
|
---|
40 | //! the MESSAGE service used to broadcast logging messages to other
|
---|
41 | //! Dim clients.
|
---|
42 | //!
|
---|
43 | //! After this the services STATE and VERSION are setup. STATE will
|
---|
44 | //! be used to broadcast the state of the machine. Version broadcasts
|
---|
45 | //! the global version number of the StateMachineDim implementation
|
---|
46 | //!
|
---|
47 | //! After redirecting the handler which handels dim's EXIT command
|
---|
48 | //! to ourself (it will then call StateMachineDim::exitHandler) and
|
---|
49 | //! adding human readable state names for the default states
|
---|
50 | //! implemented by StateMachingImp the state is set to kSM_Initializing.
|
---|
51 | //! Warning: The EXIT handler is global!
|
---|
52 | //!
|
---|
53 | //! @param name
|
---|
54 | //! The name with which the dim-services should be prefixed, e.g.
|
---|
55 | //! "DRIVE" will lead to "DRIVE/SERVICE". It is also propagated
|
---|
56 | //! to DimServer::start()
|
---|
57 | //!
|
---|
58 | //! @param out
|
---|
59 | //! A refrence to an ostream which allows to redirect the log-output
|
---|
60 | //! to something else than cout. The default is cout. The reference
|
---|
61 | //! is propagated to fLog
|
---|
62 | //!
|
---|
63 | //! @todo
|
---|
64 | //! - Shell the VERSION be set from the derived class?
|
---|
65 | //
|
---|
66 | StateMachineDim::StateMachineDim(ostream &out, const std::string &name)
|
---|
67 | : DimLog(out, name), DimStart(name, DimLog::fLog), StateMachineImp(out, name),
|
---|
68 | fDescriptionStates((name+"/STATE_LIST").c_str(), const_cast<char*>(""),
|
---|
69 | "Provides a list with descriptions for each service."
|
---|
70 | "|StateList[string]:A \\n separated list of the form id:name=description"),
|
---|
71 | fSrvState((name+"/STATE").c_str(), const_cast<char*>(""),
|
---|
72 | "Provides the state of the state machine as quality of service."
|
---|
73 | "|Text[string]:A human readable string sent by the last state change.")
|
---|
74 | // fSrvVersion((name+"/VERSION").c_str(), const_cast<int&>(fVersion)),
|
---|
75 | {
|
---|
76 | SetDefaultStateNames();
|
---|
77 | }
|
---|
78 |
|
---|
79 | // --------------------------------------------------------------------------
|
---|
80 | //
|
---|
81 | //! Overwrite StateMachineImp::AddTransition to create a EventDim
|
---|
82 | //! instead of an Event object. The event name propagated to the EventDim
|
---|
83 | //! is fName+"/"+name.
|
---|
84 | //!
|
---|
85 | //! For parameter description see StateMachineImp.
|
---|
86 | //!
|
---|
87 | EventImp *StateMachineDim::CreateEvent(int targetstate, const char *name, const char *fmt)
|
---|
88 | {
|
---|
89 | return new EventDim(targetstate, GetName()+"/"+name, fmt, this);
|
---|
90 | }
|
---|
91 |
|
---|
92 | // --------------------------------------------------------------------------
|
---|
93 | //
|
---|
94 | //! Overwrite StateMachineImp::AddStateName. In addition to storing the
|
---|
95 | //! state locally it is also propagated through Dim in the STATE_LIST
|
---|
96 | //! service.
|
---|
97 | //!
|
---|
98 | //! @param state
|
---|
99 | //! Number of the state to which a name should be assigned
|
---|
100 | //!
|
---|
101 | //! @param name
|
---|
102 | //! A name which should be assigned to the state, e.g. "Tracking"
|
---|
103 | //!
|
---|
104 | //! @param doc
|
---|
105 | //! A explanatory text describing the state
|
---|
106 | //!
|
---|
107 | void StateMachineDim::AddStateName(const int state, const std::string &name, const std::string &doc)
|
---|
108 | {
|
---|
109 | StateMachineImp::AddStateName(state, name, doc);
|
---|
110 |
|
---|
111 | const string str0 = reinterpret_cast<char*>(fDescriptionStates.itsData);
|
---|
112 | const string str1 = lexical_cast<string>(state)+':'+name+'=';
|
---|
113 |
|
---|
114 | if (str0.find(str1)!=string::npos)
|
---|
115 | return;
|
---|
116 |
|
---|
117 | fDescriptionStates.setData(const_cast<char*>((str0+str1+doc+'\n').c_str()));
|
---|
118 | fDescriptionStates.updateService();
|
---|
119 | }
|
---|
120 |
|
---|
121 | // --------------------------------------------------------------------------
|
---|
122 | //
|
---|
123 | //! Overwrite StateMachineImp::SetCurrentState. In addition to
|
---|
124 | //! calling StateMachineImo::SetCurrentState the new state is also
|
---|
125 | //! distributed via the DimService STATE.
|
---|
126 | //!
|
---|
127 | //! For parameter description see StateMachineImp.
|
---|
128 | //!
|
---|
129 | string StateMachineDim::SetCurrentState(int state, const char *txt, const std::string &cmd)
|
---|
130 | {
|
---|
131 | const string msg = StateMachineImp::SetCurrentState(state, txt, cmd);
|
---|
132 | if (msg.empty())
|
---|
133 | return "";
|
---|
134 |
|
---|
135 | fSrvState.setQuality(state);
|
---|
136 | fSrvState.setData(const_cast<char*>(msg.c_str()));
|
---|
137 | fSrvState.updateService();
|
---|
138 |
|
---|
139 | return msg;
|
---|
140 | }
|
---|
141 |
|
---|
142 | void StateMachineDim::Lock()
|
---|
143 | {
|
---|
144 | // dim_lock();
|
---|
145 | }
|
---|
146 |
|
---|
147 | void StateMachineDim::UnLock()
|
---|
148 | {
|
---|
149 | // dim_unlock();
|
---|
150 | }
|
---|
151 |
|
---|
152 | // --------------------------------------------------------------------------
|
---|
153 | //
|
---|
154 | //! Overwritten DimCommand::commandHandler()
|
---|
155 | //!
|
---|
156 | //! If fCurrentState is smaller than 0 or we are in kSM_FatalError state,
|
---|
157 | //! all incoming commands are ignored.
|
---|
158 | //!
|
---|
159 | //! The commandHandler will go through the list of available commands
|
---|
160 | //! (fListOfEventss). If the received command was recognized, it is added
|
---|
161 | //! via PushCommand into the fifo.
|
---|
162 | //!
|
---|
163 | //! @todo
|
---|
164 | //! - Fix the exit when cmd is not of type EventImp
|
---|
165 | //! - Fix docu
|
---|
166 | //! - Do we need a possibility to suppress a call to "HandleEvent"
|
---|
167 | //! or is a state<0 enough?
|
---|
168 | //
|
---|
169 | void StateMachineDim::commandHandler()
|
---|
170 | {
|
---|
171 | DimCommand *cmd = getCommand();
|
---|
172 | if (!cmd)
|
---|
173 | return;
|
---|
174 |
|
---|
175 | const EventImp *evt = dynamic_cast<EventImp*>(cmd);
|
---|
176 |
|
---|
177 | if (HasEvent(evt))
|
---|
178 | PostEvent(*evt);
|
---|
179 | }
|
---|
180 |
|
---|
181 | // --------------------------------------------------------------------------
|
---|
182 | //
|
---|
183 | //! Overwrites MessageImp::Update. This redirects output issued via
|
---|
184 | //! MessageImp to MessageDim object.
|
---|
185 | //
|
---|
186 | int StateMachineDim::Write(const Time &time, const string &txt, int qos)
|
---|
187 | {
|
---|
188 | return DimLog::fLog.Write(time, txt, qos);
|
---|
189 | }
|
---|
190 |
|
---|
191 | // --------------------------------------------------------------------------
|
---|
192 | //
|
---|
193 | //! exitHandler of the DimServer. The EXIT command is implemented by each
|
---|
194 | //! DimServer automatically. exitHandler calls Stop(code) and exit(-1)
|
---|
195 | //! in case the received exit-value is a special number (42). abort()
|
---|
196 | //! is called if 0x42 is received.
|
---|
197 | //!
|
---|
198 | //! @param code
|
---|
199 | //! value which is passed to Stop(code)
|
---|
200 | //
|
---|
201 | void StateMachineDim::exitHandler(int code)
|
---|
202 | {
|
---|
203 | Out() << " -- " << Time().GetAsStr() << " - EXIT(" << code << ") command received." << endl;
|
---|
204 | if (code<0) // negative values reserved for internal use
|
---|
205 | {
|
---|
206 | Out() << " -- " << Time().GetAsStr() << ": ignored." << endl;
|
---|
207 | return;
|
---|
208 | }
|
---|
209 |
|
---|
210 | Stop(code);
|
---|
211 | if (code==42)
|
---|
212 | exit(-1);
|
---|
213 | if (code==0x42)
|
---|
214 | abort();
|
---|
215 | }
|
---|