otsdaq  3.11.00
RunControlStateMachine.cc
1 #include "otsdaq/FiniteStateMachine/RunControlStateMachine.h"
2 #include "otsdaq/MessageFacility/MessageFacility.h"
3 
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/Macros/StringMacros.h"
6 
7 #include "otsdaq/SOAPUtilities/SOAPCommand.h"
8 #include "otsdaq/SOAPUtilities/SOAPUtilities.h"
9 
10 #include <toolbox/fsm/FailedEvent.h>
11 #include <xdaq/NamespaceURI.h>
12 #include <xoap/Method.h>
13 
14 #include <iostream>
15 #include <thread>
16 
17 #undef __MF_SUBJECT__
18 #define __MF_SUBJECT__ "FSM"
19 #define mfSubject_ std::string("FSM-") + theStateMachine_.getStateMachineName()
20 
21 using namespace ots;
22 
23 // clang-format off
24 
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";
32 
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";
45 
46 // clang-format on
47 
48 //==============================================================================
49 RunControlStateMachine::RunControlStateMachine(const std::string& name)
50  : theStateMachine_(name)
51 {
52  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
53 
54  theStateMachine_.addState('I',
55  RunControlStateMachine::INITIAL_STATE_NAME,
56  this,
57  &RunControlStateMachine::stateInitial);
58  theStateMachine_.addState('H',
59  RunControlStateMachine::HALTED_STATE_NAME,
60  this,
61  &RunControlStateMachine::stateHalted);
62  theStateMachine_.addState('C',
63  RunControlStateMachine::CONFIGURED_STATE_NAME,
64  this,
65  &RunControlStateMachine::stateConfigured);
66  theStateMachine_.addState('R',
67  RunControlStateMachine::RUNNING_STATE_NAME,
68  this,
69  &RunControlStateMachine::stateRunning);
70  theStateMachine_.addState('P',
71  RunControlStateMachine::PAUSED_STATE_NAME,
72  this,
73  &RunControlStateMachine::statePaused);
74  theStateMachine_.addState('X',
75  RunControlStateMachine::SHUTDOWN_STATE_NAME,
76  this,
77  &RunControlStateMachine::stateShutdown);
78  // theStateMachine_.addState('v', "Recovering", this,
79  // &RunControlStateMachine::stateRecovering); theStateMachine_.addState('T',
80  // "TTSTestMode", this, &RunControlStateMachine::stateTTSTestMode);
81 
82  // RAR added back in on 11/20/2016.. why was it removed..
83  // exceptions like..
84  // XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());)
85  // take state machine to "failed" otherwise
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);
92 
93  //clang-format off
94  // this line was added to get out of Failed state
95  RunControlStateMachine::addStateTransition(
96  FiniteStateMachine::FAILED_STATE,
97  'H',
98  RunControlStateMachine::HALT_TRANSITION_NAME,
99  "Halting",
100  this,
101  &RunControlStateMachine::transitionHalting);
102  RunControlStateMachine::addStateTransition(
103  FiniteStateMachine::FAILED_STATE,
104  'X',
105  RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
106  "Shutting Down",
107  this,
108  &RunControlStateMachine::transitionShuttingDown);
109  RunControlStateMachine::addStateTransition(
110  FiniteStateMachine::FAILED_STATE,
111  FiniteStateMachine::FAILED_STATE,
112  RunControlStateMachine::ERROR_TRANSITION_NAME,
113  "Erroring",
114  this,
115  &RunControlStateMachine::enteringError);
116  RunControlStateMachine::addStateTransition(
117  FiniteStateMachine::FAILED_STATE,
118  FiniteStateMachine::FAILED_STATE,
119  RunControlStateMachine::FAIL_TRANSITION_NAME,
120  "Failing",
121  this,
122  &RunControlStateMachine::transitionShuttingDown);
123 
124  RunControlStateMachine::addStateTransition(
125  'H',
126  'C',
127  RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
128  "Configuring",
129  "ConfigurationAlias",
130  this,
131  &RunControlStateMachine::transitionConfiguring);
132  RunControlStateMachine::addStateTransition(
133  'H',
134  'X',
135  RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
136  "Shutting Down",
137  this,
138  &RunControlStateMachine::transitionShuttingDown);
139  RunControlStateMachine::addStateTransition(
140  'X',
141  'I',
142  RunControlStateMachine::STARTUP_TRANSITION_NAME,
143  "Starting Up",
144  this,
145  &RunControlStateMachine::transitionStartingUp);
146 
147  // Every state can transition to halted
148  RunControlStateMachine::addStateTransition(
149  'I',
150  'H',
151  RunControlStateMachine::INIT_TRANSITION_NAME,
152  "Initializing",
153  this,
154  &RunControlStateMachine::transitionInitializing);
155  RunControlStateMachine::addStateTransition(
156  'H',
157  'H',
158  RunControlStateMachine::HALT_TRANSITION_NAME,
159  "Halting",
160  this,
161  &RunControlStateMachine::transitionHalting);
162  RunControlStateMachine::addStateTransition(
163  'C',
164  'H',
165  RunControlStateMachine::HALT_TRANSITION_NAME,
166  "Halting",
167  this,
168  &RunControlStateMachine::transitionHalting);
169  RunControlStateMachine::addStateTransition(
170  'R',
171  'H',
172  RunControlStateMachine::ABORT_TRANSITION_NAME,
173  "Aborting",
174  this,
175  &RunControlStateMachine::transitionHalting);
176  RunControlStateMachine::addStateTransition(
177  'P',
178  'H',
179  RunControlStateMachine::ABORT_TRANSITION_NAME,
180  "Aborting",
181  this,
182  &RunControlStateMachine::transitionHalting);
183 
184  RunControlStateMachine::addStateTransition(
185  'R',
186  'P',
187  RunControlStateMachine::PAUSE_TRANSITION_NAME,
188  "Pausing",
189  this,
190  &RunControlStateMachine::transitionPausing);
191  RunControlStateMachine::addStateTransition(
192  'P',
193  'R',
194  RunControlStateMachine::RESUME_TRANSITION_NAME,
195  "Resuming",
196  this,
197  &RunControlStateMachine::transitionResuming);
198  RunControlStateMachine::addStateTransition(
199  'C',
200  'R',
201  RunControlStateMachine::START_TRANSITION_NAME,
202  "Starting",
203  this,
204  &RunControlStateMachine::transitionStarting);
205  RunControlStateMachine::addStateTransition(
206  'R',
207  'C',
208  RunControlStateMachine::STOP_TRANSITION_NAME,
209  "Stopping",
210  this,
211  &RunControlStateMachine::transitionStopping);
212  RunControlStateMachine::addStateTransition(
213  'P',
214  'C',
215  RunControlStateMachine::STOP_TRANSITION_NAME,
216  "Stopping",
217  this,
218  &RunControlStateMachine::transitionStopping);
219  //clang-format on
220 
221  // NOTE!! There must be a defined message handler for each transition name created
222  // above
223  xoap::bind(this,
224  &RunControlStateMachine::runControlMessageHandler,
225  RunControlStateMachine::INIT_TRANSITION_NAME,
226  XDAQ_NS_URI);
227  xoap::bind(this,
228  &RunControlStateMachine::runControlMessageHandler,
229  RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
230  XDAQ_NS_URI);
231  xoap::bind(this,
232  &RunControlStateMachine::runControlMessageHandler,
233  RunControlStateMachine::START_TRANSITION_NAME,
234  XDAQ_NS_URI);
235  xoap::bind(this,
236  &RunControlStateMachine::runControlMessageHandler,
237  RunControlStateMachine::STOP_TRANSITION_NAME,
238  XDAQ_NS_URI);
239  xoap::bind(this,
240  &RunControlStateMachine::runControlMessageHandler,
241  RunControlStateMachine::PAUSE_TRANSITION_NAME,
242  XDAQ_NS_URI);
243  xoap::bind(this,
244  &RunControlStateMachine::runControlMessageHandler,
245  RunControlStateMachine::RESUME_TRANSITION_NAME,
246  XDAQ_NS_URI);
247  xoap::bind(this,
248  &RunControlStateMachine::runControlMessageHandler,
249  RunControlStateMachine::HALT_TRANSITION_NAME,
250  XDAQ_NS_URI);
251  xoap::bind(this,
252  &RunControlStateMachine::runControlMessageHandler,
253  RunControlStateMachine::ABORT_TRANSITION_NAME,
254  XDAQ_NS_URI);
255  xoap::bind(this,
256  &RunControlStateMachine::runControlMessageHandler,
257  RunControlStateMachine::SHUTDOWN_TRANSITION_NAME,
258  XDAQ_NS_URI);
259  xoap::bind(this,
260  &RunControlStateMachine::runControlMessageHandler,
261  RunControlStateMachine::STARTUP_TRANSITION_NAME,
262  XDAQ_NS_URI);
263  xoap::bind(this,
264  &RunControlStateMachine::runControlMessageHandler,
265  RunControlStateMachine::FAIL_TRANSITION_NAME,
266  XDAQ_NS_URI);
267  xoap::bind(this,
268  &RunControlStateMachine::runControlMessageHandler,
269  RunControlStateMachine::ERROR_TRANSITION_NAME,
270  XDAQ_NS_URI);
271 
272  xoap::bind(this,
273  &RunControlStateMachine::runControlMessageHandler,
274  "AsyncError",
275  XDAQ_NS_URI);
276  xoap::bind(this,
277  &RunControlStateMachine::runControlMessageHandler,
278  "AsyncPauseException",
279  XDAQ_NS_URI);
280 
281  reset();
282 }
283 
284 //==============================================================================
285 RunControlStateMachine::~RunControlStateMachine(void) {}
286 
287 //==============================================================================
288 void RunControlStateMachine::reset(void)
289 {
290  __GEN_COUT__ << "Resetting RunControlStateMachine with name '"
291  << theStateMachine_.getStateMachineName() << "'..." << __E__;
292  theStateMachine_.setInitialState('I');
293  theStateMachine_.reset();
294 
295  theStateMachine_.setErrorMessage("", false /*append*/); // clear error message
296 
297  asyncFailureReceived_ = false;
298  asyncPauseExceptionReceived_ = false;
299  asyncStopExceptionReceived_ = false;
300 } // end reset()
301 
306 //{
307 // auto itFrom = stateTransitionFunctionTable_.find(from);
308 // if(itFrom == stateTransitionFunctionTable_.end())
309 // {
310 // __GEN_SS__ << "Cannot find transition function from '" << from <<
311 // "' with transition '" << transition << "!'" << __E__;
312 // XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
313 // }
314 //
315 // auto itTrans = itFrom->second.find(transition);
316 // if(itTrans == itFrom->second.end())
317 // {
318 // __GEN_SS__ << "Cannot find transition function from '" << from <<
319 // "' with transition '" << transition << "!'" << __E__;
320 // XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
321 // }
322 //
323 // return itTrans->second;
324 //}
325 
326 //==============================================================================
332  xoap::MessageReference message)
333 {
334  __GEN_COUTS__(2) << "Received... \t" << SOAPUtilities::translate(message)
335  << std::endl;
336 
337  std::string command = SOAPUtilities::translate(message).getCommand();
338 
339  // get subsystem-iteration index (outermost tier — synchronized across subsystems)
340  try
341  {
343  SOAPUtilities::translate(message).getParameters().getValue(
344  "subsystemIterationIndex"),
345  subsystemIterationIndex_);
346  }
347  catch(
348  ...) // ignore errors and set subsystem-iteration index to 0 (backward compat with old Gateway)
349  {
350  __GEN_COUTT__ << "Defaulting subsystemIterationIndex_ to 0." << __E__;
351  subsystemIterationIndex_ = 0;
352  }
353  // get iteration index
354  try
355  {
357  SOAPUtilities::translate(message).getParameters().getValue("iterationIndex"),
358  iterationIndex_);
359  }
360  catch(...) // ignore errors and set iteration index to 0
361  {
362  __GEN_COUT__ << "Defaulting iteration index to 0." << __E__;
363  iterationIndex_ = 0;
364  }
365  // get subIteration index
366  try
367  {
369  SOAPUtilities::translate(message).getParameters().getValue(
370  "subIterationIndex"),
371  subIterationIndex_);
372  }
373  catch(...) // ignore errors and set subIteration index to 0
374  {
375  __GEN_COUTT__ << "Defaulting subIterationIndex_ index to 0." << __E__;
376  subIterationIndex_ = 0;
377  }
378 
379  // get MinReadyForEventGenerationStartIteration
380  try
381  {
383  SOAPUtilities::translate(message).getParameters().getValue(
384  "MinReadyForEventGenerationStartIteration"),
385  minReadyForEventGenerationStartIteration_);
386  }
387  catch(...)
388  {
389  minReadyForEventGenerationStartIteration_ = 0;
390  }
391 
392  // get retransmission indicator
393  bool retransmittedCommand = false;
394  try
395  {
396  retransmittedCommand =
397  (SOAPUtilities::translate(message).getParameters().getValue(
398  "retransmission") == "1");
399  }
400  catch(
401  ...) // ignore errors for retransmission indicator (assume it is not a retransmission)
402  {
403  ;
404  }
405 
406  if(retransmittedCommand)
407  {
408  // handle retransmission
409  __GEN_COUT__ << "retransmission identified..." << __E__;
410 
411  // attempt to stop an error if last command was same
412  if(lastIterationCommand_ == command &&
413  lastSubsystemIterationIndex_ == subsystemIterationIndex_ &&
414  lastIterationIndex_ == iterationIndex_ &&
415  lastSubIterationIndex_ == subIterationIndex_)
416  {
417  __GEN_COUT__
418  << "Assuming a timeout occurred at Gateway waiting for a response. "
419  << "Attempting to avoid error, by giving last result for command '"
420  << command << "': " << lastIterationResult_ << __E__;
421  try
422  {
423  return SOAPUtilities::makeSOAPMessageReference(lastIterationResult_);
424  }
425  catch(const std::exception&
426  e) // if an illegal result ever propagates here, it is bug!
427  {
428  __GEN_COUT__ << "There was an illegal result propagation: "
429  << lastIterationResult_
430  << ". Here was the error: " << e.what() << __E__;
431  throw;
432  }
433  }
434  else
435  __GEN_COUT__ << "Looks like Gateway command '" << command
436  << "' was lost - attempting to handle retransmission." << __E__;
437  }
438 
439  lastSubsystemIterationIndex_ = subsystemIterationIndex_;
440  lastIterationIndex_ = iterationIndex_;
441  lastSubIterationIndex_ = subIterationIndex_;
442 
443  std::string currentState;
444  if(isFirstIteration())
445  {
446  // this is the first iteration attempt for this transition
447  theProgressBar_.reset(command, theStateMachine_.getStateMachineName());
448  currentState = theStateMachine_.getCurrentStateName();
449  __GEN_COUT__ << "Starting state for " << theStateMachine_.getStateMachineName()
450  << " is " << currentState << " and attempting to " << command
451  << std::endl;
452  }
453  else
454  {
455  currentState = theStateMachine_.getStateName(lastIterationState_);
456 
457  __GEN_COUTS__(2) << "Iteration index "
458  << (isStandaloneSubsystem()
459  ? std::string("standalone")
460  : std::to_string(subsystemIterationIndex_))
461  << ":" << iterationIndex_ << "." << subIterationIndex_ << " for "
462  << theStateMachine_.getStateMachineName() << " from "
463  << currentState << " attempting to " << command << std::endl;
464  }
465 
466  RunControlStateMachine::theProgressBar_.step();
467 
468  std::string result = command + "Done";
469  lastIterationResult_ = result;
470 
471  // if error is received, immediately go to fail state
472  // likely error was sent by central FSM or external xoap
473  if(command == "Error" || command == "Fail")
474  {
475  __GEN_SS__ << command << " was received! Halting immediately." << std::endl;
476  __GEN_COUT_ERR__ << "\n" << ss.str();
477 
478  try
479  {
480  if(currentState == "Configured")
481  theStateMachine_.execTransition(
482  RunControlStateMachine::HALT_TRANSITION_NAME, message);
483  else if(currentState == "Running" || currentState == "Paused")
484  theStateMachine_.execTransition(
485  RunControlStateMachine::ABORT_TRANSITION_NAME, message);
486  }
487  catch(...)
488  {
489  __GEN_COUT_ERR__ << "Halting failed in reaction to " << command
490  << "... ignoring." << __E__;
491  }
492  theProgressBar_.complete();
493  return SOAPUtilities::makeSOAPMessageReference(result);
494  }
495  else if(command == "AsyncError")
496  {
497  std::string errorMessage =
498  SOAPUtilities::translate(message).getParameters().getValue("ErrorMessage");
499 
500  __GEN_SS__ << command << " was received! Error'ing immediately: " << errorMessage
501  << std::endl;
502  __GEN_COUT_ERR__ << "\n" << ss.str();
503  theStateMachine_.setErrorMessage(ss.str());
504 
505  if(!asyncFailureReceived_.exchange(true))
506  {
507  // Thread safety: execTransition("fail") spins on inTransition_ and
508  // checks for already-FAILED. No use-after-free: XDAQ supervisors
509  // live for the process lifetime. stateMachineAccessMutex_ is
510  // GatewaySupervisor-specific and not available here.
511  std::thread([this]() {
512  try
513  {
514  theStateMachine_.execTransition("fail");
515  }
516  catch(...)
517  {
518  __GEN_COUT_ERR__ << "AsyncError: execTransition(fail) threw" << __E__;
519  }
520  }).detach();
521  }
522 
523  return SOAPUtilities::makeSOAPMessageReference(result);
524  }
525  else if(command == "AsyncPauseException")
526  {
527  std::string errorMessage =
528  SOAPUtilities::translate(message).getParameters().getValue("ErrorMessage");
529 
530  __GEN_SS__ << command << " was received! Pause'ing immediately: " << errorMessage
531  << std::endl;
532  __GEN_COUT_ERR__ << "\n" << ss.str();
533  theStateMachine_.setErrorMessage(ss.str());
534 
535  if(!asyncPauseExceptionReceived_.exchange(true))
536  {
537  // Thread safety: inTransition_ rejects concurrent transitions.
538  // No use-after-free: XDAQ supervisors live for the process lifetime.
539  std::thread([this]() {
540  try
541  {
542  theStateMachine_.execTransition("Pause");
543  }
544  catch(...)
545  {
546  __GEN_COUT_ERR__ << "AsyncPauseException: execTransition(Pause) threw"
547  << __E__;
548  }
549  }).detach();
550  }
551 
552  return SOAPUtilities::makeSOAPMessageReference(result);
553  }
554  else if(command == "AsyncStopException")
555  {
556  std::string errorMessage =
557  SOAPUtilities::translate(message).getParameters().getValue("ErrorMessage");
558 
559  __GEN_SS__ << command << " was received! Stop'ing immediately: " << errorMessage
560  << std::endl;
561  __GEN_COUT_ERR__ << "\n" << ss.str();
562  theStateMachine_.setErrorMessage(ss.str());
563 
564  if(!asyncStopExceptionReceived_.exchange(true))
565  {
566  // Thread safety: inTransition_ rejects concurrent transitions.
567  // No use-after-free: XDAQ supervisors live for the process lifetime.
568  std::thread([this]() {
569  try
570  {
571  theStateMachine_.execTransition("Stop");
572  }
573  catch(...)
574  {
575  __GEN_COUT_ERR__ << "AsyncStopException: execTransition(Stop) threw"
576  << __E__;
577  }
578  }).detach();
579  }
580 
581  return SOAPUtilities::makeSOAPMessageReference(result);
582  }
583 
584  // if already Halted, respond to Initialize with "done"
585  // (this avoids race conditions involved with artdaq mpi reset)
586  if(command == RunControlStateMachine::INIT_TRANSITION_NAME &&
587  currentState == RunControlStateMachine::HALTED_STATE_NAME)
588  {
589  __GEN_COUT__ << "Already Initialized.. ignoring Initialize command." << std::endl;
590 
591  theStateMachine_.setErrorMessage("", false /*append*/); // clear error message
592  return SOAPUtilities::makeSOAPMessageReference(result);
593  }
594 
595  if(command == RunControlStateMachine::INIT_TRANSITION_NAME &&
596  currentState == RunControlStateMachine::FAILED_STATE_NAME)
597  {
598  __GEN_COUT__ << "Converting Initialize command to Halt, since currently in "
599  << currentState << " state." << std::endl;
600  command = RunControlStateMachine::HALT_TRANSITION_NAME;
601  message = SOAPUtilities::makeSOAPMessageReference(command);
602  }
603 
604  if((command == RunControlStateMachine::HALT_TRANSITION_NAME ||
605  command == RunControlStateMachine::SHUTDOWN_TRANSITION_NAME) &&
606  currentState == RunControlStateMachine::FAILED_STATE_NAME)
607  {
608  __GEN_COUT__ << "Clearing Errors after failure..." << std::endl;
609  theStateMachine_.setErrorMessage("", false /*append*/); // clear error message
610  asyncFailureReceived_ = false;
611  asyncPauseExceptionReceived_ = false;
612  asyncStopExceptionReceived_ = false;
613  }
614 
615  if(command == RunControlStateMachine::RESUME_TRANSITION_NAME)
616  asyncPauseExceptionReceived_ = false;
617  if(command == RunControlStateMachine::START_TRANSITION_NAME)
618  asyncStopExceptionReceived_ = false;
619 
620  __GEN_COUTVS__(2, command);
621  __GEN_COUTVS__(2, currentState);
622  __GEN_COUTVS__(2, asyncFailureReceived_);
623  __GEN_COUTVS__(2, asyncPauseExceptionReceived_);
624  __GEN_COUTVS__(2, asyncStopExceptionReceived_);
625  __GEN_COUTVS__(2, getErrorMessage());
626  __GEN_COUTVS__(2, retransmittedCommand);
627 
628  // handle normal transitions here
629  try
630  {
631  // Clear error message if starting a normal transition.
632  // Do not clear soft PAUSE or harder STOP exception
633  // Do not clear if retransmission transition from Failed (likely an error just occured that we do not want to lose!)
634  if(!((asyncPauseExceptionReceived_ &&
635  command == RunControlStateMachine::PAUSE_TRANSITION_NAME) ||
636  (asyncStopExceptionReceived_ &&
637  command == RunControlStateMachine::STOP_TRANSITION_NAME)))
638  theStateMachine_.setErrorMessage("",
639  false /*append*/); // clear error message
640 
641  if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
642  currentState == RunControlStateMachine::INITIAL_STATE_NAME)
643  {
644  command = RunControlStateMachine::INIT_TRANSITION_NAME;
645  __GEN_COUT__ << "Converting Halt command to " << command
646  << ", since currently in " << currentState << " state."
647  << std::endl;
648  message = SOAPUtilities::makeSOAPMessageReference(command);
649  }
650  if(command == RunControlStateMachine::HALT_TRANSITION_NAME &&
651  (currentState == RunControlStateMachine::PAUSED_STATE_NAME ||
652  currentState == RunControlStateMachine::RUNNING_STATE_NAME))
653  {
654  command = RunControlStateMachine::ABORT_TRANSITION_NAME;
655  __GEN_COUT__ << "Converting Halt command to " << command
656  << ", since currently in " << currentState << " state."
657  << std::endl;
658  message = SOAPUtilities::makeSOAPMessageReference(command);
659  }
660  if(command == RunControlStateMachine::CONFIGURE_TRANSITION_NAME &&
661  currentState == RunControlStateMachine::INITIAL_STATE_NAME)
662  {
663  __GEN_COUT__
664  << "Pre-empting Configure command with Initialize, since currently in "
665  << currentState << " state." << std::endl;
666  std::string precommand = RunControlStateMachine::INIT_TRANSITION_NAME;
667  xoap::MessageReference premessage =
668  SOAPUtilities::makeSOAPMessageReference(precommand);
669  theStateMachine_.execTransition(precommand, premessage);
670  __GEN_COUT__ << "Now proceeding with Configure command" << __E__;
671  }
672 
673  subsystemIterationWorkFlag_ = false;
674  iterationWorkFlag_ = false;
675  subIterationWorkFlag_ = false;
676  if(!isFirstIteration())
677  {
678  __GEN_COUTS__(2) << command << " subsystemIteration="
679  << (isStandaloneSubsystem()
680  ? std::string("standalone")
681  : std::to_string(subsystemIterationIndex_))
682  << " iteration=" << iterationIndex_ << "."
683  << subIterationIndex_ << __E__;
684  toolbox::Event::Reference event(new toolbox::Event(command, this));
685 
686  // call inheriting transition function based on last state and command
687  {
688  // e.g. transitionConfiguring(event);
689  __GEN_COUTS__(2)
690  << "Iterating on the transition function from " << currentState
691  << " through " << lastIterationCommand_ << __E__;
692 
693  auto itFrom = stateTransitionFunctionTable_.find(lastIterationState_);
694  if(itFrom == stateTransitionFunctionTable_.end())
695  {
696  __GEN_SS__ << "Cannot find transition function from '" << currentState
697  << "' with transition '" << lastIterationCommand_ << "!'"
698  << __E__;
699  __GEN_COUT_ERR__ << ss.str();
700  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
701  }
702 
703  auto itTransition = itFrom->second.find(lastIterationCommand_);
704  if(itTransition == itFrom->second.end())
705  {
706  __GEN_SS__ << "Cannot find transition function from '" << currentState
707  << "' with transition '" << lastIterationCommand_ << "!'"
708  << __E__;
709  __GEN_COUT_ERR__ << ss.str();
710  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
711  }
712 
713  (this->*(itTransition->second))(event); // call the transition function
714  }
715  }
716  else
717  {
718  // save the lookup parameters for the last function to be called for the case
719  // of additional iterations
720  lastIterationState_ = theStateMachine_.getCurrentState();
721  lastIterationCommand_ = command;
722  if(command == RunControlStateMachine::CONFIGURE_TRANSITION_NAME)
723  {
724  lastAttemptedConfigureGroup_ =
725  SOAPUtilities::translate(message).getParameters().getValue(
726  "ConfigurationAlias");
727 
728  //all entities but Gateway will have alias group name and key translation:
729  try
730  {
731  lastAttemptedConfigureGroup_ +=
732  " " +
733  SOAPUtilities::translate(message).getParameters().getValue(
734  "ConfigurationTableGroupName") +
735  "(" +
736  SOAPUtilities::translate(message).getParameters().getValue(
737  "ConfigurationTableGroupKey") +
738  ")";
739  }
740  catch(...)
741  { /* ignore missing parameters */
742  }
743  }
744 
745  theStateMachine_.execTransition(command, message);
746  }
747 
748  if(subIterationWorkFlag_) // sub-iteration has highest priority
749  {
750  __GEN_COUTV__(subIterationWorkFlag_);
751  result =
752  command + "SubIterate"; // indicate another sub-iteration back to Gateway
753  }
754  else if(iterationWorkFlag_) // iteration has next priority
755  {
756  __GEN_COUTVS__(2, iterationWorkFlag_);
757  result = command + "Iterate"; // indicate another iteration back to Gateway
758  }
759  else if(
760  subsystemIterationWorkFlag_) // subsystem-iteration is lowest priority (cross-subsystem sync)
761  {
762  __GEN_COUTVS__(2, subsystemIterationWorkFlag_);
763  result =
764  command +
765  "SubsystemIterate"; // indicate another subsystem-iteration back to Gateway
766  }
767  }
768  catch(const std::runtime_error& e)
769  {
770  __GEN_SS__ << "Run Control Message Handling Failed with command '" << command
771  << "': " << e.what() << " " << theStateMachine_.getErrorMessage()
772  << __E__;
773  __GEN_COUT_ERR__ << ss.str();
774  theStateMachine_.setErrorMessage(ss.str());
775 
776  result = command + RunControlStateMachine::FAILED_STATE_NAME;
777  }
778  catch(toolbox::fsm::exception::Exception& e)
779  {
780  __GEN_SS__ << "Run Control Message Handling Failed with command '" << command
781  << "': " << e.what() << " " << theStateMachine_.getErrorMessage()
782  << __E__;
783  __GEN_COUT_ERR__ << ss.str();
784  theStateMachine_.setErrorMessage(ss.str());
785 
786  result = command + RunControlStateMachine::FAILED_STATE_NAME;
787  }
788  catch(...)
789  {
790  __GEN_SS__ << "Run Control Message Handling Failed with command '" << command
791  << "' and encountered an unknown error."
792  << theStateMachine_.getErrorMessage() << __E__;
793  try
794  {
795  throw;
796  } //one more try to printout extra info
797  catch(const std::exception& e)
798  {
799  ss << "Exception message: " << e.what();
800  }
801  catch(...)
802  {
803  }
804  __GEN_COUT_ERR__ << ss.str();
805  theStateMachine_.setErrorMessage(ss.str());
806 
807  result = command + RunControlStateMachine::FAILED_STATE_NAME;
808  }
809 
810  RunControlStateMachine::theProgressBar_.step();
811 
812  currentState = theStateMachine_.getCurrentStateName();
813 
814  if(currentState == RunControlStateMachine::FAILED_STATE_NAME)
815  {
816  result = command + RunControlStateMachine::FAILED_STATE_NAME;
817  __GEN_COUT_ERR__ << "Unexpected Failure state for "
818  << theStateMachine_.getStateMachineName() << " is "
819  << currentState << std::endl;
820  __GEN_COUT_ERR__ << "Error message was as follows: "
821  << theStateMachine_.getErrorMessage() << std::endl;
822  }
823 
824  RunControlStateMachine::theProgressBar_.step();
825 
826  if(!subsystemIterationWorkFlag_ && !iterationWorkFlag_ && !subIterationWorkFlag_)
827  theProgressBar_.complete();
828  else
829  {
830  __GEN_COUTVS__(2, theProgressBar_.read());
831  __GEN_COUTVS__(2, theProgressBar_.isComplete());
832  }
833 
834  __GEN_COUTS__(2) << "Ending state for " << theStateMachine_.getStateMachineName()
835  << " is " << currentState << std::endl;
836  __GEN_COUTS__(2) << "result = " << result << std::endl;
837  lastIterationResult_ = result;
838  return SOAPUtilities::makeSOAPMessageReference(result);
839 } // end runControlMessageHandler()
bool isComplete()
get functions
Definition: ProgressBar.cc:88
void reset(std::string file, std::string lineNumber, int id=0)
will call this reset:
Definition: ProgressBar.cc:41
int read()
if stepsToComplete==0, then define any progress as 50%, thread safe
Definition: ProgressBar.cc:120
void complete()
declare complete, thread safe
Definition: ProgressBar.cc:95
bool isFirstIteration(void) const
true on the very first call of a transition (all indices at their starting value)
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)