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

Last change on this file since 10429 was 10429, checked in by tbretz, 14 years ago
Moved the tools function into their own namespace to get rid of problems whenlinking with root.
File size: 6.9 KB
Line 
1// **************************************************************************
2/** @class StateMachineDim
3
4@brief Class for a state machine implementation within a DIM network
5
6This class implements a StateMachine within a Dim network. It redirects
7all output posted via MessageImp to a service called "NAME/MESSAGE"
8while name is the name of the machine given in the constructor. In
9addition two services are offered: NAME/STATE and NAME/VERSION.
10NAME/STATE propagates any state change to the netork.
11
12When constructing the Dim network is started and while dstruction it is
13stopped.
14
15@todo
16 Proper support for versioning
17
18*/
19// **************************************************************************
20#include "StateMachineDim.h"
21
22#include <boost/lexical_cast.hpp>
23
24#include "tools.h"
25
26#include "Time.h"
27#include "EventDim.h"
28
29using namespace std;
30using boost::lexical_cast;
31
32const int StateMachineDim::fVersion = 42;
33
34// --------------------------------------------------------------------------
35//
36//! The constrcutor first initialized DimStart with the given machine name.
37//! DimStart is just a wrapper which constructor calls DimServer::start()
38//! to ensure that initializing the Dim sub-system, is the first what is
39//! done.
40//!
41//! The second objet instantiated is the MessageDim class which offers
42//! the MESSAGE service used to broadcast logging messages to other
43//! Dim clients.
44//!
45//! After this the services STATE and VERSION are setup. STATE will
46//! be used to broadcast the state of the machine. Version broadcasts
47//! the global version number of the StateMachineDim implementation
48//!
49//! After redirecting the handler which handels dim's EXIT command
50//! to ourself (it will then call StateMachineDim::exitHandler) and
51//! adding human readable state names for the default states
52//! implemented by StateMachingImp the state is set to kSM_Initializing.
53//! Warning: The EXIT handler is global!
54//!
55//! @param name
56//! The name with which the dim-services should be prefixed, e.g.
57//! "DRIVE" will lead to "DRIVE/SERVICE". It is also propagated
58//! to DimServer::start()
59//!
60//! @param out
61//! A refrence to an ostream which allows to redirect the log-output
62//! to something else than cout. The default is cout. The reference
63//! is propagated to fLog
64//!
65//! @todo
66//! - Shell the VERSION be set from the derived class?
67//
68StateMachineDim::StateMachineDim(ostream &out, const std::string &name)
69: StateMachine(out, name), DimStart(name, *this), fLog(name, out),
70 fSrvState((name+"/STATE").c_str(), const_cast<char*>("")),
71 fSrvVersion((name+"/VERSION").c_str(), const_cast<int&>(fVersion)),
72 fDescriptionStates((name+"/STATE_LIST").c_str(), const_cast<char*>(""))
73{
74 // WARNING: This exit handler is GLOBAL!
75 DimServer::addExitHandler(this);
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
142// --------------------------------------------------------------------------
143//
144//! Overwritten DimCommand::commandHandler()
145//!
146//! If fCurrentState is smaller than 0 or we are in kSM_FatalError state,
147//! all incoming commands are ignored.
148//!
149//! The commandHandler will go through the list of available commands
150//! (fListOfEventss). If the received command was recognized, it is added
151//! via PushCommand into the fifo.
152//!
153//! @todo
154//! - Fix the exit when cmd is not of type EventImp
155//! - Fix docu
156//! - Do we need a possibility to suppress a call to "HandleEvent"
157//! or is a state<0 enough?
158//
159void StateMachineDim::commandHandler()
160{
161 DimCommand *cmd = getCommand();
162 if (!cmd)
163 return;
164
165 const EventImp *evt = dynamic_cast<EventImp*>(cmd);
166
167 // FIXME: In the case of HandleEvent there is no need to copy the data
168 // FIMXE: Currentyl the time is not copied
169 // FIXME: Handle Event is not thread safe (Dim + Console)
170 if (HasEvent(evt))
171 PostEvent(*evt);
172}
173
174// --------------------------------------------------------------------------
175//
176//! Overwrites MessageImp::Update. This redirects output issued via
177//! MessageImp to MessageDim object.
178//
179int StateMachineDim::Write(const Time &time, const string &txt, int qos)
180{
181 return fLog.Write(time, txt, qos);
182}
183
184// --------------------------------------------------------------------------
185//
186//! exitHandler of the DimServer. The EXIT command is implemented by each
187//! DimServer automatically. exitHandler calls Stop(code) and exit(-1)
188//! in case the received exit-value is a special number (42). abort()
189//! is called if 0x42 is received.
190//!
191//! @param code
192//! value which is passed to Stop(code)
193//
194void StateMachineDim::exitHandler(int code)
195{
196 Out() << " -- " << Time().GetAsStr() << ": EXIT(" << code << ") command received." << endl;
197 if (code<0) // negative values reserved for internal use
198 {
199 Out() << " -- " << Time().GetAsStr() << ": ignored." << endl;
200 return;
201 }
202
203 Stop(code);
204 if (code==42)
205 exit(-1);
206 if (code==0x42)
207 abort();
208}
Note: See TracBrowser for help on using the repository browser.