otsdaq  3.07.00
FiniteStateMachine.cc
1 #include "otsdaq/FiniteStateMachine/FiniteStateMachine.h"
2 #include "otsdaq/MessageFacility/MessageFacility.h"
3 
4 #include "otsdaq/Macros/CoutMacros.h"
5 
6 #include <map>
7 #include <sstream>
8 
9 using namespace ots;
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "FSM"
13 #define mfSubject_ std::string("FSM-") + getStateMachineName()
14 
15 const char FiniteStateMachine::FAILED_STATE = 'F';
16 const std::string FiniteStateMachine::FAILED_STATE_NAME = "Failed";
17 const std::string FiniteStateMachine::ERROR_TRANSITION_NAME = "Error";
18 const std::string FiniteStateMachine::INITIAL_STATE_NAME = "Initial";
19 const std::string FiniteStateMachine::CONFIGURE_TRANSITION_NAME = "Configure";
20 
21 //==============================================================================
22 FiniteStateMachine::FiniteStateMachine(const std::string& stateMachineName)
23  : stateEntranceTime_(0)
24  , inTransition_(false)
25  , provenanceState_('X')
26  , theErrorMessage_("")
27  , stateMachineName_(stateMachineName)
28 {
29  __GEN_COUT__ << "Constructing FiniteStateMachine" << __E__;
30 } // end constructor()
31 
32 //==============================================================================
33 FiniteStateMachine::~FiniteStateMachine(void) {}
34 
35 //==============================================================================
36 toolbox::fsm::State FiniteStateMachine::getProvenanceState(void)
37 {
38  return provenanceState_;
39 }
40 
41 //==============================================================================
42 toolbox::fsm::State FiniteStateMachine::getTransitionFinalState(
43  const std::string& transition)
44 {
45  if(stateTransitionTable_[currentState_].find(transition) !=
46  stateTransitionTable_[currentState_].end())
47  return stateTransitionTable_[currentState_][transition];
48  else
49  {
50  if(transition == FiniteStateMachine::ERROR_TRANSITION_NAME)
51  {
52  __GEN_COUT__ << FiniteStateMachine::ERROR_TRANSITION_NAME << "'ing to "
53  << FiniteStateMachine::FAILED_STATE_NAME << __E__;
54  return stateTransitionTable_[FiniteStateMachine::FAILED_STATE]
55  [FiniteStateMachine::ERROR_TRANSITION_NAME];
56  }
57  __GEN_SS__ << "Cannot find transition name for transition '" << transition
58  << "' from current state '" << currentState_ << ".'" << __E__;
59  __GEN_COUT__ << ss.str();
60  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
61  }
62 } // end getTransitionFinalState()
63 
64 //==============================================================================
65 std::string FiniteStateMachine::getProvenanceStateName(void)
66 {
67  return getStateName(getProvenanceState());
68 }
69 
70 //==============================================================================
71 std::string FiniteStateMachine::getCurrentStateName(void)
72 {
73  return getStateName(getCurrentState());
74 }
75 
76 //==============================================================================
82 {
83  return stateEntranceTime_ ? (time(0) - stateEntranceTime_) : 0;
84 }
85 
86 //==============================================================================
87 std::string FiniteStateMachine::getCurrentTransitionName(const std::string& transition)
88 {
89  // __GEN_COUTV__(stateTransitionNameTable_.size());
90  // __GEN_SS__ << currentState_ << " " << transition << " " << currentTransition_ << __E__;
91  // __GEN_COUT__ << ss.str();
92  // __GEN_COUT__ << (stateTransitionNameTable_.find(currentState_) == stateTransitionNameTable_.end()?1:0);
93  // __GEN_COUT__ << (stateTransitionNameTable_.at(currentState_).find(transition) ==
94  // stateTransitionNameTable_.at(currentState_).end()?1:0);
95 
96  // for(auto startState : stateTransitionNameTable_)
97  // {
98  // __GEN_COUTV__(getStateName(startState.first));
99  // std::cout << startState.first << __E__;
100  // for(auto trans : stateTransitionNameTable_.at(startState.first))
101  // __GEN_COUT__ << "\t" << trans.first << " " << trans.second << __E__;
102  // }
103 
104  // if looking for current active transition, calculate from provenance state
105  if(transition == "")
106  {
107  if(stateTransitionNameTable_.at(provenanceState_).find(currentTransition_) !=
108  stateTransitionNameTable_.at(provenanceState_).end())
109  return stateTransitionNameTable_.at(provenanceState_).at(currentTransition_);
110  else
111  {
112  if(currentTransition_ == FiniteStateMachine::ERROR_TRANSITION_NAME)
113  {
114  __GEN_COUT__ << FiniteStateMachine::ERROR_TRANSITION_NAME << "'ing to "
115  << FiniteStateMachine::FAILED_STATE_NAME << __E__;
116  return currentTransition_;
117  }
118  __GEN_SS__ << "Cannot find transition name from '" << getProvenanceStateName()
119  << "' for command: " << currentTransition_ << "...";
120  __GEN_COUT_WARN__
121  << ss.str(); //reduce to warning because transitions like 'Configure' can jump multiple states, e.g. from Initial
122  return currentTransition_;
123  }
124  }
125 
126  if(stateTransitionNameTable_.at(currentState_).find(transition) !=
127  stateTransitionNameTable_.at(currentState_).end())
128  {
129  return stateTransitionNameTable_.at(currentState_).at(transition);
130  }
131  else
132  {
133  if(transition == FiniteStateMachine::ERROR_TRANSITION_NAME)
134  {
135  __GEN_COUT__ << FiniteStateMachine::ERROR_TRANSITION_NAME << "'ing to "
136  << FiniteStateMachine::FAILED_STATE_NAME << __E__;
137  return transition;
138  }
139  std::stringstream ss;
140  ss << "Cannot find transition name from '" << getCurrentStateName()
141  << "' for command: " << transition << "...";
142 
143  //reduce severity because transitions like 'Configure' are now allowed to jump multiple states, e.g. from Initial
144  if(transition == FiniteStateMachine::CONFIGURE_TRANSITION_NAME &&
145  getCurrentStateName() == FiniteStateMachine::INITIAL_STATE_NAME)
146  __GEN_COUTT__ << ss.str();
147  else
148  __GEN_COUT_WARN__ << ss.str();
149  return transition;
150  }
151 } // end getCurrentTransitionName()
152 
153 //==============================================================================
154 std::string FiniteStateMachine::getTransitionName(const toolbox::fsm::State from,
155  const std::string& transition)
156 {
157  if(stateTransitionNameTable_[from].find(transition) !=
158  stateTransitionNameTable_[from].end())
159  {
160  return stateTransitionNameTable_[from][transition];
161  }
162  else
163  {
164  if(transition == FiniteStateMachine::ERROR_TRANSITION_NAME)
165  {
166  __GEN_COUT__ << FiniteStateMachine::ERROR_TRANSITION_NAME << "'ing to "
167  << FiniteStateMachine::FAILED_STATE_NAME << __E__;
168  return transition;
169  }
170  std::ostringstream error;
171  error << "Cannot find transition name from '" << from
172  << "' for command: " << transition << __E__;
173  XCEPT_RAISE(toolbox::fsm::exception::Exception, error.str());
174  }
175 } // end getTransitionName()
176 
177 //==============================================================================
178 std::string FiniteStateMachine::getTransitionParameter(const toolbox::fsm::State from,
179  const std::string& transition)
180 {
181  if(stateTransitionParameterTable_[from].find(transition) !=
182  stateTransitionParameterTable_[from].end())
183  {
184  return stateTransitionParameterTable_[from][transition];
185  }
186  return "";
187 } // end getTransitionParameter()
188 
189 //==============================================================================
190 std::string FiniteStateMachine::getTransitionFinalStateName(const std::string& transition)
191 {
192  return getStateName(getTransitionFinalState(transition));
193 }
194 
195 //==============================================================================
196 bool FiniteStateMachine::execTransition(const std::string& transition)
197 {
198  const xoap::MessageReference message;
199  return execTransition(transition, message);
200 } // end execTransition()
201 
202 //==============================================================================
210 bool FiniteStateMachine::execTransition(const std::string& transition,
211  const xoap::MessageReference& message)
212 {
213  __GEN_COUTV__(transition);
214 
215  if(transition == "fail")
216  {
217  while(inTransition_)
218  {
219  __GEN_COUT__ << "Currently in transition '" << currentTransition_
220  << "' executed from current state " << getProvenanceStateName()
221  << ". Attempting to wait for the transition to complete."
222  << __E__;
223  sleep(1);
224  }
225  sleep(1);
226 
227  if(getStateName(getCurrentState()) == FiniteStateMachine::FAILED_STATE_NAME)
228  {
229  __GEN_COUT_INFO__ << "Already failed. Current state: "
230  << getStateName(getCurrentState())
231  << " last state: " << getProvenanceStateName() << __E__;
232  return true;
233  }
234  __GEN_COUT_INFO__ << "Failing now!! Current state: "
235  << getStateName(getCurrentState())
236  << " last state: " << getProvenanceStateName() << __E__;
237 
238  // find any valid transition and take it..
239  // all transition functions must check for a failure
240  // flag, and throw an exception to go to Fail state
241 
242  std::map<std::string, toolbox::fsm::State> transitions =
243  getTransitions(getCurrentState());
244  for(const auto& transitionPair : transitions)
245  {
246  __GEN_COUT__ << "Taking any transition to indirect failure.. found '"
247  << transitionPair.first << "'" << __E__;
248  __GEN_COUT__ << "Taking fail transition from Current state: "
249  << getStateName(getCurrentState())
250  << " last state: " << getProvenanceStateName() << __E__;
251  toolbox::Event::Reference event(
252  new toolbox::Event(transitionPair.first, this));
253 
254  try
255  {
256  this->fireEvent(event);
257  }
258  catch(toolbox::fsm::exception::Exception& e)
259  {
260  std::ostringstream error;
261  error << "Transition " << transition
262  << " was not executed from current state "
263  << getStateName(getCurrentState())
264  << ". There was an error: " << e.what();
265  __GEN_COUT_ERR__ << error.str() << __E__;
266  }
267  inTransition_ = false;
268  stateEntranceTime_ = time(0);
269  return true;
270  }
271  // //XCEPT_RAISE (toolbox::fsm::exception::Exception, transition);
272  // theMessage_ = message;
273  // toolbox::Event::Reference event(new toolbox::Event(, this));
274  //
275  }
276 
277  if(inTransition_)
278  {
279  __GEN_COUT_WARN__ << "In transition, and received another transition: "
280  << transition << ". Ignoring..." << __E__;
281  return false;
282  }
283  inTransition_ = true;
284  bool transitionSuccessful = true;
285  provenanceState_ = getCurrentState();
286 
287  std::map<std::string, toolbox::fsm::State> transitions =
288  getTransitions(getCurrentState());
289  if(transitions.find(transition) == transitions.end())
290  {
291  inTransition_ = false;
292  std::ostringstream error;
293  error << transition
294  << " is not in the list of the transitions from current state "
295  << getStateName(getCurrentState());
296  __GEN_COUT_ERR__ << error.str() << __E__;
297  __GEN_COUTV__(getErrorMessage());
298  XCEPT_RAISE(toolbox::fsm::exception::Exception, error.str());
299  //__GEN_COUT__ << error << __E__;
300  // __GEN_COUT__ << "Transition?" << inTransition_ << __E__;
301  return false;
302  }
303 
304  // fire FSM event by calling mapped function
305  // (e.g. mapped by RunControlStateMachine and function implemented by
306  // CoreSupervisorBase class inheriting from RunControlStateMachine)
307  try
308  {
309  toolbox::Event::Reference event(new toolbox::Event(transition, this));
310  theMessage_ =
311  message; // Even if it is bad, there can only be 1 transition at a time
312  // so this parameter should not change during all transition
313  currentTransition_ = transition;
314 
315  this->fireEvent(event);
316  }
317  catch(toolbox::fsm::exception::Exception& e)
318  {
319  inTransition_ = false;
320  transitionSuccessful = false;
321  std::ostringstream error;
322  __GEN_SS__ << "Transition " << transition
323  << " was not executed from current state "
324  << getStateName(getCurrentState())
325  << ". There was an error: " << e.what();
326  __GEN_COUT_ERR__ << ss.str() << __E__;
327  // diagService_->reportError(err.str(),DIAGERROR);
328 
329  // send state machine to error
330  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
331  }
332  catch(...)
333  {
334  inTransition_ = false;
335  transitionSuccessful = false;
336  __GEN_SS__ << "Transition " << transition
337  << " was not executed from current state "
338  << getStateName(getCurrentState()) << ". There was an unknown error.";
339  try
340  {
341  throw;
342  } //one more try to printout extra info
343  catch(const std::exception& e)
344  {
345  ss << "Exception message: " << e.what();
346  }
347  catch(...)
348  {
349  }
350  __GEN_COUT_ERR__ << ss.str() << __E__;
351  // diagService_->reportError(err.str(),DIAGERROR);
352 
353  // send state machine to error
354  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
355  }
356 
357  inTransition_ = false;
358  stateEntranceTime_ = time(0);
359  return transitionSuccessful;
360 } // end execTransition()
361 
362 //==============================================================================
363 bool FiniteStateMachine::isInTransition(void) { return inTransition_; }
364 
365 //==============================================================================
366 void FiniteStateMachine::setErrorMessage(const std::string& errMessage, bool append)
367 {
368  if(append)
369  theErrorMessage_ += errMessage;
370  else
371  theErrorMessage_ = errMessage;
372 } // end setErrorMessage()
373 
374 //==============================================================================
375 const std::string& FiniteStateMachine::getErrorMessage() const
376 {
377  return theErrorMessage_;
378 }
379 
380 //==============================================================================
381 void FiniteStateMachine::setInitialState(toolbox::fsm::State state)
382 {
383  toolbox::fsm::FiniteStateMachine::setInitialState(state);
384  provenanceState_ = state;
385  stateEntranceTime_ = time(0);
386 } // end setInitialState()
time_t getTimeInState(void) const
defines used also by OtsConfigurationWizardSupervisor