source: trunk/FACT++/src/StateMachineDim.cc@ 14002

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