1 #include "otsdaq/FiniteStateMachine/RunControlStateMachine.h"
2 #include "otsdaq/MessageFacility/MessageFacility.h"
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/Macros/StringMacros.h"
7 #include "otsdaq/SOAPUtilities/SOAPCommand.h"
8 #include "otsdaq/SOAPUtilities/SOAPUtilities.h"
10 #include <toolbox/fsm/FailedEvent.h>
11 #include <xdaq/NamespaceURI.h>
12 #include <xoap/Method.h>
17 #define __MF_SUBJECT__ std::string("FSM-") + theStateMachine_.getStateMachineName()
21 const std::string RunControlStateMachine::FAILED_STATE_NAME =
"Failed";
22 const std::string RunControlStateMachine::HALTED_STATE_NAME =
"Halted";
25 RunControlStateMachine::RunControlStateMachine(
const std::string& name)
26 : theStateMachine_(name)
27 , asyncFailureReceived_(false)
28 , asyncSoftFailureReceived_(false)
30 INIT_MF(
"RunControlStateMachine");
32 theStateMachine_.addState(
33 'I',
"Initial",
this, &RunControlStateMachine::stateInitial);
34 theStateMachine_.addState(
'H', RunControlStateMachine::HALTED_STATE_NAME,
this, &RunControlStateMachine::stateHalted);
35 theStateMachine_.addState(
36 'C',
"Configured",
this, &RunControlStateMachine::stateConfigured);
37 theStateMachine_.addState(
38 'R',
"Running",
this, &RunControlStateMachine::stateRunning);
39 theStateMachine_.addState(
'P',
"Paused",
this, &RunControlStateMachine::statePaused);
40 theStateMachine_.addState(
41 'X',
"Shutdown",
this, &RunControlStateMachine::stateShutdown);
50 theStateMachine_.setStateName(
'F', RunControlStateMachine::FAILED_STATE_NAME);
51 theStateMachine_.setFailedStateTransitionAction(
52 this, &RunControlStateMachine::enteringError);
53 theStateMachine_.setFailedStateTransitionChanged(
this,
54 &RunControlStateMachine::inError);
57 RunControlStateMachine::addStateTransition(
58 'F',
'H',
"Halt",
"Halting",
this, &RunControlStateMachine::transitionHalting);
59 RunControlStateMachine::addStateTransition(
65 &RunControlStateMachine::transitionShuttingDown);
67 RunControlStateMachine::addStateTransition(
74 &RunControlStateMachine::transitionConfiguring);
75 RunControlStateMachine::addStateTransition(
81 &RunControlStateMachine::transitionShuttingDown);
82 RunControlStateMachine::addStateTransition(
88 &RunControlStateMachine::transitionStartingUp);
91 RunControlStateMachine::addStateTransition(
97 &RunControlStateMachine::transitionInitializing);
98 RunControlStateMachine::addStateTransition(
99 'H',
'H',
"Halt",
"Halting",
this, &RunControlStateMachine::transitionHalting);
100 RunControlStateMachine::addStateTransition(
101 'C',
'H',
"Halt",
"Halting",
this, &RunControlStateMachine::transitionHalting);
102 RunControlStateMachine::addStateTransition(
103 'R',
'H',
"Abort",
"Aborting",
this, &RunControlStateMachine::transitionHalting);
104 RunControlStateMachine::addStateTransition(
105 'P',
'H',
"Abort",
"Aborting",
this, &RunControlStateMachine::transitionHalting);
107 RunControlStateMachine::addStateTransition(
108 'R',
'P',
"Pause",
"Pausing",
this, &RunControlStateMachine::transitionPausing);
109 RunControlStateMachine::addStateTransition(
115 &RunControlStateMachine::transitionResuming);
116 RunControlStateMachine::addStateTransition(
117 'C',
'R',
"Start",
"Starting",
this, &RunControlStateMachine::transitionStarting);
118 RunControlStateMachine::addStateTransition(
119 'R',
'C',
"Stop",
"Stopping",
this, &RunControlStateMachine::transitionStopping);
120 RunControlStateMachine::addStateTransition(
121 'P',
'C',
"Stop",
"Stopping",
this, &RunControlStateMachine::transitionStopping);
126 &RunControlStateMachine::runControlMessageHandler,
130 &RunControlStateMachine::runControlMessageHandler,
134 this, &RunControlStateMachine::runControlMessageHandler,
"Start", XDAQ_NS_URI);
136 this, &RunControlStateMachine::runControlMessageHandler,
"Stop", XDAQ_NS_URI);
138 this, &RunControlStateMachine::runControlMessageHandler,
"Pause", XDAQ_NS_URI);
140 this, &RunControlStateMachine::runControlMessageHandler,
"Resume", XDAQ_NS_URI);
142 this, &RunControlStateMachine::runControlMessageHandler,
"Halt", XDAQ_NS_URI);
144 this, &RunControlStateMachine::runControlMessageHandler,
"Abort", XDAQ_NS_URI);
146 this, &RunControlStateMachine::runControlMessageHandler,
"Shutdown", XDAQ_NS_URI);
148 this, &RunControlStateMachine::runControlMessageHandler,
"Startup", XDAQ_NS_URI);
150 this, &RunControlStateMachine::runControlMessageHandler,
"Fail", XDAQ_NS_URI);
152 this, &RunControlStateMachine::runControlMessageHandler,
"Error", XDAQ_NS_URI);
155 &RunControlStateMachine::runControlMessageHandler,
159 &RunControlStateMachine::runControlMessageHandler,
167 RunControlStateMachine::~RunControlStateMachine(
void) {}
170 void RunControlStateMachine::reset(
void)
172 __COUT__ <<
"Resetting RunControlStateMachine with name '"
173 << theStateMachine_.getStateMachineName() <<
"'..." << __E__;
174 theStateMachine_.setInitialState(
'I');
175 theStateMachine_.reset();
177 theStateMachine_.setErrorMessage(
"",
false );
179 asyncFailureReceived_ =
false;
180 asyncSoftFailureReceived_ =
false;
212 xoap::MessageReference RunControlStateMachine::runControlMessageHandler(
213 xoap::MessageReference message)
216 __COUT__ <<
"Received... \t" << SOAPUtilities::translate(message) << std::endl;
218 std::string command = SOAPUtilities::translate(message).getCommand();
223 StringMacros::getNumber(
224 SOAPUtilities::translate(message).getParameters().getValue(
"iterationIndex"),
229 __COUT__ <<
"Defaulting iteration index to 0." << __E__;
235 StringMacros::getNumber(
236 SOAPUtilities::translate(message).getParameters().getValue(
237 "subIterationIndex"),
242 __COUT__ <<
"Defaulting subIterationIndex_ index to 0." << __E__;
243 subIterationIndex_ = 0;
249 if(SOAPUtilities::translate(message).getParameters().getValue(
"retransmission") ==
255 if(lastIterationCommand_ == command &&
256 lastIterationIndex_ == iterationIndex_ &&
257 lastSubIterationIndex_ == subIterationIndex_)
260 <<
"Assuming a timeout occurred at Gateway waiting for a response. "
261 <<
"Attempting to avoid error, by giving last result for command '"
262 << command <<
"': " << lastIterationResult_ << __E__;
263 return SOAPUtilities::makeSOAPMessageReference(lastIterationResult_);
266 __COUT__ <<
"Looks like Gateway command '" << command
267 <<
"' was lost - attempting to handle retransmission." << __E__;
275 lastIterationIndex_ = iterationIndex_;
276 lastSubIterationIndex_ = subIterationIndex_;
278 std::string currentState;
279 if(iterationIndex_ == 0 && subIterationIndex_ == 0)
282 theProgressBar_.reset(command, theStateMachine_.getStateMachineName());
283 currentState = theStateMachine_.getCurrentStateName();
284 __COUT__ <<
"Starting state for " << theStateMachine_.getStateMachineName()
285 <<
" is " << currentState <<
" and attempting to " << command
290 currentState = theStateMachine_.getStateName(lastIterationState_);
292 __COUT__ <<
"Iteration index " << iterationIndex_ <<
"." << subIterationIndex_
293 <<
" for " << theStateMachine_.getStateMachineName() <<
" from "
294 << currentState <<
" attempting to " << command << std::endl;
297 RunControlStateMachine::theProgressBar_.step();
299 std::string result = command +
"Done";
300 lastIterationResult_ = result;
304 if(command ==
"Error" || command ==
"Fail")
306 __SS__ << command <<
" was received! Halting immediately." << std::endl;
307 __COUT_ERR__ <<
"\n" << ss.str();
311 if(currentState ==
"Configured")
312 theStateMachine_.execTransition(
"Halt", message);
313 else if(currentState ==
"Running" || currentState ==
"Paused")
314 theStateMachine_.execTransition(
"Abort", message);
318 __COUT_ERR__ <<
"Halting failed in reaction to " << command <<
"... ignoring."
321 return SOAPUtilities::makeSOAPMessageReference(result);
323 else if(command ==
"AsyncError")
325 std::string errorMessage =
326 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
328 __SS__ << command <<
" was received! Error'ing immediately: " << errorMessage
330 __COUT_ERR__ <<
"\n" << ss.str();
331 theStateMachine_.setErrorMessage(ss.str());
333 asyncFailureReceived_ =
true;
335 theStateMachine_.execTransition(
"fail");
338 return SOAPUtilities::makeSOAPMessageReference(result);
340 else if(command ==
"AsyncSoftError")
342 std::string errorMessage =
343 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
345 __SS__ << command <<
" was received! Pause'ing immediately: " << errorMessage
347 __COUT_ERR__ <<
"\n" << ss.str();
348 theStateMachine_.setErrorMessage(ss.str());
350 if(!asyncSoftFailureReceived_)
352 asyncSoftFailureReceived_ =
true;
355 theStateMachine_.execTransition(
"Pause");
358 return SOAPUtilities::makeSOAPMessageReference(result);
363 if(command ==
"Initialize" && currentState == RunControlStateMachine::HALTED_STATE_NAME)
365 __COUT__ <<
"Already Initialized.. ignoring Initialize command." << std::endl;
367 theStateMachine_.setErrorMessage(
"",
false );
368 return SOAPUtilities::makeSOAPMessageReference(result);
372 __COUTV__(currentState);
374 if(command ==
"Halt" && currentState ==
"Initial")
376 __COUT__ <<
"Converting Halt command to Initialize, since currently in "
379 command =
"Initialize";
380 message = SOAPUtilities::makeSOAPMessageReference(command);
386 theStateMachine_.setErrorMessage(
"",
false );
388 iterationWorkFlag_ =
false;
389 subIterationWorkFlag_ =
false;
390 if(iterationIndex_ || subIterationIndex_)
392 __COUT__ << command <<
" iteration " << iterationIndex_ <<
"."
393 << subIterationIndex_ << __E__;
394 toolbox::Event::Reference event(
new toolbox::Event(command,
this));
399 __COUT__ <<
"Iterating on the transition function from " << currentState
400 <<
" through " << lastIterationCommand_ << __E__;
402 auto itFrom = stateTransitionFunctionTable_.find(lastIterationState_);
403 if(itFrom == stateTransitionFunctionTable_.end())
405 __SS__ <<
"Cannot find transition function from '" << currentState
406 <<
"' with transition '" << lastIterationCommand_ <<
"!'"
408 __COUT_ERR__ << ss.str();
409 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
412 auto itTransition = itFrom->second.find(lastIterationCommand_);
413 if(itTransition == itFrom->second.end())
415 __SS__ <<
"Cannot find transition function from '" << currentState
416 <<
"' with transition '" << lastIterationCommand_ <<
"!'"
418 __COUT_ERR__ << ss.str();
419 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
422 (this->*(itTransition->second))(event);
429 lastIterationState_ = theStateMachine_.getCurrentState();
430 lastIterationCommand_ = command;
432 theStateMachine_.execTransition(command, message);
435 if(subIterationWorkFlag_)
437 __COUTV__(subIterationWorkFlag_);
439 command +
"SubIterate";
441 else if(iterationWorkFlag_)
443 __COUTV__(iterationWorkFlag_);
444 result = command +
"Iterate";
447 catch(toolbox::fsm::exception::Exception& e)
449 __SS__ <<
"Run Control Message Handling Failed: " << e.what() <<
" "
450 << theStateMachine_.getErrorMessage() << __E__;
451 __COUT_ERR__ << ss.str();
452 theStateMachine_.setErrorMessage(ss.str());
454 result = command +
" " + RunControlStateMachine::FAILED_STATE_NAME +
": " +
455 theStateMachine_.getErrorMessage();
459 __SS__ <<
"Run Control Message Handling encountered an unknown error."
460 << theStateMachine_.getErrorMessage() << __E__;
461 __COUT_ERR__ << ss.str();
462 theStateMachine_.setErrorMessage(ss.str());
464 result = command +
" " + RunControlStateMachine::FAILED_STATE_NAME +
": " +
465 theStateMachine_.getErrorMessage();
468 RunControlStateMachine::theProgressBar_.step();
470 currentState = theStateMachine_.getCurrentStateName();
472 if(currentState == RunControlStateMachine::FAILED_STATE_NAME)
474 result = command +
" " + RunControlStateMachine::FAILED_STATE_NAME +
": " +
475 theStateMachine_.getErrorMessage();
476 __COUT_ERR__ <<
"Unexpected Failure state for "
477 << theStateMachine_.getStateMachineName() <<
" is " << currentState
479 __COUT_ERR__ <<
"Error message was as follows: "
480 << theStateMachine_.getErrorMessage() << std::endl;
483 RunControlStateMachine::theProgressBar_.step();
485 if(!iterationWorkFlag_ && !subIterationWorkFlag_)
486 theProgressBar_.complete();
489 __COUTV__(theProgressBar_.read());
490 __COUTV__(theProgressBar_.isComplete());
493 __COUT__ <<
"Ending state for " << theStateMachine_.getStateMachineName() <<
" is "
494 << currentState << std::endl;
495 __COUT__ <<
"result = " << result << std::endl;
496 lastIterationResult_ = result;
497 return SOAPUtilities::makeSOAPMessageReference(result);