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>
18 #define __MF_SUBJECT__ "FSM"
19 #define mfSubject_ std::string("FSM-") + theStateMachine_.getStateMachineName()
25 const std::string RunControlStateMachine::FAILED_STATE_NAME = FiniteStateMachine::FAILED_STATE_NAME;
26 const std::string RunControlStateMachine::INITIAL_STATE_NAME = FiniteStateMachine::INITIAL_STATE_NAME ;
27 const std::string RunControlStateMachine::HALTED_STATE_NAME =
"Halted";
28 const std::string RunControlStateMachine::PAUSED_STATE_NAME =
"Paused";
29 const std::string RunControlStateMachine::RUNNING_STATE_NAME =
"Running";
30 const std::string RunControlStateMachine::SHUTDOWN_STATE_NAME =
"Shutdown";
31 const std::string RunControlStateMachine::CONFIGURED_STATE_NAME =
"Configured";
33 const std::string RunControlStateMachine::SHUTDOWN_TRANSITION_NAME =
"Shutdown";
34 const std::string RunControlStateMachine::STARTUP_TRANSITION_NAME =
"Startup";
35 const std::string RunControlStateMachine::INIT_TRANSITION_NAME =
"Initialize";
36 const std::string RunControlStateMachine::ERROR_TRANSITION_NAME = FiniteStateMachine::ERROR_TRANSITION_NAME;
37 const std::string RunControlStateMachine::FAIL_TRANSITION_NAME =
"Fail";
38 const std::string RunControlStateMachine::CONFIGURE_TRANSITION_NAME = FiniteStateMachine::CONFIGURE_TRANSITION_NAME;
39 const std::string RunControlStateMachine::HALT_TRANSITION_NAME =
"Halt";
40 const std::string RunControlStateMachine::ABORT_TRANSITION_NAME =
"Abort";
41 const std::string RunControlStateMachine::PAUSE_TRANSITION_NAME =
"Pause";
42 const std::string RunControlStateMachine::RESUME_TRANSITION_NAME =
"Resume";
43 const std::string RunControlStateMachine::START_TRANSITION_NAME =
"Start";
44 const std::string RunControlStateMachine::STOP_TRANSITION_NAME =
"Stop";
49 RunControlStateMachine::RunControlStateMachine(
const std::string& name)
50 : theStateMachine_(name)
54 theStateMachine_.addState(
'I',
55 RunControlStateMachine::INITIAL_STATE_NAME,
57 &RunControlStateMachine::stateInitial);
58 theStateMachine_.addState(
'H',
59 RunControlStateMachine::HALTED_STATE_NAME,
61 &RunControlStateMachine::stateHalted);
62 theStateMachine_.addState(
'C',
63 RunControlStateMachine::CONFIGURED_STATE_NAME,
65 &RunControlStateMachine::stateConfigured);
66 theStateMachine_.addState(
'R',
67 RunControlStateMachine::RUNNING_STATE_NAME,
69 &RunControlStateMachine::stateRunning);
70 theStateMachine_.addState(
'P',
71 RunControlStateMachine::PAUSED_STATE_NAME,
73 &RunControlStateMachine::statePaused);
74 theStateMachine_.addState(
'X',
75 RunControlStateMachine::SHUTDOWN_STATE_NAME,
77 &RunControlStateMachine::stateShutdown);
86 theStateMachine_.setStateName(FiniteStateMachine::FAILED_STATE,
87 RunControlStateMachine::FAILED_STATE_NAME);
88 theStateMachine_.setFailedStateTransitionAction(
89 this, &RunControlStateMachine::enteringError);
90 theStateMachine_.setFailedStateTransitionChanged(
this,
91 &RunControlStateMachine::inError);
95 RunControlStateMachine::addStateTransition(
96 FiniteStateMachine::FAILED_STATE,
98 RunControlStateMachine::HALT_TRANSITION_NAME,
101 &RunControlStateMachine::transitionHalting);
102 RunControlStateMachine::addStateTransition(
103 FiniteStateMachine::FAILED_STATE,
105 RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
108 &RunControlStateMachine::transitionShuttingDown);
109 RunControlStateMachine::addStateTransition(
110 FiniteStateMachine::FAILED_STATE,
111 FiniteStateMachine::FAILED_STATE,
112 RunControlStateMachine::ERROR_TRANSITION_NAME,
115 &RunControlStateMachine::enteringError);
116 RunControlStateMachine::addStateTransition(
117 FiniteStateMachine::FAILED_STATE,
118 FiniteStateMachine::FAILED_STATE,
119 RunControlStateMachine::FAIL_TRANSITION_NAME,
122 &RunControlStateMachine::transitionShuttingDown);
124 RunControlStateMachine::addStateTransition(
127 RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
129 "ConfigurationAlias",
131 &RunControlStateMachine::transitionConfiguring);
132 RunControlStateMachine::addStateTransition(
135 RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
138 &RunControlStateMachine::transitionShuttingDown);
139 RunControlStateMachine::addStateTransition(
142 RunControlStateMachine::STARTUP_TRANSITION_NAME,
145 &RunControlStateMachine::transitionStartingUp);
148 RunControlStateMachine::addStateTransition(
151 RunControlStateMachine::INIT_TRANSITION_NAME,
154 &RunControlStateMachine::transitionInitializing);
155 RunControlStateMachine::addStateTransition(
158 RunControlStateMachine::HALT_TRANSITION_NAME,
161 &RunControlStateMachine::transitionHalting);
162 RunControlStateMachine::addStateTransition(
165 RunControlStateMachine::HALT_TRANSITION_NAME,
168 &RunControlStateMachine::transitionHalting);
169 RunControlStateMachine::addStateTransition(
172 RunControlStateMachine::ABORT_TRANSITION_NAME,
175 &RunControlStateMachine::transitionHalting);
176 RunControlStateMachine::addStateTransition(
179 RunControlStateMachine::ABORT_TRANSITION_NAME,
182 &RunControlStateMachine::transitionHalting);
184 RunControlStateMachine::addStateTransition(
187 RunControlStateMachine::PAUSE_TRANSITION_NAME,
190 &RunControlStateMachine::transitionPausing);
191 RunControlStateMachine::addStateTransition(
194 RunControlStateMachine::RESUME_TRANSITION_NAME,
197 &RunControlStateMachine::transitionResuming);
198 RunControlStateMachine::addStateTransition(
201 RunControlStateMachine::START_TRANSITION_NAME,
204 &RunControlStateMachine::transitionStarting);
205 RunControlStateMachine::addStateTransition(
208 RunControlStateMachine::STOP_TRANSITION_NAME,
211 &RunControlStateMachine::transitionStopping);
212 RunControlStateMachine::addStateTransition(
215 RunControlStateMachine::STOP_TRANSITION_NAME,
218 &RunControlStateMachine::transitionStopping);
224 &RunControlStateMachine::runControlMessageHandler,
225 RunControlStateMachine::INIT_TRANSITION_NAME,
228 &RunControlStateMachine::runControlMessageHandler,
229 RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
232 &RunControlStateMachine::runControlMessageHandler,
233 RunControlStateMachine::START_TRANSITION_NAME,
236 &RunControlStateMachine::runControlMessageHandler,
237 RunControlStateMachine::STOP_TRANSITION_NAME,
240 &RunControlStateMachine::runControlMessageHandler,
241 RunControlStateMachine::PAUSE_TRANSITION_NAME,
244 &RunControlStateMachine::runControlMessageHandler,
245 RunControlStateMachine::RESUME_TRANSITION_NAME,
248 &RunControlStateMachine::runControlMessageHandler,
249 RunControlStateMachine::HALT_TRANSITION_NAME,
252 &RunControlStateMachine::runControlMessageHandler,
253 RunControlStateMachine::ABORT_TRANSITION_NAME,
256 &RunControlStateMachine::runControlMessageHandler,
257 RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
260 &RunControlStateMachine::runControlMessageHandler,
261 RunControlStateMachine::STARTUP_TRANSITION_NAME,
264 &RunControlStateMachine::runControlMessageHandler,
265 RunControlStateMachine::FAIL_TRANSITION_NAME,
268 &RunControlStateMachine::runControlMessageHandler,
269 RunControlStateMachine::ERROR_TRANSITION_NAME,
273 &RunControlStateMachine::runControlMessageHandler,
277 &RunControlStateMachine::runControlMessageHandler,
278 "AsyncPauseException",
285 RunControlStateMachine::~RunControlStateMachine(
void) {}
288 void RunControlStateMachine::reset(
void)
290 __GEN_COUT__ <<
"Resetting RunControlStateMachine with name '"
291 << theStateMachine_.getStateMachineName() <<
"'..." << __E__;
292 theStateMachine_.setInitialState(
'I');
293 theStateMachine_.reset();
295 theStateMachine_.setErrorMessage(
"",
false );
297 asyncFailureReceived_ =
false;
298 asyncPauseExceptionReceived_ =
false;
299 asyncStopExceptionReceived_ =
false;
332 xoap::MessageReference message)
334 __GEN_COUTS__(2) <<
"Received... \t" << SOAPUtilities::translate(message)
337 std::string command = SOAPUtilities::translate(message).getCommand();
343 SOAPUtilities::translate(message).getParameters().getValue(
"iterationIndex"),
348 __GEN_COUT__ <<
"Defaulting iteration index to 0." << __E__;
355 SOAPUtilities::translate(message).getParameters().getValue(
356 "subIterationIndex"),
361 __GEN_COUTT__ <<
"Defaulting subIterationIndex_ index to 0." << __E__;
362 subIterationIndex_ = 0;
366 bool retransmittedCommand =
false;
369 retransmittedCommand =
370 (SOAPUtilities::translate(message).getParameters().getValue(
371 "retransmission") ==
"1");
379 if(retransmittedCommand)
382 __GEN_COUT__ <<
"retransmission identified..." << __E__;
385 if(lastIterationCommand_ == command && lastIterationIndex_ == iterationIndex_ &&
386 lastSubIterationIndex_ == subIterationIndex_)
389 <<
"Assuming a timeout occurred at Gateway waiting for a response. "
390 <<
"Attempting to avoid error, by giving last result for command '"
391 << command <<
"': " << lastIterationResult_ << __E__;
394 return SOAPUtilities::makeSOAPMessageReference(lastIterationResult_);
396 catch(
const std::exception&
399 __GEN_COUT__ <<
"There was an illegal result propagation: "
400 << lastIterationResult_
401 <<
". Here was the error: " << e.what() << __E__;
406 __GEN_COUT__ <<
"Looks like Gateway command '" << command
407 <<
"' was lost - attempting to handle retransmission." << __E__;
410 lastIterationIndex_ = iterationIndex_;
411 lastSubIterationIndex_ = subIterationIndex_;
413 std::string currentState;
414 if(iterationIndex_ == 0 && subIterationIndex_ == 0)
417 theProgressBar_.
reset(command, theStateMachine_.getStateMachineName());
418 currentState = theStateMachine_.getCurrentStateName();
419 __GEN_COUT__ <<
"Starting state for " << theStateMachine_.getStateMachineName()
420 <<
" is " << currentState <<
" and attempting to " << command
425 currentState = theStateMachine_.getStateName(lastIterationState_);
427 __GEN_COUTS__(2) <<
"Iteration index " << iterationIndex_ <<
"."
428 << subIterationIndex_ <<
" for "
429 << theStateMachine_.getStateMachineName() <<
" from "
430 << currentState <<
" attempting to " << command << std::endl;
433 RunControlStateMachine::theProgressBar_.step();
435 std::string result = command +
"Done";
436 lastIterationResult_ = result;
440 if(command ==
"Error" || command ==
"Fail")
442 __GEN_SS__ << command <<
" was received! Halting immediately." << std::endl;
443 __GEN_COUT_ERR__ <<
"\n" << ss.str();
447 if(currentState ==
"Configured")
448 theStateMachine_.execTransition(
449 RunControlStateMachine::HALT_TRANSITION_NAME, message);
450 else if(currentState ==
"Running" || currentState ==
"Paused")
451 theStateMachine_.execTransition(
452 RunControlStateMachine::ABORT_TRANSITION_NAME, message);
456 __GEN_COUT_ERR__ <<
"Halting failed in reaction to " << command
457 <<
"... ignoring." << __E__;
460 return SOAPUtilities::makeSOAPMessageReference(result);
462 else if(command ==
"AsyncError")
464 std::string errorMessage =
465 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
467 __GEN_SS__ << command <<
" was received! Error'ing immediately: " << errorMessage
469 __GEN_COUT_ERR__ <<
"\n" << ss.str();
470 theStateMachine_.setErrorMessage(ss.str());
472 if(!asyncFailureReceived_.exchange(
true))
478 std::thread([
this]() {
481 theStateMachine_.execTransition(
"fail");
485 __GEN_COUT_ERR__ <<
"AsyncError: execTransition(fail) threw" << __E__;
490 return SOAPUtilities::makeSOAPMessageReference(result);
492 else if(command ==
"AsyncPauseException")
494 std::string errorMessage =
495 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
497 __GEN_SS__ << command <<
" was received! Pause'ing immediately: " << errorMessage
499 __GEN_COUT_ERR__ <<
"\n" << ss.str();
500 theStateMachine_.setErrorMessage(ss.str());
502 if(!asyncPauseExceptionReceived_.exchange(
true))
506 std::thread([
this]() {
509 theStateMachine_.execTransition(
"Pause");
513 __GEN_COUT_ERR__ <<
"AsyncPauseException: execTransition(Pause) threw"
519 return SOAPUtilities::makeSOAPMessageReference(result);
521 else if(command ==
"AsyncStopException")
523 std::string errorMessage =
524 SOAPUtilities::translate(message).getParameters().getValue(
"ErrorMessage");
526 __GEN_SS__ << command <<
" was received! Stop'ing immediately: " << errorMessage
528 __GEN_COUT_ERR__ <<
"\n" << ss.str();
529 theStateMachine_.setErrorMessage(ss.str());
531 if(!asyncStopExceptionReceived_.exchange(
true))
535 std::thread([
this]() {
538 theStateMachine_.execTransition(
"Stop");
542 __GEN_COUT_ERR__ <<
"AsyncStopException: execTransition(Stop) threw"
548 return SOAPUtilities::makeSOAPMessageReference(result);
553 if(command == RunControlStateMachine::INIT_TRANSITION_NAME &&
554 currentState == RunControlStateMachine::HALTED_STATE_NAME)
556 __GEN_COUT__ <<
"Already Initialized.. ignoring Initialize command." << std::endl;
558 theStateMachine_.setErrorMessage(
"",
false );
559 return SOAPUtilities::makeSOAPMessageReference(result);
562 if(command == RunControlStateMachine::INIT_TRANSITION_NAME &&
563 currentState == RunControlStateMachine::FAILED_STATE_NAME)
565 __GEN_COUT__ <<
"Converting Initialize command to Halt, since currently in "
566 << currentState <<
" state." << std::endl;
567 command = RunControlStateMachine::HALT_TRANSITION_NAME;
568 message = SOAPUtilities::makeSOAPMessageReference(command);
571 if((command == RunControlStateMachine::HALT_TRANSITION_NAME ||
572 command == RunControlStateMachine::SHUTDOWN_TRANSITION_NAME) &&
573 currentState == RunControlStateMachine::FAILED_STATE_NAME)
575 __GEN_COUT__ <<
"Clearing Errors after failure..." << std::endl;
576 theStateMachine_.setErrorMessage(
"",
false );
577 asyncFailureReceived_ =
false;
578 asyncPauseExceptionReceived_ =
false;
579 asyncStopExceptionReceived_ =
false;
582 if(command == RunControlStateMachine::RESUME_TRANSITION_NAME)
583 asyncPauseExceptionReceived_ =
false;
584 if(command == RunControlStateMachine::START_TRANSITION_NAME)
585 asyncStopExceptionReceived_ =
false;
587 __GEN_COUTVS__(2, command);
588 __GEN_COUTVS__(2, currentState);
589 __GEN_COUTVS__(2, asyncFailureReceived_);
590 __GEN_COUTVS__(2, asyncPauseExceptionReceived_);
591 __GEN_COUTVS__(2, asyncStopExceptionReceived_);
592 __GEN_COUTVS__(2, getErrorMessage());
593 __GEN_COUTVS__(2, retransmittedCommand);
601 if(!((asyncPauseExceptionReceived_ &&
602 command == RunControlStateMachine::PAUSE_TRANSITION_NAME) ||
603 (asyncStopExceptionReceived_ &&
604 command == RunControlStateMachine::STOP_TRANSITION_NAME)))
605 theStateMachine_.setErrorMessage(
"",
608 if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
609 currentState == RunControlStateMachine::INITIAL_STATE_NAME)
611 command = RunControlStateMachine::INIT_TRANSITION_NAME;
612 __GEN_COUT__ <<
"Converting Halt command to " << command
613 <<
", since currently in " << currentState <<
" state."
615 message = SOAPUtilities::makeSOAPMessageReference(command);
617 if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
618 (currentState == RunControlStateMachine::PAUSED_STATE_NAME ||
619 currentState == RunControlStateMachine::RUNNING_STATE_NAME))
621 command = RunControlStateMachine::ABORT_TRANSITION_NAME;
622 __GEN_COUT__ <<
"Converting Halt command to " << command
623 <<
", since currently in " << currentState <<
" state."
625 message = SOAPUtilities::makeSOAPMessageReference(command);
627 if(command == RunControlStateMachine::CONFIGURE_TRANSITION_NAME &&
628 currentState == RunControlStateMachine::INITIAL_STATE_NAME)
631 <<
"Pre-empting Configure command with Initialize, since currently in "
632 << currentState <<
" state." << std::endl;
633 std::string precommand = RunControlStateMachine::INIT_TRANSITION_NAME;
634 xoap::MessageReference premessage =
635 SOAPUtilities::makeSOAPMessageReference(precommand);
636 theStateMachine_.execTransition(precommand, premessage);
637 __GEN_COUT__ <<
"Now proceeding with Configure command" << __E__;
640 iterationWorkFlag_ =
false;
641 subIterationWorkFlag_ =
false;
642 if(iterationIndex_ || subIterationIndex_)
644 __GEN_COUTS__(2) << command <<
" iteration " << iterationIndex_ <<
"."
645 << subIterationIndex_ << __E__;
646 toolbox::Event::Reference event(
new toolbox::Event(command,
this));
652 <<
"Iterating on the transition function from " << currentState
653 <<
" through " << lastIterationCommand_ << __E__;
655 auto itFrom = stateTransitionFunctionTable_.find(lastIterationState_);
656 if(itFrom == stateTransitionFunctionTable_.end())
658 __GEN_SS__ <<
"Cannot find transition function from '" << currentState
659 <<
"' with transition '" << lastIterationCommand_ <<
"!'"
661 __GEN_COUT_ERR__ << ss.str();
662 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
665 auto itTransition = itFrom->second.find(lastIterationCommand_);
666 if(itTransition == itFrom->second.end())
668 __GEN_SS__ <<
"Cannot find transition function from '" << currentState
669 <<
"' with transition '" << lastIterationCommand_ <<
"!'"
671 __GEN_COUT_ERR__ << ss.str();
672 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
675 (this->*(itTransition->second))(event);
682 lastIterationState_ = theStateMachine_.getCurrentState();
683 lastIterationCommand_ = command;
684 if(command == RunControlStateMachine::CONFIGURE_TRANSITION_NAME)
686 lastAttemptedConfigureGroup_ =
687 SOAPUtilities::translate(message).getParameters().getValue(
688 "ConfigurationAlias");
693 lastAttemptedConfigureGroup_ +=
695 SOAPUtilities::translate(message).getParameters().getValue(
696 "ConfigurationTableGroupName") +
698 SOAPUtilities::translate(message).getParameters().getValue(
699 "ConfigurationTableGroupKey") +
707 theStateMachine_.execTransition(command, message);
710 if(subIterationWorkFlag_)
712 __GEN_COUTV__(subIterationWorkFlag_);
714 command +
"SubIterate";
716 else if(iterationWorkFlag_)
718 __GEN_COUTVS__(2, iterationWorkFlag_);
719 result = command +
"Iterate";
722 catch(
const std::runtime_error& e)
724 __GEN_SS__ <<
"Run Control Message Handling Failed with command '" << command
725 <<
"': " << e.what() <<
" " << theStateMachine_.getErrorMessage()
727 __GEN_COUT_ERR__ << ss.str();
728 theStateMachine_.setErrorMessage(ss.str());
730 result = command + RunControlStateMachine::FAILED_STATE_NAME;
732 catch(toolbox::fsm::exception::Exception& e)
734 __GEN_SS__ <<
"Run Control Message Handling Failed with command '" << command
735 <<
"': " << e.what() <<
" " << theStateMachine_.getErrorMessage()
737 __GEN_COUT_ERR__ << ss.str();
738 theStateMachine_.setErrorMessage(ss.str());
740 result = command + RunControlStateMachine::FAILED_STATE_NAME;
744 __GEN_SS__ <<
"Run Control Message Handling Failed with command '" << command
745 <<
"' and encountered an unknown error."
746 << theStateMachine_.getErrorMessage() << __E__;
751 catch(
const std::exception& e)
753 ss <<
"Exception message: " << e.what();
758 __GEN_COUT_ERR__ << ss.str();
759 theStateMachine_.setErrorMessage(ss.str());
761 result = command + RunControlStateMachine::FAILED_STATE_NAME;
764 RunControlStateMachine::theProgressBar_.step();
766 currentState = theStateMachine_.getCurrentStateName();
768 if(currentState == RunControlStateMachine::FAILED_STATE_NAME)
770 result = command + RunControlStateMachine::FAILED_STATE_NAME;
771 __GEN_COUT_ERR__ <<
"Unexpected Failure state for "
772 << theStateMachine_.getStateMachineName() <<
" is "
773 << currentState << std::endl;
774 __GEN_COUT_ERR__ <<
"Error message was as follows: "
775 << theStateMachine_.getErrorMessage() << std::endl;
778 RunControlStateMachine::theProgressBar_.step();
780 if(!iterationWorkFlag_ && !subIterationWorkFlag_)
784 __GEN_COUTVS__(2, theProgressBar_.
read());
785 __GEN_COUTVS__(2, theProgressBar_.
isComplete());
788 __GEN_COUTS__(2) <<
"Ending state for " << theStateMachine_.getStateMachineName()
789 <<
" is " << currentState << std::endl;
790 __GEN_COUTS__(2) <<
"result = " << result << std::endl;
791 lastIterationResult_ = result;
792 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.
defines used also by OtsConfigurationWizardSupervisor
void INIT_MF(const char *name)
static bool getNumber(const std::string &s, T &retValue)