otsdaq  v2_05_02_indev
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 //==============================================================================
16 FiniteStateMachine::FiniteStateMachine(const std::string& stateMachineName)
17  : stateEntranceTime_(0), inTransition_(false), provenanceState_('X'), theErrorMessage_(""), stateMachineName_(stateMachineName)
18 {
19  __GEN_COUT__ << "Constructing FiniteStateMachine" << std::endl;
20 }
21 
22 //==============================================================================
23 FiniteStateMachine::~FiniteStateMachine(void) {}
24 
25 //==============================================================================
26 toolbox::fsm::State FiniteStateMachine::getProvenanceState(void) { return provenanceState_; }
27 
28 //==============================================================================
29 toolbox::fsm::State FiniteStateMachine::getTransitionFinalState(const std::string& transition)
30 {
31  if(stateTransitionTable_[currentState_].find(transition) != stateTransitionTable_[currentState_].end())
32  return stateTransitionTable_[currentState_][transition];
33  else
34  {
35  std::ostringstream error;
36  error << "Cannot find transition name with transition: " << transition << ", unknown!";
37  XCEPT_RAISE(toolbox::fsm::exception::Exception, error.str());
38  }
39 }
40 
41 //==============================================================================
42 std::string FiniteStateMachine::getProvenanceStateName(void) { return getStateName(getProvenanceState()); }
43 
44 //==============================================================================
45 std::string FiniteStateMachine::getCurrentStateName(void) { return getStateName(getCurrentState()); }
46 
47 //==============================================================================
48 // getTimeInState
49 // returns number of seconds elapsed while in current state
50 // returns 0 if invalid (i.e. stateEntranceTime_ is not set - stateEntranceTime_ is
51 // initialized to 0)
52 time_t FiniteStateMachine::getTimeInState(void) { return stateEntranceTime_ ? (time(0) - stateEntranceTime_) : 0; }
53 
54 //==============================================================================
55 std::string FiniteStateMachine::getCurrentTransitionName(const std::string& transition)
56 {
57  if(stateTransitionNameTable_[currentState_].find(transition) != stateTransitionNameTable_[currentState_].end())
58  {
59  return stateTransitionNameTable_[currentState_][transition];
60  }
61  else
62  {
63  std::ostringstream error;
64  error << "Cannot find transition name with transition: " << transition << ", unknown!";
65  XCEPT_RAISE(toolbox::fsm::exception::Exception, error.str());
66  }
67 }
68 
69 //==============================================================================
70 std::string FiniteStateMachine::getTransitionName(const toolbox::fsm::State from, const std::string& transition)
71 {
72  if(stateTransitionNameTable_[from].find(transition) != stateTransitionNameTable_[from].end())
73  {
74  return stateTransitionNameTable_[from][transition];
75  }
76  else
77  {
78  std::ostringstream error;
79  error << "Cannot find transition name from " << from << " with transition: " << transition << ", unknown!";
80  XCEPT_RAISE(toolbox::fsm::exception::Exception, error.str());
81  }
82 }
83 
84 //==============================================================================
85 std::string FiniteStateMachine::getTransitionParameter(const toolbox::fsm::State from, const std::string& transition)
86 {
87  if(stateTransitionParameterTable_[from].find(transition) != stateTransitionParameterTable_[from].end())
88  {
89  return stateTransitionParameterTable_[from][transition];
90  }
91  return "";
92 }
93 
94 //==============================================================================
95 std::string FiniteStateMachine::getTransitionFinalStateName(const std::string& transition) { return getStateName(getTransitionFinalState(transition)); }
96 
97 //==============================================================================
98 bool FiniteStateMachine::execTransition(const std::string& transition)
99 {
100  const xoap::MessageReference message;
101  return execTransition(transition, message);
102 }
103 
104 //==============================================================================
105 // execTransition
106 //
107 // Returns true if transition is successfully executed
108 // else false if this exec did not complete a transition.
109 //
110 // Note: For iteration handling, there is iterationIndex_ and iterationWorkFlag_.
111 // These are different (higher level) than the members of VStateMachine.
112 bool FiniteStateMachine::execTransition(const std::string& transition, const xoap::MessageReference& message)
113 {
114  __GEN_COUTV__(transition);
115 
116  if(transition == "fail")
117  {
118  __GEN_COUT_INFO__ << "Failing now!!" << __E__;
119 
120  while(inTransition_)
121  {
122  __GEN_COUT__ << "Currently in a transition executed from current state " << getProvenanceStateName()
123  << ". Attempting to wait for the transition to complete." << __E__;
124  sleep(1);
125  }
126  sleep(1);
127 
128  // find any valid transition and take it..
129  // all transition functions must check for a failure
130  // flag, and throw an exception to go to Fail state
131 
132  std::map<std::string, toolbox::fsm::State> transitions = getTransitions(getCurrentState());
133  for(const auto& transitionPair : transitions)
134  {
135  __GEN_COUT__ << "Taking transition to indirect failure: " << transitionPair.first << __E__;
136  toolbox::Event::Reference event(new toolbox::Event(transitionPair.first, this));
137 
138  try
139  {
140  this->fireEvent(event);
141  }
142  catch(toolbox::fsm::exception::Exception& e)
143  {
144  std::ostringstream error;
145  error << "Transition " << transition << " was not executed from current state " << getStateName(getCurrentState())
146  << ". There was an error: " << e.what();
147  __GEN_COUT_ERR__ << error.str() << std::endl;
148  }
149  inTransition_ = false;
150  stateEntranceTime_ = time(0);
151  return true;
152  }
153  // //XCEPT_RAISE (toolbox::fsm::exception::Exception, transition);
154  // theMessage_ = message;
155  // toolbox::Event::Reference event(new toolbox::Event(, this));
156  //
157  }
158 
159  if(inTransition_)
160  {
161  __GEN_COUT_WARN__ << "In transition, and received another transition: " << transition << ". Ignoring..." << __E__;
162 
163  return false;
164  }
165  inTransition_ = true;
166  bool transitionSuccessful = true;
167  provenanceState_ = getCurrentState();
168 
169  std::map<std::string, toolbox::fsm::State> transitions = getTransitions(getCurrentState());
170  if(transitions.find(transition) == transitions.end())
171  {
172  inTransition_ = false;
173  std::ostringstream error;
174  error << transition << " is not in the list of the transitions from current state " << getStateName(getCurrentState());
175  __GEN_COUT_ERR__ << error.str() << std::endl;
176  XCEPT_RAISE(toolbox::fsm::exception::Exception, error.str());
177  //__GEN_COUT__ << error << std::endl;
178  // __GEN_COUT__ << "Transition?" << inTransition_ << std::endl;
179  return false;
180  }
181 
182  // fire FSM event by calling mapped function
183  // (e.g. mapped by RunControlStateMachine and function implemented by
184  // CoreSupervisorBase class inheriting from RunControlStateMachine)
185  try
186  {
187  toolbox::Event::Reference event(new toolbox::Event(transition, this));
188  theMessage_ = message; // Even if it is bad, there can only be 1 transition at a time
189  // so this parameter should not change during all transition
190 
191  this->fireEvent(event);
192  }
193  catch(toolbox::fsm::exception::Exception& e)
194  {
195  inTransition_ = false;
196  transitionSuccessful = false;
197  std::ostringstream error;
198  __GEN_SS__ << "Transition " << transition << " was not executed from current state " << getStateName(getCurrentState())
199  << ". There was an error: " << e.what();
200  __GEN_COUT_ERR__ << ss.str() << std::endl;
201  // diagService_->reportError(err.str(),DIAGERROR);
202 
203  // send state machine to error
204  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
205  }
206  catch(...)
207  {
208  inTransition_ = false;
209  transitionSuccessful = false;
210  __GEN_SS__ << "Transition " << transition << " was not executed from current state " << getStateName(getCurrentState())
211  << ". There was an unknown error.";
212  __GEN_COUT_ERR__ << ss.str() << std::endl;
213  // diagService_->reportError(err.str(),DIAGERROR);
214 
215  // send state machine to error
216  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
217  }
218 
219  inTransition_ = false;
220  stateEntranceTime_ = time(0);
221  return transitionSuccessful;
222 }
223 
224 //==============================================================================
225 bool FiniteStateMachine::isInTransition(void) { return inTransition_; }
226 
227 //==============================================================================
228 void FiniteStateMachine::setErrorMessage(const std::string& errMessage, bool append)
229 {
230  if(append)
231  theErrorMessage_ += errMessage;
232  else
233  theErrorMessage_ = errMessage;
234 }
235 
236 //==============================================================================
237 const std::string& FiniteStateMachine::getErrorMessage() const { return theErrorMessage_; }
238 
239 //==============================================================================
240 void FiniteStateMachine::setInitialState(toolbox::fsm::State state)
241 {
242  toolbox::fsm::FiniteStateMachine::setInitialState(state);
243  provenanceState_ = state;
244  stateEntranceTime_ = time(0);
245 }
246 
247 //==============================================================================
248 const xoap::MessageReference& FiniteStateMachine::getCurrentMessage(void) { return theMessage_; }