| 1 | // **************************************************************************
|
|---|
| 2 | /** @class StateMachineDim
|
|---|
| 3 |
|
|---|
| 4 | This class implements a StateMachine within a Dim network. It redirects
|
|---|
| 5 | all output posted via MessageImp to a service called "NAME/MESSAGE"
|
|---|
| 6 | while name is the name of the machine given in the constructor. In
|
|---|
| 7 | addition two services are offered: NAME/STATE and NAME/VERSION.
|
|---|
| 8 | NAME/STATE propagates any state change to the netork.
|
|---|
| 9 |
|
|---|
| 10 | When constructing the Dim network is started and while dstruction it is
|
|---|
| 11 | stopped.
|
|---|
| 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 |
|
|---|
| 25 | using namespace std;
|
|---|
| 26 |
|
|---|
| 27 | const 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 | //
|
|---|
| 63 | StateMachineDim::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 | //!
|
|---|
| 84 | EventImp *StateMachineDim::CreateEvent(const string &name, const string &fmt)
|
|---|
| 85 | {
|
|---|
| 86 | return new EventDim(GetName()+"/"+name, fmt, this);
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | EventImp *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 | //!
|
|---|
| 109 | bool 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(it->first)+':'+it->second.first+'='+it->second.second+'\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 | //!
|
|---|
| 135 | string 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 | //!
|
|---|
| 151 | void StateMachineDim::Lock()
|
|---|
| 152 | {
|
|---|
| 153 | dim_lock();
|
|---|
| 154 | }
|
|---|
| 155 |
|
|---|
| 156 | // --------------------------------------------------------------------------
|
|---|
| 157 | //
|
|---|
| 158 | //! In the case of dim this secures HandleEvent against dim's commandHandler
|
|---|
| 159 | //!
|
|---|
| 160 | void StateMachineDim::UnLock()
|
|---|
| 161 | {
|
|---|
| 162 | dim_unlock();
|
|---|
| 163 | }
|
|---|
| 164 |
|
|---|
| 165 | void 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 | //
|
|---|
| 194 | void 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 | //
|
|---|
| 211 | int 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 | //
|
|---|
| 226 | void 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 | }
|
|---|