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