otsdaq  v2_05_02_indev
Iterator.cc
1 #include "otsdaq/GatewaySupervisor/Iterator.h"
2 #include "otsdaq/CoreSupervisors/CoreSupervisorBase.h"
3 #include "otsdaq/GatewaySupervisor/GatewaySupervisor.h"
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/MessageFacility/MessageFacility.h"
6 #include "otsdaq/WebUsersUtilities/WebUsers.h"
7 
8 #include <iostream>
9 #include <thread> //for std::thread
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "Iterator"
13 
14 using namespace ots;
15 
16 //==============================================================================
17 Iterator::Iterator(GatewaySupervisor* supervisor)
18  : workloopRunning_(false)
19  , activePlanIsRunning_(false)
20  , iteratorBusy_(false)
21  , commandPlay_(false)
22  , commandPause_(false)
23  , commandHalt_(false)
24  , activePlanName_("")
25  , activeCommandIndex_(-1)
26  , activeCommandStartTime_(0)
27  , theSupervisor_(supervisor)
28 {
29  __MOUT__ << "Iterator constructed." << __E__;
30  __COUT__ << "Iterator constructed." << __E__;
31 }
32 
33 //==============================================================================
34 Iterator::~Iterator(void) {}
35 
36 //==============================================================================
37 void Iterator::IteratorWorkLoop(Iterator* iterator) try
38 {
39  __MOUT__ << "Iterator work loop starting..." << __E__;
40  __COUT__ << "Iterator work loop starting..." << __E__;
41 
42  // mutex init scope
43  {
44  // lockout the messages array for the remainder of the scope
45  // this guarantees the reading thread can safely access the messages
46  if(iterator->theSupervisor_->VERBOSE_MUTEX)
47  __COUT__ << "Waiting for iterator access" << __E__;
48  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
49  if(iterator->theSupervisor_->VERBOSE_MUTEX)
50  __COUT__ << "Have iterator access" << __E__;
51 
52  iterator->errorMessage_ = ""; // clear error message
53  }
54 
55  ConfigurationManagerRW theConfigurationManager(WebUsers::DEFAULT_ITERATOR_USERNAME); // this is a restricted username
56  // theConfigurationManager.init();
57  theConfigurationManager.getAllTableInfo(true); // to prep all info
58 
59  IteratorWorkLoopStruct theIteratorStruct(iterator, &theConfigurationManager);
60 
61  const IterateTable* itConfig;
62 
63  std::vector<IterateTable::Command> commands;
64 
65  while(1)
66  {
67  // Process:
68  // - always "listen" for commands
69  // - play: if no plan running, activePlanIsRunning_ = true,
70  // and start or continue plan based on name/commandIndex
71  // - pause: if plan playing, pause it, activePlanIsRunning_ = false
72  // and do not clear commandIndex or name, iteratorBusy_ = true
73  // - halt: if plan playing or not, activePlanIsRunning_ = false
74  // and clear commandIndex or name, iteratorBusy_ = false
75  // - when running
76  // - go through each command
77  // - start the command, commandBusy = true
78  // - check for complete, then commandBusy = false
79 
80  // start command handling
81  // define mutex scope
82  {
83  // lockout the messages array for the remainder of the scope
84  // this guarantees the reading thread can safely access the messages
85  if(iterator->theSupervisor_->VERBOSE_MUTEX)
86  __COUT__ << "Waiting for iterator access" << __E__;
87  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
88  if(iterator->theSupervisor_->VERBOSE_MUTEX)
89  __COUT__ << "Have iterator access" << __E__;
90 
91  if(iterator->commandPlay_)
92  {
93  iterator->commandPlay_ = false; // clear
94 
95  if(!iterator->activePlanIsRunning_)
96  {
97  // valid PLAY command!
98 
99  iterator->activePlanIsRunning_ = true;
100  iterator->iteratorBusy_ = true;
101 
102  if(theIteratorStruct.activePlan_ != iterator->activePlanName_)
103  {
104  __COUT__ << "New plan name encountered old=" << theIteratorStruct.activePlan_ << " vs new=" << iterator->activePlanName_ << __E__;
105  theIteratorStruct.commandIndex_ = -1; // reset for new plan
106  }
107 
108  theIteratorStruct.activePlan_ = iterator->activePlanName_;
109  iterator->lastStartedPlanName_ = iterator->activePlanName_;
110 
111  if(theIteratorStruct.commandIndex_ == (unsigned int)-1)
112  {
113  __COUT__ << "Starting plan '" << theIteratorStruct.activePlan_ << ".'" << __E__;
114  __MOUT__ << "Starting plan '" << theIteratorStruct.activePlan_ << ".'" << __E__;
115  }
116  else
117  {
118  theIteratorStruct.doResumeAction_ = true;
119  __COUT__ << "Continuing plan '" << theIteratorStruct.activePlan_ << "' at command index " << theIteratorStruct.commandIndex_ << ". "
120  << __E__;
121  __MOUT__ << "Continuing plan '" << theIteratorStruct.activePlan_ << "' at command index " << theIteratorStruct.commandIndex_ << ". "
122  << __E__;
123  }
124  }
125  }
126  else if(iterator->commandPause_ && !theIteratorStruct.doPauseAction_)
127  {
128  theIteratorStruct.doPauseAction_ = true;
129  iterator->commandPause_ = false; // clear
130  }
131  else if(iterator->commandHalt_ && !theIteratorStruct.doHaltAction_)
132  {
133  theIteratorStruct.doHaltAction_ = true;
134  iterator->commandHalt_ = false; // clear
135  }
136 
137  theIteratorStruct.running_ = iterator->activePlanIsRunning_;
138 
139  if(iterator->activeCommandIndex_ != // update active command status if changed
140  theIteratorStruct.commandIndex_)
141  {
142  iterator->activeCommandIndex_ = theIteratorStruct.commandIndex_;
143  iterator->activeCommandStartTime_ = time(0); // reset on any change
144 
145  if(theIteratorStruct.commandIndex_ < theIteratorStruct.commandIterations_.size())
146  iterator->activeCommandIteration_ = theIteratorStruct.commandIterations_[theIteratorStruct.commandIndex_];
147  else
148  iterator->activeCommandIteration_ = -1;
149 
150  iterator->depthIterationStack_.clear();
151  for(const auto& depthIteration : theIteratorStruct.stepIndexStack_)
152  iterator->depthIterationStack_.push_back(depthIteration);
153  // if(theIteratorStruct.stepIndexStack_.size())
154  // iterator->activeLoopIteration_ =
155  // theIteratorStruct.stepIndexStack_.back(); else
156  // iterator->activeLoopIteration_ = -1;
157  }
158 
159  } // end command handling and iterator mutex
160 
163  // do halt or pause action outside of iterator mutex
164 
165  if(theIteratorStruct.doPauseAction_)
166  {
167  // valid PAUSE command!
168 
169  // safely pause plan!
170  // i.e. check that command is complete
171 
172  __COUT__ << "Waiting to pause..." << __E__;
173  while(!iterator->checkCommand(&theIteratorStruct))
174  __COUT__ << "Waiting to pause..." << __E__;
175 
176  __COUT__ << "Completing pause..." << __E__;
177 
178  theIteratorStruct.doPauseAction_ = false; // clear
179 
180  // lockout the messages array for the remainder of the scope
181  // this guarantees the reading thread can safely access the messages
182  if(iterator->theSupervisor_->VERBOSE_MUTEX)
183  __COUT__ << "Waiting for iterator access" << __E__;
184  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
185  if(iterator->theSupervisor_->VERBOSE_MUTEX)
186  __COUT__ << "Have iterator access" << __E__;
187 
188  iterator->activePlanIsRunning_ = false;
189 
190  __COUT__ << "Paused plan '" << theIteratorStruct.activePlan_ << "' at command index " << theIteratorStruct.commandIndex_ << ". " << __E__;
191  __MOUT__ << "Paused plan '" << theIteratorStruct.activePlan_ << "' at command index " << theIteratorStruct.commandIndex_ << ". " << __E__;
192 
193  continue; // resume workloop
194  }
195  else if(theIteratorStruct.doHaltAction_)
196  {
197  // valid HALT command!
198 
199  // safely end plan!
200  // i.e. check that command is complete
201 
202  __COUT__ << "Waiting to halt..." << __E__;
203  while(!iterator->checkCommand(&theIteratorStruct))
204  __COUT__ << "Waiting to halt..." << __E__;
205 
206  __COUT__ << "Completing halt..." << __E__;
207 
208  theIteratorStruct.doHaltAction_ = false; // clear
209 
210  iterator->haltIterator(iterator, &theIteratorStruct);
211 
212  // //last ditch effort to make sure FSM is halted
213  // iterator->haltIterator(
214  // iterator->theSupervisor_,
215  // theIteratorStruct.fsmName_);
216  //
217  // //lockout the messages array for the remainder of the scope
218  // //this guarantees the reading thread can safely access the
219  // messages
220  // if(iterator->theSupervisor_->VERBOSE_MUTEX) __COUT__ << "Waiting
221  // for iterator access" << __E__; std::lock_guard<std::mutex>
222  // lock(iterator->accessMutex_);
223  // if(iterator->theSupervisor_->VERBOSE_MUTEX) __COUT__ << "Have
224  // iterator access" << __E__;
225  //
226  // iterator->activePlanIsRunning_ = false;
227  // iterator->iteratorBusy_ = false;
228  //
229  // __COUT__ << "Halted plan '" << theIteratorStruct.activePlan_ << "'
230  // at command index " << theIteratorStruct.commandIndex_ <<
231  //". " << __E__;
232  // __MOUT__ << "Halted plan '" << theIteratorStruct.activePlan_ << "'
233  // at command index " << theIteratorStruct.commandIndex_ <<
234  //". " << __E__;
235  //
236  // theIteratorStruct.activePlan_ = ""; //clear
237  // theIteratorStruct.commandIndex_ = -1; //clear
238 
239  continue; // resume workloop
240  }
241 
244  // handle running
245  // __COUT__ << "thinking.." << theIteratorStruct.running_ << " " <<
246  // theIteratorStruct.activePlan_ << " cmd=" <<
247  // theIteratorStruct.commandIndex_ << __E__;
248  if(theIteratorStruct.running_ && theIteratorStruct.activePlan_ != "") // important, because after errors, still "running" until halt
249  {
250  if(theIteratorStruct.commandIndex_ == (unsigned int)-1)
251  {
252  // initialize the running plan
253 
254  __COUT__ << "Get commands" << __E__;
255 
256  theIteratorStruct.commandIndex_ = 0;
257 
258  theIteratorStruct.cfgMgr_->init(); // completely reset to re-align with any changes
259  itConfig = theIteratorStruct.cfgMgr_->__GET_CONFIG__(IterateTable);
260 
261  theIteratorStruct.commands_ = itConfig->getPlanCommands(theIteratorStruct.cfgMgr_, theIteratorStruct.activePlan_);
262 
263  // reset commandIteration counts
264  theIteratorStruct.commandIterations_.clear();
265  for(auto& command : theIteratorStruct.commands_)
266  {
267  theIteratorStruct.commandIterations_.push_back(0);
268  __COUT__ << "command " << command.type_ << __E__;
269  __COUT__ << "table " << IterateTable::commandToTableMap_.at(command.type_) << __E__;
270  __COUT__ << "param count = " << command.params_.size() << __E__;
271 
272  for(auto& param : command.params_)
273  {
274  __COUT__ << "\t param " << param.first << " : " << param.second << __E__;
275  }
276  }
277 
278  theIteratorStruct.originalTrackChanges_ = ConfigurationInterface::isVersionTrackingEnabled();
279  theIteratorStruct.originalConfigGroup_ = theIteratorStruct.cfgMgr_->getActiveGroupName();
280  theIteratorStruct.originalConfigKey_ = theIteratorStruct.cfgMgr_->getActiveGroupKey();
281 
282  __COUT__ << "originalTrackChanges " << theIteratorStruct.originalTrackChanges_ << __E__;
283  __COUT__ << "originalConfigGroup " << theIteratorStruct.originalConfigGroup_ << __E__;
284  __COUT__ << "originalConfigKey " << theIteratorStruct.originalConfigKey_ << __E__;
285 
286  } // end initial section
287 
288  if(!theIteratorStruct.commandBusy_)
289  {
290  if(theIteratorStruct.commandIndex_ < theIteratorStruct.commands_.size())
291  {
292  // execute command
293  theIteratorStruct.commandBusy_ = true;
294 
295  __COUT__ << "Iterator starting command " << theIteratorStruct.commandIndex_ + 1 << ": "
296  << theIteratorStruct.commands_[theIteratorStruct.commandIndex_].type_ << __E__;
297  __MOUT__ << "Iterator starting command " << theIteratorStruct.commandIndex_ + 1 << ": "
298  << theIteratorStruct.commands_[theIteratorStruct.commandIndex_].type_ << __E__;
299 
300  iterator->startCommand(&theIteratorStruct);
301  }
302  else if(theIteratorStruct.commandIndex_ == theIteratorStruct.commands_.size()) // Done!
303  {
304  __COUT__ << "Finished Iteration Plan '" << theIteratorStruct.activePlan_ << __E__;
305  __MOUT__ << "Finished Iteration Plan '" << theIteratorStruct.activePlan_ << __E__;
306 
307  __COUT__ << "Reverting track changes." << __E__;
308  ConfigurationInterface::setVersionTrackingEnabled(theIteratorStruct.originalTrackChanges_);
309 
310  __COUT__ << "Activating original group..." << __E__;
311  try
312  {
313  theIteratorStruct.cfgMgr_->activateTableGroup(theIteratorStruct.originalConfigGroup_, theIteratorStruct.originalConfigKey_);
314  }
315  catch(...)
316  {
317  __COUT_WARN__ << "Original group could not be activated." << __E__;
318  }
319 
320  // leave FSM halted
321  __COUT__ << "Completing halt..." << __E__;
322 
323  iterator->haltIterator(iterator, &theIteratorStruct);
324 
325  //
326  // //leave FSM halted
327  // iterator->haltIterator(
328  // iterator->theSupervisor_,
329  // theIteratorStruct.fsmName_);
330  //
331  // //lockout the messages array for the remainder of
332  // the scope
333  // //this guarantees the reading thread can safely
334  // access the messages
335  // if(iterator->theSupervisor_->VERBOSE_MUTEX)
336  //__COUT__
337  //<< "Waiting for iterator access" << __E__;
338  // std::lock_guard<std::mutex>
339  // lock(iterator->accessMutex_);
340  // if(iterator->theSupervisor_->VERBOSE_MUTEX)
341  //__COUT__
342  //<< "Have iterator access" << __E__;
343  //
344  // //similar to halt
345  // iterator->activePlanIsRunning_ = false;
346  // iterator->iteratorBusy_ = false;
347  //
348  // iterator->lastStartedPlanName_ =
349  // theIteratorStruct.activePlan_;
350  // theIteratorStruct.activePlan_ = ""; //clear
351  // theIteratorStruct.commandIndex_ = -1; //clear
352  }
353  }
354  else if(theIteratorStruct.commandBusy_)
355  {
356  // check for command completion
357  if(iterator->checkCommand(&theIteratorStruct))
358  {
359  theIteratorStruct.commandBusy_ = false; // command complete
360 
361  ++theIteratorStruct.commandIndex_;
362 
363  __COUT__ << "Ready for next command. Done with " << theIteratorStruct.commandIndex_ << " of " << theIteratorStruct.commands_.size()
364  << __E__;
365  __MOUT__ << "Iterator ready for next command. Done with " << theIteratorStruct.commandIndex_ << " of " << theIteratorStruct.commands_.size()
366  << __E__;
367  }
368 
369  // Note: check command gets one shot to resume
370  if(theIteratorStruct.doResumeAction_) // end resume action
371  theIteratorStruct.doResumeAction_ = false;
372  }
373 
374  } // end running
375  else
376  sleep(1); // when inactive sleep a lot
377 
380 
381  // __COUT__ << "end loop.." << theIteratorStruct.running_ << " " <<
382  // theIteratorStruct.activePlan_ << " cmd=" <<
383  // theIteratorStruct.commandIndex_ << __E__;
384  }
385 
386  iterator->workloopRunning_ = false; // if we ever exit
387 }
388 catch(const std::runtime_error& e)
389 {
390  __SS__ << "Encountered error in Iterator thread:\n" << e.what() << __E__;
391  __COUT_ERR__ << ss.str();
392 
393  // lockout the messages array for the remainder of the scope
394  // this guarantees the reading thread can safely access the messages
395  if(iterator->theSupervisor_->VERBOSE_MUTEX)
396  __COUT__ << "Waiting for iterator access" << __E__;
397  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
398  if(iterator->theSupervisor_->VERBOSE_MUTEX)
399  __COUT__ << "Have iterator access" << __E__;
400 
401  iterator->workloopRunning_ = false; // if we ever exit
402  iterator->errorMessage_ = ss.str();
403 }
404 catch(...)
405 {
406  __SS__ << "Encountered unknown error in Iterator thread." << __E__;
407  __COUT_ERR__ << ss.str();
408 
409  // lockout the messages array for the remainder of the scope
410  // this guarantees the reading thread can safely access the messages
411  if(iterator->theSupervisor_->VERBOSE_MUTEX)
412  __COUT__ << "Waiting for iterator access" << __E__;
413  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
414  if(iterator->theSupervisor_->VERBOSE_MUTEX)
415  __COUT__ << "Have iterator access" << __E__;
416 
417  iterator->workloopRunning_ = false; // if we ever exit
418  iterator->errorMessage_ = ss.str();
419 } // end IteratorWorkLoop()
420 
421 //==============================================================================
422 void Iterator::startCommand(IteratorWorkLoopStruct* iteratorStruct) try
423 {
424  {
425  int i = 0;
426  for(const auto& depthIteration : iteratorStruct->stepIndexStack_)
427  {
428  __COUT__ << i++ << ":" << depthIteration << __E__;
429  }
430  }
431 
432  // should be mutually exclusive with GatewaySupervisor main thread state machine
433  // accesses lockout the messages array for the remainder of the scope this
434  // guarantees the reading thread can safely access the messages
435  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
436  __COUT__ << "Waiting for FSM access" << __E__;
437  std::lock_guard<std::mutex> lock(iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
438  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
439  __COUT__ << "Have FSM access" << __E__;
440 
441  // for out of range, throw exception - should never happen
442  if(iteratorStruct->commandIndex_ >= iteratorStruct->commands_.size())
443  {
444  __SS__ << "Out of range commandIndex = " << iteratorStruct->commandIndex_ << " in size = " << iteratorStruct->commands_.size() << __E__;
445  __SS_THROW__;
446  }
447 
448  // increment iteration count for command
449  ++iteratorStruct->commandIterations_[iteratorStruct->commandIndex_];
450 
451  std::string type = iteratorStruct->commands_[iteratorStruct->commandIndex_].type_;
452  if(type == IterateTable::COMMAND_BEGIN_LABEL)
453  {
454  return startCommandBeginLabel(iteratorStruct);
455  }
456  else if(type == IterateTable::COMMAND_CHOOSE_FSM)
457  {
458  return startCommandChooseFSM(iteratorStruct,
459  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandChooseFSMParams_.NameOfFSM_]);
460  }
461  else if(type == IterateTable::COMMAND_CONFIGURE_ACTIVE_GROUP)
462  {
463  return startCommandConfigureActive(iteratorStruct);
464  }
465  else if(type == IterateTable::COMMAND_CONFIGURE_ALIAS)
466  {
467  return startCommandConfigureAlias(
468  iteratorStruct, iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandConfigureAliasParams_.SystemAlias_]);
469  }
470  else if(type == IterateTable::COMMAND_CONFIGURE_GROUP)
471  {
472  return startCommandConfigureGroup(iteratorStruct);
473  }
474  else if(type == IterateTable::COMMAND_EXECUTE_FE_MACRO)
475  {
476  return startCommandMacro(iteratorStruct, true /*isFEMacro*/);
477  }
478  else if(type == IterateTable::COMMAND_EXECUTE_MACRO)
479  {
480  return startCommandMacro(iteratorStruct, false /*isFEMacro*/);
481  }
482  else if(type == IterateTable::COMMAND_MODIFY_ACTIVE_GROUP)
483  {
484  return startCommandModifyActive(iteratorStruct);
485  }
486  else if(type == IterateTable::COMMAND_REPEAT_LABEL)
487  {
488  return startCommandRepeatLabel(iteratorStruct);
489  }
490  else if(type == IterateTable::COMMAND_RUN)
491  {
492  return startCommandRun(iteratorStruct);
493  }
494  else
495  {
496  __SS__ << "Failed attempt to start unrecognized command type = " << type << __E__;
497  __COUT_ERR__ << ss.str();
498  __SS_THROW__;
499  }
500 }
501 catch(...)
502 {
503  __COUT__ << "Error caught. Reverting track changes." << __E__;
504  ConfigurationInterface::setVersionTrackingEnabled(iteratorStruct->originalTrackChanges_);
505 
506  __COUT__ << "Activating original group..." << __E__;
507  try
508  {
509  iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_, iteratorStruct->originalConfigKey_);
510  }
511  catch(...)
512  {
513  __COUT_WARN__ << "Original group could not be activated." << __E__;
514  }
515  throw;
516 } // end startCommand()
517 
518 //==============================================================================
519 // checkCommand
520 // when busy for a while, start to sleep
521 // use sleep() or nanosleep()
522 bool Iterator::checkCommand(IteratorWorkLoopStruct* iteratorStruct) try
523 {
524  // for out of range, return done
525  if(iteratorStruct->commandIndex_ >= iteratorStruct->commands_.size())
526  {
527  __COUT__ << "Out of range commandIndex = " << iteratorStruct->commandIndex_ << " in size = " << iteratorStruct->commands_.size() << __E__;
528  return true;
529  }
530 
531  std::string type = iteratorStruct->commands_[iteratorStruct->commandIndex_].type_;
532  if(type == IterateTable::COMMAND_BEGIN_LABEL)
533  {
534  // do nothing
535  return true;
536  }
537  else if(type == IterateTable::COMMAND_CHOOSE_FSM)
538  {
539  // do nothing
540  return true;
541  }
542  else if(type == IterateTable::COMMAND_CONFIGURE_ALIAS || type == IterateTable::COMMAND_CONFIGURE_ACTIVE_GROUP ||
543  type == IterateTable::COMMAND_CONFIGURE_GROUP)
544  {
545  return checkCommandConfigure(iteratorStruct);
546  }
547  else if(type == IterateTable::COMMAND_EXECUTE_FE_MACRO)
548  {
549  return checkCommandMacro(iteratorStruct, true /*isFEMacro*/);
550  }
551  else if(type == IterateTable::COMMAND_EXECUTE_MACRO)
552  {
553  return checkCommandMacro(iteratorStruct, false /*isFEMacro*/);
554  }
555  else if(type == IterateTable::COMMAND_MODIFY_ACTIVE_GROUP)
556  {
557  // do nothing
558  return true;
559  }
560  else if(type == IterateTable::COMMAND_REPEAT_LABEL)
561  {
562  // do nothing
563  return true;
564  }
565  else if(type == IterateTable::COMMAND_RUN)
566  {
567  return checkCommandRun(iteratorStruct);
568  }
569  else
570  {
571  __SS__ << "Attempt to check unrecognized command type = " << type << __E__;
572  __COUT_ERR__ << ss.str();
573  __SS_THROW__;
574  }
575 }
576 catch(...)
577 {
578  __COUT__ << "Error caught. Reverting track changes." << __E__;
579  ConfigurationInterface::setVersionTrackingEnabled(iteratorStruct->originalTrackChanges_);
580 
581  __COUT__ << "Activating original group..." << __E__;
582  try
583  {
584  iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_, iteratorStruct->originalConfigKey_);
585  }
586  catch(...)
587  {
588  __COUT_WARN__ << "Original group could not be activated." << __E__;
589  }
590 
591  throw;
592 } // end checkCommand()
593 
594 //==============================================================================
595 void Iterator::startCommandChooseFSM(IteratorWorkLoopStruct* iteratorStruct, const std::string& fsmName)
596 {
597  __COUT__ << "fsmName " << fsmName << __E__;
598 
599  iteratorStruct->fsmName_ = fsmName;
600  iteratorStruct->theIterator_->lastFsmName_ = fsmName;
601 
602  // Translate fsmName
603  // to gives us run alias (fsmRunAlias_) and next run number (fsmNextRunNumber_)
604 
605  // CAREFUL?? Threads
606 
608 
609  iteratorStruct->fsmRunAlias_ = "Run"; // default to "Run"
610 
611  // get stateMachineAliasFilter if possible
612  ConfigurationTree configLinkNode = iteratorStruct->cfgMgr_->getSupervisorTableNode(iteratorStruct->theIterator_->theSupervisor_->getContextUID(),
613  iteratorStruct->theIterator_->theSupervisor_->getSupervisorUID());
614 
615  if(!configLinkNode.isDisconnected())
616  {
617  try // for backwards compatibility
618  {
619  ConfigurationTree fsmLinkNode = configLinkNode.getNode("LinkToStateMachineTable");
620  if(!fsmLinkNode.isDisconnected())
621  iteratorStruct->fsmRunAlias_ = fsmLinkNode.getNode(fsmName + "/RunDisplayAlias").getValue<std::string>();
622  else
623  __COUT_INFO__ << "FSM Link disconnected." << __E__;
624  }
625  catch(std::runtime_error& e)
626  {
627  //__COUT_INFO__ << e.what() << __E__;
628  __COUT_INFO__ << "No state machine Run alias. Ignoring and assuming alias of '" << iteratorStruct->fsmRunAlias_ << ".'" << __E__;
629  }
630  catch(...)
631  {
632  __COUT_ERR__ << "Unknown error. Should never happen." << __E__;
633 
634  __COUT_INFO__ << "No state machine Run alias. Ignoring and assuming alias of '" << iteratorStruct->fsmRunAlias_ << ".'" << __E__;
635  }
636  }
637  else
638  __COUT_INFO__ << "FSM Link disconnected." << __E__;
639 
640  __COUT__ << "fsmRunAlias_ = " << iteratorStruct->fsmRunAlias_ << __E__;
641 
643 
644  iteratorStruct->fsmNextRunNumber_ = iteratorStruct->theIterator_->theSupervisor_->getNextRunNumber(iteratorStruct->fsmName_);
645 
646  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getCurrentStateName() == "Running" ||
647  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getCurrentStateName() == "Paused")
648  --iteratorStruct->fsmNextRunNumber_; // current run number is one back
649 
650  __COUT__ << "fsmNextRunNumber_ = " << iteratorStruct->fsmNextRunNumber_ << __E__;
651 } // end startCommandChooseFSM()
652 
653 //==============================================================================
654 // return true if an action was attempted
655 bool Iterator::haltIterator(Iterator* iterator, IteratorWorkLoopStruct* iteratorStruct)
656 //(GatewaySupervisor* theSupervisor, const std::string& fsmName)
657 {
658  GatewaySupervisor* theSupervisor = iterator->theSupervisor_;
659  const std::string& fsmName = iterator->lastFsmName_;
660 
661  std::vector<std::string> fsmCommandParameters;
662  std::string errorStr = "";
663  std::string currentState = theSupervisor->theStateMachine_.getCurrentStateName();
664 
665  bool haltAttempted = true;
666  if(currentState == "Initialized" || currentState == "Halted")
667  {
668  __COUT__ << "Do nothing. Already halted." << __E__;
669  haltAttempted = false;
670  }
671  else if(currentState == "Running")
672  errorStr = theSupervisor->attemptStateMachineTransition(
673  0, 0, "Abort", fsmName, WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, WebUsers::DEFAULT_ITERATOR_USERNAME, fsmCommandParameters);
674  else
675  errorStr = theSupervisor->attemptStateMachineTransition(
676  0, 0, "Halt", fsmName, WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, WebUsers::DEFAULT_ITERATOR_USERNAME, fsmCommandParameters);
677 
678  if(haltAttempted)
679  {
680  if(errorStr != "")
681  {
682  __SS__ << "Iterator failed to halt because of the following error: " << errorStr;
683  __SS_THROW__;
684  }
685 
686  // else successfully launched
687  __COUT__ << "FSM in transition = " << theSupervisor->theStateMachine_.isInTransition() << __E__;
688  __COUT__ << "halting state machine launched." << __E__;
689  }
690 
691  // finish up halting the iterator
692  __COUT__ << "Conducting Iterator halt." << __E__;
693 
694  if(iteratorStruct)
695  {
696  __COUT__ << "Reverting track changes." << __E__;
697  ConfigurationInterface::setVersionTrackingEnabled(iteratorStruct->originalTrackChanges_);
698 
699  __COUT__ << "Activating original group..." << __E__;
700  try
701  {
702  iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_, iteratorStruct->originalConfigKey_);
703  }
704  catch(...)
705  {
706  __COUT_WARN__ << "Original group could not be activated." << __E__;
707  }
708  }
709 
710  // lockout the messages array for the remainder of the scope
711  // this guarantees the reading thread can safely access the messages
712  if(iterator->theSupervisor_->VERBOSE_MUTEX)
713  __COUT__ << "Waiting for iterator access" << __E__;
714  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
715  if(iterator->theSupervisor_->VERBOSE_MUTEX)
716  __COUT__ << "Have iterator access" << __E__;
717 
718  iterator->activePlanIsRunning_ = false;
719  iterator->iteratorBusy_ = false;
720 
721  // clear
722  iterator->activePlanName_ = "";
723  iterator->activeCommandIndex_ = -1;
724 
725  if(iteratorStruct)
726  {
727  __COUT__ << "Halted plan '" << iteratorStruct->activePlan_ << "' at command index " << iteratorStruct->commandIndex_ << ". " << __E__;
728  __MOUT__ << "Halted plan '" << iteratorStruct->activePlan_ << "' at command index " << iteratorStruct->commandIndex_ << ". " << __E__;
729 
730  iterator->lastStartedPlanName_ = iteratorStruct->activePlan_;
731  iteratorStruct->activePlan_ = ""; // clear
732  iteratorStruct->commandIndex_ = -1; // clear
733  }
734 
735  return haltAttempted;
736 } // end haltIterator()
737 
738 //==============================================================================
739 void Iterator::startCommandBeginLabel(IteratorWorkLoopStruct* iteratorStruct)
740 {
741  __COUT__ << "Entering label '" << iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandBeginLabelParams_.Label_] << "'..."
742  << std::endl;
743 
744  // add new step index to stack
745  iteratorStruct->stepIndexStack_.push_back(0);
746 } // end startCommandBeginLabel()
747 
748 //==============================================================================
749 void Iterator::startCommandRepeatLabel(IteratorWorkLoopStruct* iteratorStruct)
750 {
751  // search for first matching label backward and set command to there
752 
753  int numOfRepetitions;
754  sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_].c_str(),
755  "%d",
756  &numOfRepetitions);
757  __COUT__ << "numOfRepetitions remaining = " << numOfRepetitions << __E__;
758 
759  char repStr[200];
760 
761  if(numOfRepetitions <= 0)
762  {
763  // write original number of repetitions value back
764  sprintf(repStr, "%d", iteratorStruct->stepIndexStack_.back());
765  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] =
766  repStr; // re-store as string
767 
768  // remove step index from stack
769  iteratorStruct->stepIndexStack_.pop_back();
770 
771  return; // no more repetitions
772  }
773 
774  --numOfRepetitions;
775 
776  // increment step index in stack
777  ++(iteratorStruct->stepIndexStack_.back());
778 
779  unsigned int i;
780  for(i = iteratorStruct->commandIndex_; i > 0; --i) // assume 0 is always the fallback option
781  if(iteratorStruct->commands_[i].type_ == IterateTable::COMMAND_BEGIN_LABEL &&
782  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRepeatLabelParams_.Label_] ==
783  iteratorStruct->commands_[i].params_[IterateTable::commandBeginLabelParams_.Label_])
784  break;
785 
786  sprintf(repStr, "%d", numOfRepetitions);
787  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] =
788  repStr; // re-store as string
789 
790  iteratorStruct->commandIndex_ = i;
791  __COUT__ << "Jumping back to commandIndex " << iteratorStruct->commandIndex_ << __E__;
792 } // end startCommandRepeatLabel()
793 
794 //==============================================================================
795 void Iterator::startCommandRun(IteratorWorkLoopStruct* iteratorStruct)
796 {
797  iteratorStruct->runIsDone_ = false;
798  iteratorStruct->fsmCommandParameters_.clear();
799 
800  std::string errorStr = "";
801  std::string currentState = iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getCurrentStateName();
802 
803  // execute first transition (may need two)
804 
805  if(currentState == "Configured")
806  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
807  0,
808  "Start",
809  iteratorStruct->fsmName_,
810  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
811  WebUsers::DEFAULT_ITERATOR_USERNAME,
812  iteratorStruct->fsmCommandParameters_);
813  else
814  errorStr = "Can only Run from the Configured state. The current state is " + currentState;
815 
816  if(errorStr != "")
817  {
818  __SS__ << "Iterator failed to run because of the following error: " << errorStr;
819  __SS_THROW__;
820  }
821 
822  // save original duration
823  sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRunParams_.DurationInSeconds_].c_str(),
824  "%ld",
825  &iteratorStruct->originalDurationInSeconds_);
826  __COUTV__(iteratorStruct->originalDurationInSeconds_);
827 
828  // else successfully launched
829  __COUT__ << "FSM in transition = " << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition() << __E__;
830  __COUT__ << "startCommandRun success." << __E__;
831 } // end startCommandRun()
832 
833 //==============================================================================
834 void Iterator::startCommandConfigureActive(IteratorWorkLoopStruct* iteratorStruct)
835 {
836  __COUT__ << "startCommandConfigureActive " << __E__;
837 
838  // steps:
839  // get active config group
840  // transition to configure with parameters describing group
841 
842  std::string group = iteratorStruct->cfgMgr_->getActiveGroupName();
843  TableGroupKey key = iteratorStruct->cfgMgr_->getActiveGroupKey();
844 
845  __COUT__ << "group " << group << __E__;
846  __COUT__ << "key " << key << __E__;
847 
848  // create special alias for this group using : separators
849 
850  std::stringstream systemAlias;
851  systemAlias << "GROUP:" << group << ":" << key;
852  startCommandConfigureAlias(iteratorStruct, systemAlias.str());
853 } // end startCommandConfigureActive()
854 
855 //==============================================================================
856 void Iterator::startCommandConfigureGroup(IteratorWorkLoopStruct* iteratorStruct)
857 {
858  __COUT__ << "startCommandConfigureGroup " << __E__;
859 
860  // steps:
861  // transition to configure with parameters describing group
862 
863  std::string group = iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandConfigureGroupParams_.GroupName_];
864  TableGroupKey key = TableGroupKey(iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandConfigureGroupParams_.GroupKey_]);
865 
866  __COUT__ << "group " << group << __E__;
867  __COUT__ << "key " << key << __E__;
868 
869  // create special alias for this group using : separators
870 
871  std::stringstream systemAlias;
872  systemAlias << "GROUP:" << group << ":" << key;
873  startCommandConfigureAlias(iteratorStruct, systemAlias.str());
874 } // end startCommandConfigureGroup()
875 
876 //==============================================================================
877 void Iterator::startCommandConfigureAlias(IteratorWorkLoopStruct* iteratorStruct, const std::string& systemAlias)
878 {
879  __COUT__ << "systemAlias " << systemAlias << __E__;
880 
881  iteratorStruct->fsmCommandParameters_.clear();
882  iteratorStruct->fsmCommandParameters_.push_back(systemAlias);
883 
884  std::string errorStr = "";
885  std::string currentState = iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getCurrentStateName();
886 
887  // execute first transition (may need two in conjunction with checkCommandConfigure())
888 
889  if(currentState == "Initial")
890  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
891  0,
892  "Initialize",
893  iteratorStruct->fsmName_,
894  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
895  WebUsers::DEFAULT_ITERATOR_USERNAME,
896  iteratorStruct->fsmCommandParameters_);
897  else if(currentState == "Halted")
898  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
899  0,
900  "Configure",
901  iteratorStruct->fsmName_,
902  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
903  WebUsers::DEFAULT_ITERATOR_USERNAME,
904  iteratorStruct->fsmCommandParameters_);
905  else if(currentState == "Configured")
906  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
907  0,
908  "Halt",
909  iteratorStruct->fsmName_,
910  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
911  WebUsers::DEFAULT_ITERATOR_USERNAME,
912  iteratorStruct->fsmCommandParameters_);
913  else
914  errorStr = "Can only Configure from the Initial or Halted state. The current state is " + currentState;
915 
916  if(errorStr != "")
917  {
918  __SS__ << "Iterator failed to configure with system alias '"
919  << (iteratorStruct->fsmCommandParameters_.size() ? iteratorStruct->fsmCommandParameters_[0] : "UNKNOWN")
920  << "' because of the following error: " << errorStr;
921  __SS_THROW__;
922  }
923 
924  // else successfully launched
925  __COUT__ << "FSM in transition = " << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition() << __E__;
926  __COUT__ << "startCommandConfigureAlias success." << __E__;
927 } // end startCommandConfigureAlias()
928 
929 //==============================================================================
930 void Iterator::startCommandMacro(IteratorWorkLoopStruct* iteratorStruct, bool isFrontEndMacro)
931 {
932  // Steps:
933  // 4 parameters CommandExecuteFEMacroParams:
934  // //targets
935  // const std::string FEMacroName_ = "FEMacroName";
936  // //macro parameters (table/groupID)
937 
938  const std::string& macroName = iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandExecuteMacroParams_.MacroName_];
939  const std::string& enableSavingOutput =
940  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandExecuteMacroParams_.EnableSavingOutput_];
941  const std::string& outputFilePath =
942  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandExecuteMacroParams_.OutputFilePath_];
943  const std::string& outputFileRadix =
944  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandExecuteMacroParams_.OutputFileRadix_];
945  const std::string& inputArgs =
946  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandExecuteMacroParams_.MacroArgumentString_];
947 
948  __COUTV__(macroName);
949  __COUTV__(enableSavingOutput);
950  __COUTV__(outputFilePath);
951  __COUTV__(outputFileRadix);
952  __COUTV__(inputArgs);
953 
954  // send request to MacroMaker a la FEVInterface::runFrontEndMacro
955  // but need to pass iteration information, so that the call is launched by just one
956  // send to each front end. Front-ends must immediately respond that is started
957  // FEVInterfacesManager.. must start a thread for running the macro iterations
958  // Then check for complete.
959 
960  iteratorStruct->targetsDone_.clear(); // reset
961 
962  __COUTV__(iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.size());
963  for(const auto& target : iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_)
964  {
965  __COUT__ << "target " << target.table_ << ":" << target.UID_ << __E__;
966 
967  // for each target, init to not done
968  iteratorStruct->targetsDone_.push_back(false);
969 
970  xoap::MessageReference message = SOAPUtilities::makeSOAPMessageReference("FECommunication");
971 
972  SOAPParameters parameters;
973  std::string type = isFrontEndMacro ? "feMacroMultiDimensionalStart" : "macroMultiDimensionalStart";
974  parameters.addParameter("type", type);
975  parameters.addParameter("requester", WebUsers::DEFAULT_ITERATOR_USERNAME);
976  parameters.addParameter("targetInterfaceID", target.UID_);
977  parameters.addParameter(isFrontEndMacro ? "feMacroName" : "macroName", macroName);
978  parameters.addParameter("enableSavingOutput", enableSavingOutput);
979  parameters.addParameter("outputFilePath", outputFilePath);
980  parameters.addParameter("outputFileRadix", outputFileRadix);
981  parameters.addParameter("inputArgs", inputArgs);
982  SOAPUtilities::addParameters(message, parameters);
983 
984  __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message) << __E__;
985 
986  xoap::MessageReference replyMessage = iteratorStruct->theIterator_->theSupervisor_->SOAPMessenger::sendWithSOAPReply(
987  iteratorStruct->theIterator_->theSupervisor_->allSupervisorInfo_.getAllMacroMakerTypeSupervisorInfo().begin()->second.getDescriptor(), message);
988 
989  __COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage) << __E__;
990 
991  SOAPParameters rxParameters;
992  rxParameters.addParameter("Error");
993  std::string response = SOAPUtilities::receive(replyMessage, rxParameters);
994 
995  std::string error = rxParameters.getValue("Error");
996 
997  if(response != type + "Done" || error != "")
998  {
999  // error occurred!
1000  __SS__ << "Error transmitting request to target interface '" << target.UID_ << "' from '" << WebUsers::DEFAULT_ITERATOR_USERNAME << ".' Response '"
1001  << response << "' with error: " << error << __E__;
1002  __SS_THROW__;
1003  }
1004  } // end target loop
1005 
1006 } // end startCommandMacro()
1007 
1008 //==============================================================================
1009 bool Iterator::checkCommandMacro(IteratorWorkLoopStruct* iteratorStruct, bool isFrontEndMacro)
1010 {
1011  sleep(1);
1012 
1013  // Steps:
1014  // 4 parameters CommandExecuteFEMacroParams:
1015  // //targets
1016  // const std::string FEMacroName_ = "FEMacroName";
1017  // //macro parameters (table/groupID)
1018 
1019  const std::string& macroName = iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandExecuteMacroParams_.MacroName_];
1020 
1021  __COUTV__(macroName);
1022 
1023  // send request to MacroMaker to check completion of macro
1024  // as targets are identified complete, remove targets_ from vector
1025 
1026  for(unsigned int i = 0; i < iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.size(); ++i)
1027  {
1028  ots::IterateTable::CommandTarget& target = iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_[i];
1029 
1030  __COUT__ << "target " << target.table_ << ":" << target.UID_ << __E__;
1031 
1032  xoap::MessageReference message = SOAPUtilities::makeSOAPMessageReference("FECommunication");
1033 
1034  SOAPParameters parameters;
1035  std::string type = isFrontEndMacro ? "feMacroMultiDimensionalCheck" : "macroMultiDimensionalCheck";
1036  parameters.addParameter("type", type);
1037  parameters.addParameter("requester", WebUsers::DEFAULT_ITERATOR_USERNAME);
1038  parameters.addParameter("targetInterfaceID", target.UID_);
1039  parameters.addParameter(isFrontEndMacro ? "feMacroName" : "macroName", macroName);
1040  SOAPUtilities::addParameters(message, parameters);
1041 
1042  __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message) << __E__;
1043 
1044  xoap::MessageReference replyMessage = iteratorStruct->theIterator_->theSupervisor_->SOAPMessenger::sendWithSOAPReply(
1045  iteratorStruct->theIterator_->theSupervisor_->allSupervisorInfo_.getAllMacroMakerTypeSupervisorInfo().begin()->second.getDescriptor(), message);
1046 
1047  __COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage) << __E__;
1048 
1049  SOAPParameters rxParameters;
1050  rxParameters.addParameter("Error");
1051  rxParameters.addParameter("Done");
1052  std::string response = SOAPUtilities::receive(replyMessage, rxParameters);
1053 
1054  std::string error = rxParameters.getValue("Error");
1055  bool done = rxParameters.getValue("Done") == "1";
1056 
1057  if(response != type + "Done" || error != "")
1058  {
1059  // error occurred!
1060  __SS__ << "Error transmitting request to target interface '" << target.UID_ << "' from '" << WebUsers::DEFAULT_ITERATOR_USERNAME << ".' Response '"
1061  << response << "' with error: " << error << __E__;
1062  __SS_THROW__;
1063  }
1064 
1065  if(!done) // still more to do so give up checking
1066  return false;
1067 
1068  // mark target done
1069  iteratorStruct->targetsDone_[i] = true;
1070 
1071  // iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.erase(
1072  // targetIt--); //go back after delete
1073 
1074  } // end target loop
1075 
1076  // if here all targets are done
1077  return true;
1078 } // end checkCommandMacro()
1079 
1080 //==============================================================================
1081 void Iterator::startCommandModifyActive(IteratorWorkLoopStruct* iteratorStruct)
1082 {
1083  // Steps:
1084  // 4 parameters commandModifyActiveParams_:
1085  // const std::string DoTrackGroupChanges_ TrueFalse
1086  // //targets
1087  // const std::string RelativePathToField_ = "RelativePathToField";
1088  // const std::string FieldStartValue_ = "FieldStartValue";
1089  // const std::string FieldIterationStepSize_ = "FieldIterationStepSize";
1090  //
1091  // if tracking changes,
1092  // create a new group
1093  // for every enabled FE
1094  // set field = start value + stepSize * currentStepIndex_
1095  // activate group
1096  // else
1097  // load scratch group
1098  // for every enabled FE
1099  // set field = start value + stepSize * stepIndex
1100  // activate group
1101 
1102  bool doTrackGroupChanges = false;
1103  if("True" == iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandModifyActiveParams_.DoTrackGroupChanges_])
1104  doTrackGroupChanges = true;
1105 
1106  const std::string& startValueStr =
1107  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandModifyActiveParams_.FieldStartValue_];
1108  const std::string& stepSizeStr =
1109  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandModifyActiveParams_.FieldIterationStepSize_];
1110 
1111  const unsigned int stepIndex = iteratorStruct->stepIndexStack_.back();
1112 
1113  __COUT__ << "doTrackGroupChanges " << (doTrackGroupChanges ? "yes" : "no") << std::endl;
1114  __COUT__ << "stepIndex " << stepIndex << std::endl;
1115 
1116  ConfigurationInterface::setVersionTrackingEnabled(doTrackGroupChanges);
1117 
1118  // two approaches: double or long handling
1119 
1120  if(startValueStr.size() && (startValueStr[startValueStr.size() - 1] == 'f' || startValueStr.find('.') != std::string::npos))
1121  {
1122  // handle as double
1123  double startValue = strtod(startValueStr.c_str(), 0);
1124  double stepSize = strtod(stepSizeStr.c_str(), 0);
1125 
1126  __COUT__ << "startValue " << startValue << std::endl;
1127  __COUT__ << "stepSize " << stepSize << std::endl;
1128  __COUT__ << "currentValue " << startValue + stepSize * stepIndex << std::endl;
1129 
1130  helpCommandModifyActive(iteratorStruct, startValue + stepSize * stepIndex, doTrackGroupChanges);
1131  }
1132  else // handle as long
1133  {
1134  long int startValue;
1135  long int stepSize;
1136 
1137  StringMacros::getNumber(startValueStr, startValue);
1138  StringMacros::getNumber(startValueStr, stepSize);
1139 
1140  // long int startValue;
1141  //
1142  // if(startValueStr.size() > 2 && startValueStr[1] == 'x') //assume hex value
1143  // startValue = strtol(startValueStr.c_str(),0,16);
1144  // else if(startValueStr.size() > 1 && startValueStr[0] == 'b') //assume
1145  // binary value startValue =
1146  // strtol(startValueStr.substr(1).c_str(),0,2);
1148  // strtol(startValueStr.c_str(),0,10);
1149  //
1150  // long int stepSize;
1151  //
1152  // if(stepSizeStr.size() > 2 && stepSizeStr[1] == 'x') //assume hex value
1153  // stepSize = strtol(stepSizeStr.c_str(),0,16);
1154  // else if(stepSizeStr.size() > 1 && stepSizeStr[0] == 'b') //assume binary
1155  // value stepSize = strtol(stepSizeStr.substr(1).c_str(),0,2); //skip
1156  // first 'b' character else stepSize =
1157  // strtol(stepSizeStr.c_str(),0,10);
1158 
1159  __COUT__ << "startValue " << startValue << std::endl;
1160  __COUT__ << "stepSize " << stepSize << std::endl;
1161  __COUT__ << "currentValue " << startValue + stepSize * stepIndex << std::endl;
1162 
1163  helpCommandModifyActive(iteratorStruct, startValue + stepSize * stepIndex, doTrackGroupChanges);
1164  }
1165 
1166 } // end startCommandModifyActive()
1167 
1168 //==============================================================================
1169 // checkCommandRun
1170 // return true if done
1171 //
1172 // Either will be done on (priority 1) running threads (for Frontends) ending
1173 // or (priority 2 and ignored if <= 0) duration timeout
1174 //
1175 // Note: use command structure strings to maintain duration left
1176 // Note: watch iterator->doPauseAction and iterator->doHaltAction and respond
1177 bool Iterator::checkCommandRun(IteratorWorkLoopStruct* iteratorStruct)
1178 {
1179  sleep(1); // sleep to give FSM time to transition
1180 
1181  // all RunControlStateMachine access commands should be mutually exclusive with
1182  // GatewaySupervisor main thread state machine accesses should be mutually exclusive
1183  // with GatewaySupervisor main thread state machine accesses lockout the messages
1184  // array for the remainder of the scope this guarantees the reading thread can safely
1185  // access the messages
1186  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1187  __COUT__ << "Waiting for FSM access" << __E__;
1188  std::lock_guard<std::mutex> lock(iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
1189  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1190  __COUT__ << "Have FSM access" << __E__;
1191 
1192  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition())
1193  return false;
1194 
1195  iteratorStruct->fsmCommandParameters_.clear();
1196 
1197  std::string errorStr = "";
1198  std::string currentState = iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getCurrentStateName();
1199 
1201  // check for imposed actions and forced exits
1202  if(iteratorStruct->doPauseAction_)
1203  {
1204  // transition to pause state
1205  __COUT__ << "Transitioning FSM to Paused..." << __E__;
1206 
1207  if(currentState == "Paused")
1208  {
1209  // done with early pause exit!
1210  __COUT__ << "Transition to Paused complete." << __E__;
1211  return true;
1212  }
1213  else if(currentState == "Running") // launch transition to pause
1214  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1215  0,
1216  "Pause",
1217  iteratorStruct->fsmName_,
1218  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1219  WebUsers::DEFAULT_ITERATOR_USERNAME,
1220  iteratorStruct->fsmCommandParameters_);
1221  else if(currentState == "Configured")
1222  {
1223  // no need to pause state machine, no run going on
1224  __COUT__ << "In Configured state. No need to transition to Paused." << __E__;
1225  return true;
1226  }
1227  else
1228  errorStr = "Expected to be in Paused. Unexpectedly, the current state is " + currentState +
1229  ". Last State Machine error message was as follows: " + iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getErrorMessage();
1230 
1231  if(errorStr != "")
1232  {
1233  __SS__ << "Iterator failed to pause because of the following error: " << errorStr;
1234  __SS_THROW__;
1235  }
1236  return false;
1237  }
1238  else if(iteratorStruct->doHaltAction_)
1239  {
1240  // transition to halted state
1241  __COUT__ << "Transitioning FSM to Halted..." << __E__;
1242 
1243  if(currentState == "Halted")
1244  {
1245  // done with early halt exit!
1246  __COUT__ << "Transition to Halted complete." << __E__;
1247  return true;
1248  }
1249  else if(currentState == "Running" || // launch transition to halt
1250  currentState == "Paused")
1251  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1252  0,
1253  "Abort",
1254  iteratorStruct->fsmName_,
1255  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1256  WebUsers::DEFAULT_ITERATOR_USERNAME,
1257  iteratorStruct->fsmCommandParameters_);
1258  else if(currentState == "Configured") // launch transition to halt
1259  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1260  0,
1261  "Halt",
1262  iteratorStruct->fsmName_,
1263  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1264  WebUsers::DEFAULT_ITERATOR_USERNAME,
1265  iteratorStruct->fsmCommandParameters_);
1266  else
1267  errorStr = "Expected to be in Halted. Unexpectedly, the current state is " + currentState +
1268  ". Last State Machine error message was as follows: " + iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getErrorMessage();
1269 
1270  if(errorStr != "")
1271  {
1272  __SS__ << "Iterator failed to halt because of the following error: " << errorStr;
1273  __SS_THROW__;
1274  }
1275  return false;
1276  }
1277  else if(iteratorStruct->doResumeAction_)
1278  {
1279  // Note: check command gets one shot to resume
1280 
1281  // transition to running state
1282  __COUT__ << "Transitioning FSM to Running..." << __E__;
1283 
1284  if(currentState == "Paused") // launch transition to running
1285  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1286  0,
1287  "Resume",
1288  iteratorStruct->fsmName_,
1289  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1290  WebUsers::DEFAULT_ITERATOR_USERNAME,
1291  iteratorStruct->fsmCommandParameters_);
1292 
1293  if(errorStr != "")
1294  {
1295  __SS__ << "Iterator failed to run because of the following error: " << errorStr;
1296  __SS_THROW__;
1297  }
1298  return false;
1299  }
1300 
1302  // normal running
1303 
1304  if(currentState != "Running")
1305  {
1306  if(iteratorStruct->runIsDone_ && currentState == "Configured")
1307  {
1308  // indication of done
1309  __COUT__ << "Reached end of run " << iteratorStruct->fsmNextRunNumber_ << __E__;
1310  return true;
1311  }
1312 
1313  errorStr = "Expected to be in Running. Unexpectedly, the current state is " + currentState +
1314  ". Last State Machine error message was as follows: " + iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getErrorMessage();
1315  }
1316  else // else in Running state! Check for end of run
1317  {
1318  bool waitOnRunningThreads = false;
1319  if("True" == iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRunParams_.WaitOnRunningThreads_])
1320  waitOnRunningThreads = true;
1321 
1322  time_t remainingDurationInSeconds;
1323  sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRunParams_.DurationInSeconds_].c_str(),
1324  "%ld",
1325  &remainingDurationInSeconds);
1326 
1327  __COUT__ << "waitOnRunningThreads " << waitOnRunningThreads << __E__;
1328  __COUT__ << "remainingDurationInSeconds " << remainingDurationInSeconds << __E__;
1329 
1331  // priority 1 is waiting on running threads
1332  if(waitOnRunningThreads)
1333  {
1334  // get status of all running FE workloops
1335  GatewaySupervisor* theSupervisor = iteratorStruct->theIterator_->theSupervisor_;
1336 
1337  bool allFrontEndsAreDone = true;
1338  for(auto& it : theSupervisor->allSupervisorInfo_.getAllFETypeSupervisorInfo())
1339  {
1340  try
1341  {
1342  std::string status = theSupervisor->send(it.second.getDescriptor(), "WorkLoopStatusRequest");
1343 
1344  __COUT__ << "FESupervisor instance " << it.first << " has status = " << status << std::endl;
1345 
1346  if(status != CoreSupervisorBase::WORK_LOOP_DONE)
1347  {
1348  allFrontEndsAreDone = false;
1349  break;
1350  }
1351  }
1352  catch(xdaq::exception::Exception& e)
1353  {
1354  __SS__ << "Could not retrieve status from FESupervisor instance " << it.first << "." << std::endl;
1355  __COUT_WARN__ << ss.str();
1356  errorStr = ss.str();
1357 
1358  if(errorStr != "")
1359  {
1360  __SS__ << "Iterator failed to run because of the following error: " << errorStr;
1361  __SS_THROW__;
1362  }
1363  }
1364  }
1365 
1366  if(allFrontEndsAreDone)
1367  {
1368  // need to end run!
1369  __COUT__ << "FE workloops all complete! Stopping run..." << __E__;
1370 
1371  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1372  0,
1373  "Stop",
1374  iteratorStruct->fsmName_,
1375  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1376  WebUsers::DEFAULT_ITERATOR_USERNAME,
1377  iteratorStruct->fsmCommandParameters_);
1378 
1379  if(errorStr != "")
1380  {
1381  __SS__ << "Iterator failed to stop run because of the following error: " << errorStr;
1382  __SS_THROW__;
1383  }
1384 
1385  // write indication of run done into duration
1386  iteratorStruct->runIsDone_ = true;
1387 
1388  return false;
1389  }
1390  }
1391 
1393  // priority 2 is duration, if <= 0 it is ignored
1394  if(remainingDurationInSeconds > 1)
1395  {
1396  --remainingDurationInSeconds;
1397 
1398  // write back to string
1399  char str[200];
1400  sprintf(str, "%ld", remainingDurationInSeconds);
1401  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRunParams_.DurationInSeconds_] = str; // re-store as string
1402  }
1403  else if(remainingDurationInSeconds == 1)
1404  {
1405  // need to end run!
1406  __COUT__ << "Time duration reached! Stopping run..." << __E__;
1407 
1408  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1409  0,
1410  "Stop",
1411  iteratorStruct->fsmName_,
1412  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1413  WebUsers::DEFAULT_ITERATOR_USERNAME,
1414  iteratorStruct->fsmCommandParameters_);
1415 
1416  if(errorStr != "")
1417  {
1418  __SS__ << "Iterator failed to stop run because of the following error: " << errorStr;
1419  __SS_THROW__;
1420  }
1421 
1422  // write indication of run done
1423  iteratorStruct->runIsDone_ = true;
1424 
1425  // write original duration back to string
1426  char str[200];
1427  sprintf(str, "%ld", iteratorStruct->originalDurationInSeconds_);
1428  iteratorStruct->commands_[iteratorStruct->commandIndex_].params_[IterateTable::commandRunParams_.DurationInSeconds_] = str; // re-store as string
1429  return false;
1430  }
1431  }
1432 
1433  if(errorStr != "")
1434  {
1435  __SS__ << "Iterator failed to run because of the following error: " << errorStr;
1436  __SS_THROW__;
1437  }
1438  return false;
1439 } // end checkCommandRun()
1440 
1441 //==============================================================================
1442 // return true if done
1443 bool Iterator::checkCommandConfigure(IteratorWorkLoopStruct* iteratorStruct)
1444 {
1445  sleep(1); // sleep to give FSM time to transition
1446 
1447  // all RunControlStateMachine access commands should be mutually exclusive with
1448  // GatewaySupervisor main thread state machine accesses should be mutually exclusive
1449  // with GatewaySupervisor main thread state machine accesses lockout the messages
1450  // array for the remainder of the scope this guarantees the reading thread can safely
1451  // access the messages
1452  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1453  __COUT__ << "Waiting for FSM access" << __E__;
1454  std::lock_guard<std::mutex> lock(iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
1455  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1456  __COUT__ << "Have FSM access" << __E__;
1457 
1458  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition())
1459  return false;
1460 
1461  std::string errorStr = "";
1462  std::string currentState = iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getCurrentStateName();
1463 
1464  if(currentState == "Halted")
1465  errorStr = iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(0,
1466  0,
1467  "Configure",
1468  iteratorStruct->fsmName_,
1469  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1470  WebUsers::DEFAULT_ITERATOR_USERNAME,
1471  iteratorStruct->fsmCommandParameters_);
1472  else if(currentState != "Configured")
1473  errorStr = "Expected to be in Configure. Unexpectedly, the current state is " + currentState + "." +
1474  ". Last State Machine error message was as follows: " + iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.getErrorMessage();
1475  else // else successfully done (in Configured state!)
1476  {
1477  __COUT__ << "checkCommandConfigureAlias complete." << __E__;
1478 
1479  // also activate the Iterator config manager to mimic active config
1480  std::pair<std::string, TableGroupKey> newActiveGroup = iteratorStruct->cfgMgr_->getTableGroupFromAlias(iteratorStruct->fsmCommandParameters_[0]);
1481  iteratorStruct->cfgMgr_->loadTableGroup(newActiveGroup.first, newActiveGroup.second, true /*activate*/);
1482 
1483  __COUT__ << "originalTrackChanges " << iteratorStruct->originalTrackChanges_ << __E__;
1484  __COUT__ << "originalConfigGroup " << iteratorStruct->originalConfigGroup_ << __E__;
1485  __COUT__ << "originalConfigKey " << iteratorStruct->originalConfigKey_ << __E__;
1486 
1487  __COUT__ << "currentTrackChanges " << ConfigurationInterface::isVersionTrackingEnabled() << __E__;
1488  __COUT__ << "originalConfigGroup " << iteratorStruct->cfgMgr_->getActiveGroupName() << __E__;
1489  __COUT__ << "originalConfigKey " << iteratorStruct->cfgMgr_->getActiveGroupKey() << __E__;
1490 
1491  return true;
1492  }
1493 
1494  if(errorStr != "")
1495  {
1496  __SS__ << "Iterator failed to configure with system alias '"
1497  << (iteratorStruct->fsmCommandParameters_.size() ? iteratorStruct->fsmCommandParameters_[0] : "UNKNOWN")
1498  << "' because of the following error: " << errorStr;
1499  __SS_THROW__;
1500  }
1501  return false;
1502 }
1503 
1504 //==============================================================================
1505 bool Iterator::handleCommandRequest(HttpXmlDocument& xmldoc, const std::string& command, const std::string& parameter)
1506 {
1507  //__COUTV__(command);
1508  if(command == "iteratePlay")
1509  {
1510  playIterationPlan(xmldoc, parameter);
1511  return true;
1512  }
1513  else if(command == "iteratePause")
1514  {
1515  pauseIterationPlan(xmldoc);
1516  return true;
1517  }
1518  else if(command == "iterateHalt")
1519  {
1520  haltIterationPlan(xmldoc);
1521  return true;
1522  }
1523  else if(command == "getIterationPlanStatus")
1524  {
1525  getIterationPlanStatus(xmldoc);
1526  return true;
1527  }
1528  else // return true if iterator has control of state machine
1529  {
1530  // lockout the messages array for the remainder of the scope
1531  // this guarantees the reading thread can safely access the messages
1532  if(theSupervisor_->VERBOSE_MUTEX)
1533  __COUT__ << "Waiting for iterator access" << __E__;
1534  std::lock_guard<std::mutex> lock(accessMutex_);
1535  if(theSupervisor_->VERBOSE_MUTEX)
1536  __COUT__ << "Have iterator access" << __E__;
1537 
1538  if(iteratorBusy_)
1539  {
1540  __SS__ << "Error - Can not accept request because the Iterator "
1541  << "is currently "
1542  << "in control of State Machine progress. ";
1543  __COUT_ERR__ << "\n" << ss.str();
1544  __MOUT_ERR__ << "\n" << ss.str();
1545 
1546  xmldoc.addTextElementToData("state_tranisition_attempted",
1547  "0"); // indicate to GUI transition NOT attempted
1548  xmldoc.addTextElementToData("state_tranisition_attempted_err",
1549  ss.str()); // indicate to GUI transition NOT attempted
1550 
1551  return true; // to block other commands
1552  }
1553  }
1554  return false;
1555 }
1556 
1557 //==============================================================================
1558 void Iterator::playIterationPlan(HttpXmlDocument& xmldoc, const std::string& planName)
1559 {
1560  __MOUT__ << "Attempting to play iteration plan '" << planName << ".'" << __E__;
1561  __COUT__ << "Attempting to play iteration plan '" << planName << ".'" << __E__;
1562 
1563  // setup "play" command
1564 
1565  // lockout the messages array for the remainder of the scope
1566  // this guarantees the reading thread can safely access the messages
1567  if(theSupervisor_->VERBOSE_MUTEX)
1568  __COUT__ << "Waiting for iterator access" << __E__;
1569  std::lock_guard<std::mutex> lock(accessMutex_);
1570  if(theSupervisor_->VERBOSE_MUTEX)
1571  __COUT__ << "Have iterator access" << __E__;
1572 
1573  if(!activePlanIsRunning_ && !commandPlay_)
1574  {
1575  if(!workloopRunning_)
1576  {
1577  // start thread with member variables initialized
1578 
1579  workloopRunning_ = true;
1580 
1581  // must start thread first
1582  std::thread([](Iterator* iterator) { Iterator::IteratorWorkLoop(iterator); }, this).detach();
1583  }
1584 
1585  activePlanName_ = planName;
1586  commandPlay_ = true;
1587  }
1588  else
1589  {
1590  __SS__ << "Invalid play command attempted. Can only play when the Iterator is "
1591  "inactive or paused."
1592  << " If you would like to restart an iteration plan, first try halting." << __E__;
1593  __MOUT__ << ss.str();
1594 
1595  xmldoc.addTextElementToData("error_message", ss.str());
1596 
1597  __COUT__ << "Invalid play command attempted. " << commandPlay_ << " " << activePlanName_ << __E__;
1598  }
1599 }
1600 
1601 //==============================================================================
1602 void Iterator::pauseIterationPlan(HttpXmlDocument& xmldoc)
1603 {
1604  __MOUT__ << "Attempting to pause iteration plan '" << activePlanName_ << ".'" << __E__;
1605  __COUT__ << "Attempting to pause iteration plan '" << activePlanName_ << ".'" << __E__;
1606 
1607  // setup "pause" command
1608 
1609  // lockout the messages array for the remainder of the scope
1610  // this guarantees the reading thread can safely access the messages
1611  if(theSupervisor_->VERBOSE_MUTEX)
1612  __COUT__ << "Waiting for iterator access" << __E__;
1613  std::lock_guard<std::mutex> lock(accessMutex_);
1614  if(theSupervisor_->VERBOSE_MUTEX)
1615  __COUT__ << "Have iterator access" << __E__;
1616 
1617  if(workloopRunning_ && activePlanIsRunning_ && !commandPause_)
1618  {
1619  commandPause_ = true;
1620  }
1621  else
1622  {
1623  __SS__ << "Invalid pause command attempted. Can only pause when running." << __E__;
1624  __MOUT__ << ss.str();
1625 
1626  xmldoc.addTextElementToData("error_message", ss.str());
1627 
1628  __COUT__ << "Invalid pause command attempted. " << workloopRunning_ << " " << activePlanIsRunning_ << " " << commandPause_ << " " << activePlanName_
1629  << __E__;
1630  }
1631 }
1632 
1633 //==============================================================================
1634 void Iterator::haltIterationPlan(HttpXmlDocument& /*xmldoc*/)
1635 {
1636  __MOUT__ << "Attempting to halt iteration plan '" << activePlanName_ << ".'" << __E__;
1637  __COUT__ << "Attempting to halt iteration plan '" << activePlanName_ << ".'" << __E__;
1638 
1639  // setup "halt" command
1640 
1641  if(workloopRunning_)
1642  {
1643  // lockout the messages array for the remainder of the scope
1644  // this guarantees the reading thread can safely access the messages
1645  if(theSupervisor_->VERBOSE_MUTEX)
1646  __COUT__ << "Waiting for iterator access" << __E__;
1647  std::lock_guard<std::mutex> lock(accessMutex_);
1648  if(theSupervisor_->VERBOSE_MUTEX)
1649  __COUT__ << "Have iterator access" << __E__;
1650 
1651  __COUT__ << "activePlanIsRunning_: " << activePlanIsRunning_ << __E__;
1652  __COUT__ << "Passing halt command to iterator thread." << __E__;
1653  commandHalt_ = true;
1654 
1655  // clear
1656  activePlanName_ = "";
1657  activeCommandIndex_ = -1;
1658  }
1659  else // no thread, so halt (and reset Error') without command to thread
1660  {
1661  __COUT__ << "No thread, so conducting halt." << __E__;
1662  Iterator::haltIterator(this);
1663  //
1664  // activePlanIsRunning_ = false;
1665  // iteratorBusy_ = false;
1666  //
1667  // bool haltAttempted = false;
1668  // try
1669  // {
1670  // haltAttempted = Iterator::haltIterator(theSupervisor_, lastFsmName_);
1671  // }
1672  // catch(const std::runtime_error& e)
1673  // {
1674  // haltAttempted = false;
1675  // __COUT__ << "Halt error: " << e.what() << __E__;
1676  // }
1677  //
1678  // if(!haltAttempted) //then show error
1679  // {
1680  // __SS__ << "Invalid halt command attempted. Can only halt when there is
1681  // an active iteration plan." << __E__;
1682  // __MOUT_ERR__ << ss.str();
1683  //
1684  // xmldoc.addTextElementToData("error_message", ss.str());
1685  //
1686  // __COUT__ << "Invalid halt command attempted. " <<
1687  // workloopRunning_ << " " <<
1688  // activePlanIsRunning_ << " " <<
1689  // commandHalt_ << " " <<
1690  // activePlanName_ << __E__;
1691  // }
1692  // else
1693  // __COUT__ << "Halt was attempted." << __E__;
1694  }
1695 }
1696 
1697 //==============================================================================
1698 // return state machine and iterator status
1699 void Iterator::getIterationPlanStatus(HttpXmlDocument& xmldoc)
1700 {
1701  xmldoc.addTextElementToData("current_state",
1702  theSupervisor_->theStateMachine_.isInTransition()
1703  ? theSupervisor_->theStateMachine_.getCurrentTransitionName(theSupervisor_->stateMachineLastCommandInput_)
1704  : theSupervisor_->theStateMachine_.getCurrentStateName());
1705 
1706  // xmldoc.addTextElementToData("in_transition",
1707  // theSupervisor_->theStateMachine_.isInTransition() ? "1" : "0");
1708  if(theSupervisor_->theStateMachine_.isInTransition())
1709  xmldoc.addTextElementToData("transition_progress", theSupervisor_->theProgressBar_.readPercentageString());
1710  else
1711  xmldoc.addTextElementToData("transition_progress", "100");
1712 
1713  char tmp[20];
1714  sprintf(tmp, "%lu", theSupervisor_->theStateMachine_.getTimeInState());
1715  xmldoc.addTextElementToData("time_in_state", tmp);
1716 
1717  // lockout the messages array for the remainder of the scope
1718  // this guarantees the reading thread can safely access the messages
1719  if(theSupervisor_->VERBOSE_MUTEX)
1720  __COUT__ << "Waiting for iterator access" << __E__;
1721  std::lock_guard<std::mutex> lock(accessMutex_);
1722  if(theSupervisor_->VERBOSE_MUTEX)
1723  __COUT__ << "Have iterator access" << __E__;
1724 
1725  xmldoc.addTextElementToData("active_plan", activePlanName_);
1726  xmldoc.addTextElementToData("last_started_plan", lastStartedPlanName_);
1727  xmldoc.addTextElementToData("last_finished_plan", lastFinishedPlanName_);
1728 
1729  sprintf(tmp, "%u", activeCommandIndex_);
1730  xmldoc.addTextElementToData("current_command_index", tmp);
1731  sprintf(tmp, "%ld", time(0) - activeCommandStartTime_);
1732  xmldoc.addTextElementToData("current_command_duration", tmp);
1733  sprintf(tmp, "%u", activeCommandIteration_);
1734  xmldoc.addTextElementToData("current_command_iteration", tmp);
1735 
1736  for(const auto& depthIteration : depthIterationStack_)
1737  {
1738  sprintf(tmp, "%u", depthIteration);
1739  xmldoc.addTextElementToData("depth_iteration", tmp);
1740  }
1741 
1742  if(activePlanIsRunning_ && iteratorBusy_)
1743  {
1744  if(workloopRunning_)
1745  xmldoc.addTextElementToData("active_plan_status", "Running");
1746  else
1747  xmldoc.addTextElementToData("active_plan_status", "Error");
1748  }
1749  else if(!activePlanIsRunning_ && iteratorBusy_)
1750  xmldoc.addTextElementToData("active_plan_status", "Paused");
1751  else
1752  xmldoc.addTextElementToData("active_plan_status", "Inactive");
1753 
1754  xmldoc.addTextElementToData("error_message", errorMessage_);
1755 }