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

Last change on this file since 14630 was 14558, checked in by tbretz, 12 years ago
Slight modification to addining new states; updating states is now allowed, added a return value, compile the string which is send as description each time again.
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",
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",
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//!
109bool StateMachineDim::AddStateName(const int state, const std::string &name, const std::string &doc)
110{
111 if (name.empty())
112 return false;
113
114 const bool rc = HasState(state) || GetStateIndex(name)!=kSM_NotAvailable;
115
116 StateMachineImp::AddStateName(state, name, doc);
117
118 string str;
119 for (auto it=fStateNames.begin(); it!=fStateNames.end(); it++)
120 str += to_string(state)+':'+name+'='+doc+'\n';
121
122 fDescriptionStates.Update(str);
123
124 return rc;
125}
126
127// --------------------------------------------------------------------------
128//
129//! Overwrite StateMachineImp::SetCurrentState. In addition to
130//! calling StateMachineImo::SetCurrentState the new state is also
131//! distributed via the DimService STATE.
132//!
133//! For parameter description see StateMachineImp.
134//!
135string StateMachineDim::SetCurrentState(int state, const char *txt, const std::string &cmd)
136{
137 const string msg = StateMachineImp::SetCurrentState(state, txt, cmd);
138 if (msg.empty())
139 return "";
140
141 fSrvState.setQuality(state);
142 fSrvState.Update(msg);
143
144 return msg;
145}
146
147// --------------------------------------------------------------------------
148//
149//! In the case of dim this secures HandleEvent against dim's commandHandler
150//!
151void StateMachineDim::Lock()
152{
153 dim_lock();
154}
155
156// --------------------------------------------------------------------------
157//
158//! In the case of dim this secures HandleEvent against dim's commandHandler
159//!
160void StateMachineDim::UnLock()
161{
162 dim_unlock();
163}
164
165void StateMachineDim::infoHandler()
166{
167 DimInfo *inf = getInfo();
168 if (!inf)
169 return;
170
171 const EventImp *evt = dynamic_cast<EventImp*>(inf);
172
173 if (HasEvent(evt))
174 PostEvent(*evt);
175}
176
177// --------------------------------------------------------------------------
178//
179//! Overwritten DimCommand::commandHandler()
180//!
181//! If fCurrentState is smaller than 0 or we are in kSM_FatalError state,
182//! all incoming commands are ignored.
183//!
184//! The commandHandler will go through the list of available commands
185//! (fListOfEventss). If the received command was recognized, it is added
186//! via PushCommand into the fifo.
187//!
188//! @todo
189//! - Fix the exit when cmd is not of type EventImp
190//! - Fix docu
191//! - Do we need a possibility to suppress a call to "HandleEvent"
192//! or is a state<0 enough?
193//
194void StateMachineDim::commandHandler()
195{
196 DimCommand *cmd = getCommand();
197 if (!cmd)
198 return;
199
200 const EventImp *evt = dynamic_cast<EventImp*>(cmd);
201
202 if (HasEvent(evt))
203 PostEvent(*evt);
204}
205
206// --------------------------------------------------------------------------
207//
208//! Overwrites MessageImp::Update. This redirects output issued via
209//! MessageImp to MessageDim object.
210//
211int StateMachineDim::Write(const Time &time, const string &txt, int qos)
212{
213 return DimLog::fLog.Write(time, txt, qos);
214}
215
216// --------------------------------------------------------------------------
217//
218//! exitHandler of the DimServer. The EXIT command is implemented by each
219//! DimServer automatically. exitHandler calls Stop(code) and exit(-1)
220//! in case the received exit-value is a special number (42). abort()
221//! is called if 0x42 is received.
222//!
223//! @param code
224//! value which is passed to Stop(code)
225//
226void StateMachineDim::exitHandler(int code)
227{
228 Out() << " -- " << Time().GetAsStr() << " - EXIT(" << code << ") command received." << endl;
229 if (code<0) // negative values reserved for internal use
230 {
231 Out() << " -- " << Time().GetAsStr() << ": ignored." << endl;
232 return;
233 }
234
235 Stop(code);
236 if (code==42)
237 exit(128);
238 if (code==0x42)
239 abort();
240}
Note: See TracBrowser for help on using the repository browser.