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

Last change on this file since 10183 was 10183, checked in by tbretz, 9 years ago
New import.
File size: 5.8 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 "tools.h"
23
24#include "Time.h"
25#include "EventDim.h"
26
27using namespace std;
28
29const int StateMachineDim::fVersion = 42;
30
31// --------------------------------------------------------------------------
32//
33//! The constrcutor first initialized DimStart with the given machine name.
34//! DimStart is just a wrapper which constructor calls DimServer::start()
35//! to ensure that initializing the Dim sub-system, is the first what is
36//! done.
37//!
38//! The second objet instantiated is the MessageDim class which offers
39//! the MESSAGE service used to broadcast logging messages to other
40//! Dim clients.
41//!
42//! After this the services STATE and VERSION are setup. STATE will
43//! be used to broadcast the state of the machine. Version broadcasts
44//! the global version number of the StateMachineDim implementation
45//!
46//! After redirecting the handler which handels dim's EXIT command
47//! to ourself (it will then call StateMachineDim::exitHandler) and
48//! adding human readable state names for the default states
49//! implemented by StateMachingImp the state is set to kSM_Initializing.
50//! Warning: The EXIT handler is global!
51//!
52//! @param name
53//!    The name with which the dim-services should be prefixed, e.g.
54//!    "DRIVE" will lead to "DRIVE/SERVICE". It is also propagated
55//!    to DimServer::start()
56//!
57//! @param out
58//!    A refrence to an ostream which allows to redirect the log-output
59//!    to something else than cout. The default is cout. The reference
60//!    is propagated to fLog
61//!
62//! @todo
63//!    - Shell the VERSION be set from the derived class?
64//
65StateMachineDim::StateMachineDim(ostream &out, const std::string &name)
66: StateMachine(out, name), DimStart(name, *this), fLog(name, out),
67fSrvState(Form("%s/STATE", name.c_str()).c_str(), const_cast<char*>("")),
68fSrvVersion(Form("%s/VERSION", name.c_str()).c_str(), const_cast<int&>(fVersion))
69{
70    // WARNING: This exit handler is GLOBAL!
71    DimServer::addExitHandler(this);
72}
73
74// --------------------------------------------------------------------------
75//
76//! Overwrite StateMachineImp::AddTransition to create a EventDim
77//! instead of an Event object. The event name propagated to the EventDim
78//! is fName+"/"+name.
79//!
80//! For parameter description see StateMachineImp.
81//!
82EventImp *StateMachineDim::CreateEvent(int targetstate, const char *name, const char *fmt)
83{
84    return new EventDim(targetstate, GetName()+"/"+name, fmt, this);
85}
86
87// --------------------------------------------------------------------------
88//
89//! Overwrite StateMachineImp::SetCurrentState. In addition to
90//! calling StateMachineImo::SetCurrentState the new state is also
91//! distributed via the DimService STATE.
92//!
93//! For parameter description see StateMachineImp.
94//!
95string StateMachineDim::SetCurrentState(int state, const char *txt, const std::string &cmd)
96{
97    const string msg = StateMachineImp::SetCurrentState(state, txt, cmd);
98    if (msg.empty())
99        return "";
100
101    fSrvState.setQuality(state);
102    fSrvState.setData(const_cast<char*>(msg.c_str()));
103    fSrvState.updateService();
104
105    return msg;
106}
107
108// --------------------------------------------------------------------------
109//
110//! Overwritten DimCommand::commandHandler()
111//!
112//! If fCurrentState is smaller than 0 or we are in kSM_FatalError state,
113//! all incoming commands are ignored.
114//!
115//! The commandHandler will go through the list of available commands
116//! (fListOfEventss). If the received command was recognized, it is added
117//! via PushCommand into the fifo.
118//!
119//! @todo
120//!    - Fix the exit when cmd is not of type EventImp
121//!    - Fix docu
122//!    - Do we need a possibility to suppress a call to "HandleEvent"
123//!      or is a state<0 enough?
124//
125void StateMachineDim::commandHandler()
126{
127    DimCommand *cmd = getCommand();
128    if (!cmd)
129        return;
130
131    const EventImp *evt = dynamic_cast<EventImp*>(cmd);
132
133    // FIXME: In the case of HandleEvent there is no need to copy the data
134    // FIMXE: Currentyl the time is not copied
135    // FIXME: Handle Event is not thread safe (Dim + Console)
136    if (HasEvent(evt))
137        PostEvent(*evt);
138}
139
140// --------------------------------------------------------------------------
141//
142//! Overwrites MessageImp::Update. This redirects output issued via
143//! MessageImp to MessageDim object.
144//
145int StateMachineDim::Write(const Time &time, const char *txt, int qos)
146{
147    return fLog.Write(time, txt, qos);
148}
149
150// --------------------------------------------------------------------------
151//
152//! exitHandler of the DimServer. The EXIT command is implemented by each
153//! DimServer automatically. exitHandler calls Stop(code) and exit(-1)
154//! in case the received exit-value is a special number (42). abort()
155//! is called if 0x42 is received.
156//!
157//! @param code
158//!    value which is passed to Stop(code)
159//
160void StateMachineDim::exitHandler(int code)
161{
162    Out() << " -- " << Time().GetAsStr() << ": EXIT(" << code << ") command received." << endl;
163    if (code<0) // negative values reserved for internal use
164    {
165        Out() << " -- " << Time().GetAsStr() << ": ignored." << endl;
166        return;
167    }
168
169    Stop(code);
170    if (code==42)
171        exit(-1);
172    if (code==0x42)
173        abort();
174}
Note: See TracBrowser for help on using the repository browser.