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

Last change on this file since 11380 was 11280, checked in by tbretz, 13 years ago
Added virtual function for locking; fixed the order of instantiation of the base classes of StateMachineDim.
File size: 7.0 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 <boost/lexical_cast.hpp>
21
22#include "tools.h"
23
24#include "Time.h"
25#include "EventDim.h"
26
27using namespace std;
28using boost::lexical_cast;
29
30const 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//
66StateMachineDim::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//!
87EventImp *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//!
107void 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//!
129string 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
142void StateMachineDim::Lock()
143{
144// dim_lock();
145}
146
147void 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//
169void 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//
186int 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//
201void 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}
Note: See TracBrowser for help on using the repository browser.