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

Last change on this file since 10379 was 10379, checked in by tbretz, 9 years ago
Added service to provide the STATE_LIST with the available descriptions of the states.
File size: 6.6 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),
67    fSrvState(Form("%s/STATE", name.c_str()).c_str(), const_cast<char*>("")),
68    fSrvVersion(Form("%s/VERSION", name.c_str()).c_str(), const_cast<int&>(fVersion)),
69    fDescriptionStates(Form("%s/STATE_LIST", name.c_str()).c_str(), const_cast<char*>(""))
70{
71    // WARNING: This exit handler is GLOBAL!
72    DimServer::addExitHandler(this);
73
74    for (StateNames::const_iterator i=fStateNames.begin(); i!=fStateNames.end(); i++)
75        DistStateName(i->first, i->second.first, i->second.second);
76}
77
78// --------------------------------------------------------------------------
79//
80//! Overwrite StateMachineImp::AddTransition to create a EventDim
81//! instead of an Event object. The event name propagated to the EventDim
82//! is fName+"/"+name.
83//!
84//! For parameter description see StateMachineImp.
85//!
86EventImp *StateMachineDim::CreateEvent(int targetstate, const char *name, const char *fmt)
87{
88    return new EventDim(targetstate, GetName()+"/"+name, fmt, this);
89}
90
91void StateMachineDim::DistStateName(const int state, const std::string &name, const std::string &doc)
92{
93    ostringstream out;
94    out << reinterpret_cast<char*>(fDescriptionStates.itsData);
95    out << state << ':' << name << '=' << doc << '\n';
96
97    fDescriptionStates.setData(const_cast<char*>(out.str().c_str()));
98    fDescriptionStates.updateService();
99}
100
101void StateMachineDim::AddStateName(const int state, const std::string &name, const std::string &doc)
102{
103    StateMachineImp::AddStateName(state, name, doc);
104    DistStateName(state, name, doc);
105}
106
107// --------------------------------------------------------------------------
108//
109//! Overwrite StateMachineImp::SetCurrentState. In addition to
110//! calling StateMachineImo::SetCurrentState the new state is also
111//! distributed via the DimService STATE.
112//!
113//! For parameter description see StateMachineImp.
114//!
115string StateMachineDim::SetCurrentState(int state, const char *txt, const std::string &cmd)
116{
117    const string msg = StateMachineImp::SetCurrentState(state, txt, cmd);
118    if (msg.empty())
119        return "";
120
121    fSrvState.setQuality(state);
122    fSrvState.setData(const_cast<char*>(msg.c_str()));
123    fSrvState.updateService();
124
125    return msg;
126}
127
128// --------------------------------------------------------------------------
129//
130//! Overwritten DimCommand::commandHandler()
131//!
132//! If fCurrentState is smaller than 0 or we are in kSM_FatalError state,
133//! all incoming commands are ignored.
134//!
135//! The commandHandler will go through the list of available commands
136//! (fListOfEventss). If the received command was recognized, it is added
137//! via PushCommand into the fifo.
138//!
139//! @todo
140//!    - Fix the exit when cmd is not of type EventImp
141//!    - Fix docu
142//!    - Do we need a possibility to suppress a call to "HandleEvent"
143//!      or is a state<0 enough?
144//
145void StateMachineDim::commandHandler()
146{
147    DimCommand *cmd = getCommand();
148    if (!cmd)
149        return;
150
151    const EventImp *evt = dynamic_cast<EventImp*>(cmd);
152
153    // FIXME: In the case of HandleEvent there is no need to copy the data
154    // FIMXE: Currentyl the time is not copied
155    // FIXME: Handle Event is not thread safe (Dim + Console)
156    if (HasEvent(evt))
157        PostEvent(*evt);
158}
159
160// --------------------------------------------------------------------------
161//
162//! Overwrites MessageImp::Update. This redirects output issued via
163//! MessageImp to MessageDim object.
164//
165int StateMachineDim::Write(const Time &time, const string &txt, int qos)
166{
167    return fLog.Write(time, txt, qos);
168}
169
170// --------------------------------------------------------------------------
171//
172//! exitHandler of the DimServer. The EXIT command is implemented by each
173//! DimServer automatically. exitHandler calls Stop(code) and exit(-1)
174//! in case the received exit-value is a special number (42). abort()
175//! is called if 0x42 is received.
176//!
177//! @param code
178//!    value which is passed to Stop(code)
179//
180void StateMachineDim::exitHandler(int code)
181{
182    Out() << " -- " << Time().GetAsStr() << ": EXIT(" << code << ") command received." << endl;
183    if (code<0) // negative values reserved for internal use
184    {
185        Out() << " -- " << Time().GetAsStr() << ": ignored." << endl;
186        return;
187    }
188
189    Stop(code);
190    if (code==42)
191        exit(-1);
192    if (code==0x42)
193        abort();
194}
Note: See TracBrowser for help on using the repository browser.