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__ "FSM"
18 #define mfSubject_ std::string("FSM-") + theStateMachine_.getStateMachineName()
24 const std::string RunControlStateMachine::FAILED_STATE_NAME = FiniteStateMachine::FAILED_STATE_NAME;
25 const std::string RunControlStateMachine::INITIAL_STATE_NAME =
"Initial";
26 const std::string RunControlStateMachine::HALTED_STATE_NAME =
"Halted";
27 const std::string RunControlStateMachine::PAUSED_STATE_NAME =
"Paused";
28 const std::string RunControlStateMachine::RUNNING_STATE_NAME =
"Running";
29 const std::string RunControlStateMachine::SHUTDOWN_STATE_NAME =
"Shutdown";
30 const std::string RunControlStateMachine::CONFIGURED_STATE_NAME =
"Configured";
32 const std::string RunControlStateMachine::SHUTDOWN_TRANSITION_NAME =
"Shutdown";
33 const std::string RunControlStateMachine::STARTUP_TRANSITION_NAME =
"Startup";
34 const std::string RunControlStateMachine::INIT_TRANSITION_NAME =
"Initialize";
35 const std::string RunControlStateMachine::ERROR_TRANSITION_NAME = FiniteStateMachine::ERROR_TRANSITION_NAME;
36 const std::string RunControlStateMachine::FAIL_TRANSITION_NAME =
"Fail";
37 const std::string RunControlStateMachine::CONFIGURE_TRANSITION_NAME =
"Configure";
38 const std::string RunControlStateMachine::HALT_TRANSITION_NAME =
"Halt";
39 const std::string RunControlStateMachine::ABORT_TRANSITION_NAME =
"Abort";
40 const std::string RunControlStateMachine::PAUSE_TRANSITION_NAME =
"Pause";
41 const std::string RunControlStateMachine::RESUME_TRANSITION_NAME =
"Resume";
42 const std::string RunControlStateMachine::START_TRANSITION_NAME =
"Start";
43 const std::string RunControlStateMachine::STOP_TRANSITION_NAME =
"Stop";
48 RunControlStateMachine::RunControlStateMachine(
const std::string& name)
49 : theStateMachine_(name)
50 , asyncFailureReceived_(false)
51 , asyncPauseExceptionReceived_(false)
52 , asyncStopExceptionReceived_(false)
56 theStateMachine_.addState(
'I',
57 RunControlStateMachine::INITIAL_STATE_NAME,
59 &RunControlStateMachine::stateInitial);
60 theStateMachine_.addState(
'H',
61 RunControlStateMachine::HALTED_STATE_NAME,
63 &RunControlStateMachine::stateHalted);
64 theStateMachine_.addState(
'C',
65 RunControlStateMachine::CONFIGURED_STATE_NAME,
67 &RunControlStateMachine::stateConfigured);
68 theStateMachine_.addState(
'R',
69 RunControlStateMachine::RUNNING_STATE_NAME,
71 &RunControlStateMachine::stateRunning);
72 theStateMachine_.addState(
'P',
73 RunControlStateMachine::PAUSED_STATE_NAME,
75 &RunControlStateMachine::statePaused);
76 theStateMachine_.addState(
'X',
77 RunControlStateMachine::SHUTDOWN_STATE_NAME,
79 &RunControlStateMachine::stateShutdown);
88 theStateMachine_.setStateName(FiniteStateMachine::FAILED_STATE,
89 RunControlStateMachine::FAILED_STATE_NAME);
90 theStateMachine_.setFailedStateTransitionAction(
91 this, &RunControlStateMachine::enteringError);
92 theStateMachine_.setFailedStateTransitionChanged(
this,
93 &RunControlStateMachine::inError);
97 RunControlStateMachine::addStateTransition(
98 FiniteStateMachine::FAILED_STATE,
100 RunControlStateMachine::HALT_TRANSITION_NAME,
103 &RunControlStateMachine::transitionHalting);
104 RunControlStateMachine::addStateTransition(
105 FiniteStateMachine::FAILED_STATE,
107 RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
110 &RunControlStateMachine::transitionShuttingDown);
111 RunControlStateMachine::addStateTransition(
112 FiniteStateMachine::FAILED_STATE,
113 FiniteStateMachine::FAILED_STATE,
114 RunControlStateMachine::ERROR_TRANSITION_NAME,
117 &RunControlStateMachine::enteringError);
118 RunControlStateMachine::addStateTransition(
119 FiniteStateMachine::FAILED_STATE,
120 FiniteStateMachine::FAILED_STATE,
121 RunControlStateMachine::FAIL_TRANSITION_NAME,
124 &RunControlStateMachine::transitionShuttingDown);
126 RunControlStateMachine::addStateTransition(
129 RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
131 "ConfigurationAlias",
133 &RunControlStateMachine::transitionConfiguring);
134 RunControlStateMachine::addStateTransition(
137 RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
140 &RunControlStateMachine::transitionShuttingDown);
141 RunControlStateMachine::addStateTransition(
144 RunControlStateMachine::STARTUP_TRANSITION_NAME,
147 &RunControlStateMachine::transitionStartingUp);
150 RunControlStateMachine::addStateTransition(
153 RunControlStateMachine::INIT_TRANSITION_NAME,
156 &RunControlStateMachine::transitionInitializing);
157 RunControlStateMachine::addStateTransition(
160 RunControlStateMachine::HALT_TRANSITION_NAME,
163 &RunControlStateMachine::transitionHalting);
164 RunControlStateMachine::addStateTransition(
167 RunControlStateMachine::HALT_TRANSITION_NAME,
170 &RunControlStateMachine::transitionHalting);
171 RunControlStateMachine::addStateTransition(
174 RunControlStateMachine::ABORT_TRANSITION_NAME,
177 &RunControlStateMachine::transitionHalting);
178 RunControlStateMachine::addStateTransition(
181 RunControlStateMachine::ABORT_TRANSITION_NAME,
184 &RunControlStateMachine::transitionHalting);
186 RunControlStateMachine::addStateTransition(
189 RunControlStateMachine::PAUSE_TRANSITION_NAME,
192 &RunControlStateMachine::transitionPausing);
193 RunControlStateMachine::addStateTransition(
196 RunControlStateMachine::RESUME_TRANSITION_NAME,
199 &RunControlStateMachine::transitionResuming);
200 RunControlStateMachine::addStateTransition(
203 RunControlStateMachine::START_TRANSITION_NAME,
206 &RunControlStateMachine::transitionStarting);
207 RunControlStateMachine::addStateTransition(
210 RunControlStateMachine::STOP_TRANSITION_NAME,
213 &RunControlStateMachine::transitionStopping);
214 RunControlStateMachine::addStateTransition(
217 RunControlStateMachine::STOP_TRANSITION_NAME,
220 &RunControlStateMachine::transitionStopping);
226 &RunControlStateMachine::runControlMessageHandler,
227 RunControlStateMachine::INIT_TRANSITION_NAME,
230 &RunControlStateMachine::runControlMessageHandler,
231 RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
234 &RunControlStateMachine::runControlMessageHandler,
235 RunControlStateMachine::START_TRANSITION_NAME,
238 &RunControlStateMachine::runControlMessageHandler,
239 RunControlStateMachine::STOP_TRANSITION_NAME,
242 &RunControlStateMachine::runControlMessageHandler,
243 RunControlStateMachine::PAUSE_TRANSITION_NAME,
246 &RunControlStateMachine::runControlMessageHandler,
247 RunControlStateMachine::RESUME_TRANSITION_NAME,
250 &RunControlStateMachine::runControlMessageHandler,
251 RunControlStateMachine::HALT_TRANSITION_NAME,
254 &RunControlStateMachine::runControlMessageHandler,
255 RunControlStateMachine::ABORT_TRANSITION_NAME,
258 &RunControlStateMachine::runControlMessageHandler,
259 RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
262 &RunControlStateMachine::runControlMessageHandler,
263 RunControlStateMachine::STARTUP_TRANSITION_NAME,
266 &RunControlStateMachine::runControlMessageHandler,
267 RunControlStateMachine::FAIL_TRANSITION_NAME,
270 &RunControlStateMachine::runControlMessageHandler,
271 RunControlStateMachine::ERROR_TRANSITION_NAME,
275 &RunControlStateMachine::runControlMessageHandler,
279 &RunControlStateMachine::runControlMessageHandler,
280 "AsyncPauseException",
287 RunControlStateMachine::~RunControlStateMachine(
void) {}
290 void RunControlStateMachine::reset(
void)
292 __GEN_COUT__ <<
"Resetting RunControlStateMachine with name '"
293 << theStateMachine_.getStateMachineName() <<
"'..." << __E__;
294 theStateMachine_.setInitialState(
'I');
295 theStateMachine_.reset();
297 theStateMachine_.setErrorMessage(
"",
false );
299 asyncFailureReceived_ =
false;
300 asyncPauseExceptionReceived_ =
false;
301 asyncStopExceptionReceived_ =
false;
334 xoap::MessageReference message)
336 __GEN_COUTS__(2) <<
"Received... \t" << SOAPUtilities::translate(message)
339 std::string command = SOAPUtilities::translate(message).getCommand();
345 SOAPUtilities::translate(message).getParameters().getValue(
"iterationIndex"),
350 __GEN_COUT__ <<
"Defaulting iteration index to 0." << __E__;
357 SOAPUtilities::translate(message).getParameters().getValue(
358 "subIterationIndex"),
363 __GEN_COUTT__ <<
"Defaulting subIterationIndex_ index to 0." << __E__;
364 subIterationIndex_ = 0;
368 bool retransmittedCommand =
false;
371 retransmittedCommand =
372 (SOAPUtilities::translate(message).getParameters().getValue(
373 "retransmission") ==
"1");
381 if(retransmittedCommand)
384 __GEN_COUT__ <<
"retransmission identified..." << __E__;
387 if(lastIterationCommand_ == command && lastIterationIndex_ == iterationIndex_ &&
388 lastSubIterationIndex_ == subIterationIndex_)
391 <<
"Assuming a timeout occurred at Gateway waiting for a response. "
392 <<
"Attempting to avoid error, by giving last result for command '"
393 << command <<
"': " << lastIterationResult_ << __E__;
396 return SOAPUtilities::makeSOAPMessageReference(lastIterationResult_);
398 catch(
const std::exception&
401 __GEN_COUT__ <<
"There was an illegal result propagation: "
402 << lastIterationResult_
403 <<
". Here was the error: " << e.what() << __E__;
408 __GEN_COUT__ <<
"Looks like Gateway command '" << command
409 <<
"' was lost - attempting to handle retransmission." << __E__;
412 lastIterationIndex_ = iterationIndex_;
413 lastSubIterationIndex_ = subIterationIndex_;
415 std::string currentState;
416 if(iterationIndex_ == 0 && subIterationIndex_ == 0)
419 theProgressBar_.
reset(command, theStateMachine_.getStateMachineName());
420 currentState = theStateMachine_.getCurrentStateName();
421 __GEN_COUT__ <<
"Starting state for " << theStateMachine_.getStateMachineName()
422 <<
" is " << currentState <<
" and attempting to " << command
427 currentState = theStateMachine_.getStateName(lastIterationState_);
429 __GEN_COUTS__(2) <<
"Iteration index " << iterationIndex_ <<
"."
430 << subIterationIndex_ <<
" for "
431 << theStateMachine_.getStateMachineName() <<
" from "
432 << currentState <<
" attempting to " << command << std::endl;
435 RunControlStateMachine::theProgressBar_.step();
437 std::string result = command +
"Done";
438 lastIterationResult_ = result;
442 if(command ==
"Error" || command ==
"Fail")
444 __GEN_SS__ << command <<
" was received! Halting immediately." << std::endl;
445 __GEN_COUT_ERR__ <<
"\n" << ss.str();
449 if(currentState ==
"Configured")
450 theStateMachine_.execTransition(
451 RunControlStateMachine::HALT_TRANSITION_NAME, message);
452 else if(currentState ==
"Running" || currentState ==
"Paused")
453 theStateMachine_.execTransition(
454 RunControlStateMachine::ABORT_TRANSITION_NAME, message);
458 __GEN_COUT_ERR__ <<
"Halting failed in reaction to " << command
459 <<
"... ignoring." << __E__;
461 return SOAPUtilities::makeSOAPMessageReference(result);
463 else if(command ==
"AsyncError")
465 std::string errorMessage =
466 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
468 __GEN_SS__ << command <<
" was received! Error'ing immediately: " << errorMessage
470 __GEN_COUT_ERR__ <<
"\n" << ss.str();
471 theStateMachine_.setErrorMessage(ss.str());
473 asyncFailureReceived_ =
true;
475 theStateMachine_.execTransition(
"fail");
478 return SOAPUtilities::makeSOAPMessageReference(result);
480 else if(command ==
"AsyncPauseException")
482 std::string errorMessage =
483 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
485 __GEN_SS__ << command <<
" was received! Pause'ing immediately: " << errorMessage
487 __GEN_COUT_ERR__ <<
"\n" << ss.str();
488 theStateMachine_.setErrorMessage(ss.str());
490 if(!asyncPauseExceptionReceived_)
492 asyncPauseExceptionReceived_ =
true;
495 theStateMachine_.execTransition(
"Pause");
498 return SOAPUtilities::makeSOAPMessageReference(result);
500 else if(command ==
"AsyncStopException")
502 std::string errorMessage =
503 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
505 __GEN_SS__ << command <<
" was received! Stop'ing immediately: " << errorMessage
507 __GEN_COUT_ERR__ <<
"\n" << ss.str();
508 theStateMachine_.setErrorMessage(ss.str());
510 if(!asyncStopExceptionReceived_)
512 asyncStopExceptionReceived_ =
true;
515 theStateMachine_.execTransition(
"Stop");
518 return SOAPUtilities::makeSOAPMessageReference(result);
523 if(command == RunControlStateMachine::INIT_TRANSITION_NAME &&
524 currentState == RunControlStateMachine::HALTED_STATE_NAME)
526 __GEN_COUT__ <<
"Already Initialized.. ignoring Initialize command." << std::endl;
528 theStateMachine_.setErrorMessage(
"",
false );
529 return SOAPUtilities::makeSOAPMessageReference(result);
532 if(command == RunControlStateMachine::INIT_TRANSITION_NAME &&
533 currentState == RunControlStateMachine::FAILED_STATE_NAME)
535 __GEN_COUT__ <<
"Converting Initialize command to Halt, since currently in "
536 << currentState <<
" state." << std::endl;
537 command = RunControlStateMachine::HALT_TRANSITION_NAME;
538 message = SOAPUtilities::makeSOAPMessageReference(command);
541 if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
542 currentState == RunControlStateMachine::FAILED_STATE_NAME)
544 __GEN_COUT__ <<
"Clearing Errors after failure..." << std::endl;
545 theStateMachine_.setErrorMessage(
"",
false );
546 asyncFailureReceived_ =
false;
549 __GEN_COUTVS__(2, command);
550 __GEN_COUTVS__(2, currentState);
551 __GEN_COUTVS__(2, asyncFailureReceived_);
552 __GEN_COUTVS__(2, asyncPauseExceptionReceived_);
553 __GEN_COUTVS__(2, asyncStopExceptionReceived_);
554 __GEN_COUTVS__(2, getErrorMessage());
555 __GEN_COUTVS__(2, retransmittedCommand);
563 if(!((asyncPauseExceptionReceived_ &&
564 command == RunControlStateMachine::PAUSE_TRANSITION_NAME) ||
565 (asyncStopExceptionReceived_ &&
566 command == RunControlStateMachine::STOP_TRANSITION_NAME)))
567 theStateMachine_.setErrorMessage(
"",
570 if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
571 currentState == RunControlStateMachine::INITIAL_STATE_NAME)
573 command = RunControlStateMachine::INIT_TRANSITION_NAME;
574 __GEN_COUT__ <<
"Converting Halt command to " << command
575 <<
", since currently in " << currentState <<
" state."
577 message = SOAPUtilities::makeSOAPMessageReference(command);
579 if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
580 (currentState == RunControlStateMachine::PAUSED_STATE_NAME ||
581 currentState == RunControlStateMachine::RUNNING_STATE_NAME))
583 command = RunControlStateMachine::ABORT_TRANSITION_NAME;
584 __GEN_COUT__ <<
"Converting Halt command to " << command
585 <<
", since currently in " << currentState <<
" state."
587 message = SOAPUtilities::makeSOAPMessageReference(command);
589 if(command == RunControlStateMachine::CONFIGURE_TRANSITION_NAME &&
590 currentState == RunControlStateMachine::INITIAL_STATE_NAME)
593 <<
"Pre-empting Configure command with Initialize, since currently in "
594 << currentState <<
" state." << std::endl;
595 std::string precommand = RunControlStateMachine::INIT_TRANSITION_NAME;
596 xoap::MessageReference premessage =
597 SOAPUtilities::makeSOAPMessageReference(precommand);
598 theStateMachine_.execTransition(precommand, premessage);
599 __GEN_COUT__ <<
"Now proceeding with Configure command" << __E__;
602 iterationWorkFlag_ =
false;
603 subIterationWorkFlag_ =
false;
604 if(iterationIndex_ || subIterationIndex_)
606 __GEN_COUTS__(2) << command <<
" iteration " << iterationIndex_ <<
"."
607 << subIterationIndex_ << __E__;
608 toolbox::Event::Reference event(
new toolbox::Event(command,
this));
614 <<
"Iterating on the transition function from " << currentState
615 <<
" through " << lastIterationCommand_ << __E__;
617 auto itFrom = stateTransitionFunctionTable_.find(lastIterationState_);
618 if(itFrom == stateTransitionFunctionTable_.end())
620 __GEN_SS__ <<
"Cannot find transition function from '" << currentState
621 <<
"' with transition '" << lastIterationCommand_ <<
"!'"
623 __GEN_COUT_ERR__ << ss.str();
624 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
627 auto itTransition = itFrom->second.find(lastIterationCommand_);
628 if(itTransition == itFrom->second.end())
630 __GEN_SS__ <<
"Cannot find transition function from '" << currentState
631 <<
"' with transition '" << lastIterationCommand_ <<
"!'"
633 __GEN_COUT_ERR__ << ss.str();
634 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
637 (this->*(itTransition->second))(event);
644 lastIterationState_ = theStateMachine_.getCurrentState();
645 lastIterationCommand_ = command;
646 if(command == RunControlStateMachine::CONFIGURE_TRANSITION_NAME)
648 lastAttemptedConfigureGroup_ =
649 SOAPUtilities::translate(message).getParameters().getValue(
650 "ConfigurationAlias");
655 lastAttemptedConfigureGroup_ +=
657 SOAPUtilities::translate(message).getParameters().getValue(
658 "ConfigurationTableGroupName") +
660 SOAPUtilities::translate(message).getParameters().getValue(
661 "ConfigurationTableGroupKey") +
669 theStateMachine_.execTransition(command, message);
672 if(subIterationWorkFlag_)
674 __GEN_COUTV__(subIterationWorkFlag_);
676 command +
"SubIterate";
678 else if(iterationWorkFlag_)
680 __GEN_COUTVS__(2, iterationWorkFlag_);
681 result = command +
"Iterate";
684 catch(
const std::runtime_error& e)
686 __GEN_SS__ <<
"Run Control Message Handling Failed with command '" << command
687 <<
"': " << e.what() <<
" " << theStateMachine_.getErrorMessage()
689 __GEN_COUT_ERR__ << ss.str();
690 theStateMachine_.setErrorMessage(ss.str());
692 result = command + RunControlStateMachine::FAILED_STATE_NAME;
694 catch(toolbox::fsm::exception::Exception& e)
696 __GEN_SS__ <<
"Run Control Message Handling Failed with command '" << command
697 <<
"': " << e.what() <<
" " << theStateMachine_.getErrorMessage()
699 __GEN_COUT_ERR__ << ss.str();
700 theStateMachine_.setErrorMessage(ss.str());
702 result = command + RunControlStateMachine::FAILED_STATE_NAME;
706 __GEN_SS__ <<
"Run Control Message Handling Failed with command '" << command
707 <<
"' and encountered an unknown error."
708 << theStateMachine_.getErrorMessage() << __E__;
713 catch(
const std::exception& e)
715 ss <<
"Exception message: " << e.what();
720 __GEN_COUT_ERR__ << ss.str();
721 theStateMachine_.setErrorMessage(ss.str());
723 result = command + RunControlStateMachine::FAILED_STATE_NAME;
726 RunControlStateMachine::theProgressBar_.step();
728 currentState = theStateMachine_.getCurrentStateName();
730 if(currentState == RunControlStateMachine::FAILED_STATE_NAME)
732 result = command + RunControlStateMachine::FAILED_STATE_NAME;
733 __GEN_COUT_ERR__ <<
"Unexpected Failure state for "
734 << theStateMachine_.getStateMachineName() <<
" is "
735 << currentState << std::endl;
736 __GEN_COUT_ERR__ <<
"Error message was as follows: "
737 << theStateMachine_.getErrorMessage() << std::endl;
740 RunControlStateMachine::theProgressBar_.step();
742 if(!iterationWorkFlag_ && !subIterationWorkFlag_)
746 __GEN_COUTVS__(2, theProgressBar_.
read());
747 __GEN_COUTVS__(2, theProgressBar_.
isComplete());
750 __GEN_COUTS__(2) <<
"Ending state for " << theStateMachine_.getStateMachineName()
751 <<
" is " << currentState << std::endl;
752 __GEN_COUTS__(2) <<
"result = " << result << std::endl;
753 lastIterationResult_ = result;
754 return SOAPUtilities::makeSOAPMessageReference(result);
bool isComplete()
get functions
void reset(std::string file, std::string lineNumber, int id=0)
will call this reset:
int read()
if stepsToComplete==0, then define any progress as 50%, thread safe
void complete()
declare complete, thread safe
xoap::MessageReference runControlMessageHandler(xoap::MessageReference message)
Run Control Messages.
void INIT_MF(const char *name)
static bool getNumber(const std::string &s, T &retValue)