otsdaq  3.11.00
FEVInterfacesManager.cc
1 #include "otsdaq/FECore/FEVInterfacesManager.h"
2 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
3 #include "otsdaq/FECore/MakeInterface.h"
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/MessageFacility/MessageFacility.h"
6 
7 #include "artdaq-core/Utilities/configureMessageFacility.hh"
8 #include "artdaq/BuildInfo/GetPackageBuildInfo.hh"
9 #include "fhiclcpp/make_ParameterSet.h"
10 #include "messagefacility/MessageLogger/MessageLogger.h"
11 
12 #include <iostream>
13 #include <sstream>
14 #include <thread> //for std::thread
15 
16 using namespace ots;
17 
18 //==============================================================================
19 FEVInterfacesManager::FEVInterfacesManager(
20  const ConfigurationTree& theXDAQContextConfigTree,
21  const std::string& supervisorConfigurationPath)
22  : Configurable(theXDAQContextConfigTree, supervisorConfigurationPath)
23  , VStateMachine(Configurable::theConfigurationRecordName_)
24 {
25  init();
26  __CFG_COUT__ << "Constructed." << __E__;
27 } //end constructor
28 
29 //==============================================================================
30 FEVInterfacesManager::~FEVInterfacesManager(void)
31 {
32  destroy();
33  __CFG_COUT__ << "Destructed." << __E__;
34 } //end destructor
35 
36 //==============================================================================
38 
39 //==============================================================================
40 void FEVInterfacesManager::destroy(void)
41 {
42  for(auto& it : theFEInterfaces_)
43  it.second.reset();
44 
45  theFEInterfaces_.clear();
46  theFENamesByPriority_.clear();
47 } //end destroy()
48 
49 //==============================================================================
50 void FEVInterfacesManager::createInterfaces(void)
51 {
52  const std::string COL_NAME_feGroupLink = "LinkToFEInterfaceTable";
53  const std::string COL_NAME_feTypeLink = "LinkToFETypeTable";
54  const std::string COL_NAME_fePlugin = "FEInterfacePluginName";
55 
56  __CFG_COUT__ << "Path: " << theConfigurationPath_ + "/" + COL_NAME_feGroupLink
57  << __E__;
58 
59  destroy();
60 
61  { // could access application node like so, ever needed?
62  ConfigurationTree appNode =
63  theXDAQContextConfigTree_.getBackNode(theConfigurationPath_, 1);
64  __CFG_COUTV__(appNode.getValueAsString());
65 
66  auto fes = appNode.getNode("LinkToSupervisorTable")
67  .getNode("LinkToFEInterfaceTable")
68  .getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
69  __CFG_COUTV__(StringMacros::vectorToString(fes));
70  }
71 
72  ConfigurationTree feGroupLinkNode =
73  Configurable::getSelfNode().getNode(COL_NAME_feGroupLink);
74 
75  std::vector<std::pair<std::string, ConfigurationTree>> feChildren =
76  feGroupLinkNode.getChildren();
77 
78  // acquire names by priority
79  theFENamesByPriority_ =
80  feGroupLinkNode.getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
81  __CFG_COUTV__(StringMacros::vectorToString(theFENamesByPriority_));
82 
83  for(const auto& interface : feChildren)
84  {
85  try
86  {
87  if(!interface.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
88  .getValue<bool>())
89  continue;
90  }
91  catch(...) // if Status column not there ignore (for backwards compatibility)
92  {
93  __CFG_COUT_INFO__ << "Ignoring FE Status since Status column is missing!"
94  << __E__;
95  }
96 
97  __CFG_COUT__
98  << "Interface Plugin Name: "
99  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
100  << __E__;
101  __CFG_COUT__ << "Interface Name: " << interface.first << __E__;
102  __CFG_COUT__ << "XDAQContext Node: " << theXDAQContextConfigTree_ << __E__;
103  __CFG_COUT__ << "Path to configuration: "
104  << (theConfigurationPath_ + "/" + COL_NAME_feGroupLink + "/" +
105  interface.first + "/" + COL_NAME_feTypeLink)
106  << __E__;
107 
108  try
109  {
110  theFEInterfaces_[interface.first] = makeInterface(
111  interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>(),
112  interface.first,
113  theXDAQContextConfigTree_,
114  (theConfigurationPath_ + "/" + COL_NAME_feGroupLink + "/" +
115  interface.first + "/" + COL_NAME_feTypeLink));
116 
117  // setup parent supervisor and interface manager
118  // of FEVinterface (for backwards compatibility, left out of constructor)
119  theFEInterfaces_[interface.first]->setParentPointers(
121 
122  __CFG_COUTV__(interface.first);
123  __CFG_COUTV__(VStateMachine::parentSupervisor_);
124  __CFG_COUTV__(VStateMachine::parentSupervisor_->getContextUID());
125  __CFG_COUTV__(VStateMachine::parentSupervisor_->getSupervisorUID());
126  __CFG_COUTTV__(
127  theFEInterfaces_[interface.first]->VStateMachine::parentSupervisor_);
128  __CFG_COUTTV__(theFEInterfaces_[interface.first]
129  ->VStateMachine::parentSupervisor_->getContextUID());
130  __CFG_COUTTV__(theFEInterfaces_[interface.first]
131  ->VStateMachine::parentSupervisor_->getSupervisorUID());
132  }
133  catch(const cet::exception& e)
134  {
135  __CFG_SS__
136  << "Failed to instantiate plugin named '" << interface.first
137  << "' of type '"
138  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
139  << "' due to the following error: \n"
140  << e.what() << __E__;
141  __COUT_ERR__ << ss.str();
142  __CFG_SS_THROW__;
143  }
144  catch(const std::runtime_error& e)
145  {
146  __CFG_SS__
147  << "Failed to instantiate plugin named '" << interface.first
148  << "' of type '"
149  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
150  << "' due to the following error: \n"
151  << e.what() << __E__;
152  __COUT_ERR__ << ss.str();
153  __CFG_SS_THROW__;
154  }
155  catch(...)
156  {
157  __CFG_SS__
158  << "Failed to instantiate plugin named '" << interface.first
159  << "' of type '"
160  << interface.second.getNode(COL_NAME_fePlugin).getValue<std::string>()
161  << "' due to an unknown error." << __E__;
162  try
163  {
164  throw;
165  } //one more try to printout extra info
166  catch(const std::exception& e)
167  {
168  ss << "Exception message: " << e.what();
169  }
170  catch(...)
171  {
172  }
173  __COUT_ERR__ << ss.str();
174  throw; // if we do not throw, it is hard to tell what is happening..
175  //__CFG_SS_THROW__;
176  }
177  }
178  __CFG_COUT__ << "Done creating interfaces" << __E__;
179 } // end createInterfaces()
180 
181 //==============================================================================
187 {
188  std::string progress = "";
189  unsigned int cnt = 0;
190  //__CFG_COUTV__(theFENamesByPriority_.size());
191  //__CFG_COUTV__(VStateMachine::getTransitionName());
192  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
193  try
194  {
195  const std::string& name = theFENamesByPriority_[i];
196  FEVInterface* fe = getFEInterfaceP(name);
197  std::string feProgress = fe->getStatusProgressDetail();
198  if(feProgress.size())
199  progress +=
200  ((cnt++) ? "," : "") + StringMacros::encodeURIComponent(feProgress);
201  }
202  catch(...)
203  {
204  } // ignore errors
205 
206  // if(progress.size())
207  // __CFG_COUTV__(progress);
208 
209  return progress;
210 } // end getStatusProgressString()
211 
212 //==============================================================================
213 unsigned int FEVInterfacesManager::getMinReadyForEventGenerationStartIteration(void) const
214 {
215  unsigned int maxIteration = 0;
216  for(const auto& fePair : theFEInterfaces_)
217  {
218  unsigned int val = fePair.second->getMinReadyForEventGenerationStartIteration();
219  if(val > maxIteration)
220  maxIteration = val;
221  }
222  return maxIteration;
223 } // end getMinReadyForEventGenerationStartIteration()
224 
225 //==============================================================================
227 {
228  const std::string transitionName = "Configuring";
229 
230  __CFG_COUT__ << transitionName << " FEVInterfacesManager " << __E__;
231 
232  // create interfaces (the first iteration)
234  createInterfaces(); // by priority
235 
236  FEVInterface* fe;
237 
238  preStateMachineExecutionLoop();
239  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
240  {
241  // if one state machine is doing a sub-iteration, then target that one
242  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
243  i != subIterationWorkStateMachineIndex_)
244  continue; // skip those not in the sub-iteration
245 
246  const std::string& name = theFENamesByPriority_[i];
247 
248  // test for front-end existence
249  fe = getFEInterfaceP(name);
250 
251  if(stateMachinesIterationDone_[name])
252  continue; // skip state machines already done
253 
254  __CFG_COUT__ << transitionName << " interface " << name << __E__;
255 
256  preStateMachineExecution(i, transitionName);
257  fe->configure();
258  postStateMachineExecution(i);
259 
260  // when done with fe configure, configure slow controls
261  if(!fe->VStateMachine::getSubIterationWork() &&
262  !fe->VStateMachine::getIterationWork() &&
263  !fe->VStateMachine::getSubsystemIterationWork())
264  {
265  // configure slow controls and start slow controls workloop
266  // slow controls workloop stays alive through start/stop.. and dies on halt
267  fe->configureSlowControls();
268  fe->startSlowControlsWorkLoop();
269 
270  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
271  }
272  }
273  postStateMachineExecutionLoop();
274 
275  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
276 } // end configure()
277 
278 //==============================================================================
279 void FEVInterfacesManager::halt(void)
280 {
281  const std::string transitionName = "Halting";
282  FEVInterface* fe;
283 
284  preStateMachineExecutionLoop();
285  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
286  {
287  // if one state machine is doing a sub-iteration, then target that one
288  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
289  i != subIterationWorkStateMachineIndex_)
290  continue; // skip those not in the sub-iteration
291 
292  const std::string& name = theFENamesByPriority_[i];
293 
294  fe = getFEInterfaceP(name);
295 
296  if(stateMachinesIterationDone_[name])
297  continue; // skip state machines already done
298 
299  __CFG_COUT__ << transitionName << " interface " << name << __E__;
300  __CFG_COUT__ << transitionName << " interface " << name << __E__;
301  __CFG_COUT__ << transitionName << " interface " << name << __E__;
302 
303  preStateMachineExecution(i, transitionName);
304 
305  // since halting also occurs on errors, ignore more errors
306  try
307  {
308  fe->stopWorkLoop();
309  }
310  catch(...)
311  {
312  __CFG_COUT_WARN__
313  << "An error occurred while halting the front-end workloop for '" << name
314  << ",' ignoring." << __E__;
315  }
316 
317  // since halting also occurs on errors, ignore more errors
318  try
319  {
320  fe->stopSlowControlsWorkLoop();
321  }
322  catch(...)
323  {
324  __CFG_COUT_WARN__ << "An error occurred while halting the Slow Controls "
325  "front-end workloop for '"
326  << name << ",' ignoring." << __E__;
327  }
328 
329  // since halting also occurs on errors, ignore more errors
330  try
331  {
332  fe->halt();
333  }
334  catch(...)
335  {
336  __CFG_COUT_WARN__ << "An error occurred while halting the front-end '" << name
337  << ",' ignoring." << __E__;
338  }
339 
340  postStateMachineExecution(i);
341 
342  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
343  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
344  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
345  }
346  postStateMachineExecutionLoop();
347 
348  if(!VStateMachine::getSubIterationWork() && !VStateMachine::getIterationWork())
349  destroy(); // destroy all FE interfaces on halt, must be configured for FE interfaces to exist
350 
351  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
352 } // end halt()
353 
354 //==============================================================================
355 void FEVInterfacesManager::pause(void)
356 {
357  const std::string transitionName = "Pausing";
358  FEVInterface* fe;
359 
360  preStateMachineExecutionLoop();
361  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
362  {
363  // if one state machine is doing a sub-iteration, then target that one
364  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
365  i != subIterationWorkStateMachineIndex_)
366  continue; // skip those not in the sub-iteration
367 
368  const std::string& name = theFENamesByPriority_[i];
369 
370  fe = getFEInterfaceP(name);
371 
372  if(stateMachinesIterationDone_[name])
373  continue; // skip state machines already done
374 
375  __CFG_COUT__ << transitionName << " interface " << name << __E__;
376  __CFG_COUT__ << transitionName << " interface " << name << __E__;
377  __CFG_COUT__ << transitionName << " interface " << name << __E__;
378 
379  preStateMachineExecution(i, transitionName);
380  fe->stopWorkLoop();
381  fe->pause();
382  postStateMachineExecution(i);
383 
384  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
385  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
386  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
387  }
388  postStateMachineExecutionLoop();
389 
390  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
391 } // end pause()
392 
393 //==============================================================================
394 void FEVInterfacesManager::resume(void)
395 {
396  const std::string transitionName = "Resuming";
397  // FEVInterface* fe;
398 
399  preStateMachineExecutionLoop();
400  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
401  {
402  // if one state machine is doing a sub-iteration, then target that one
403  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
404  i != subIterationWorkStateMachineIndex_)
405  continue; // skip those not in the sub-iteration
406 
407  const std::string& name = theFENamesByPriority_[i];
408 
409  FEVInterface* fe = getFEInterfaceP(name);
410 
411  if(stateMachinesIterationDone_[name])
412  continue; // skip state machines already done
413 
414  __CFG_COUT__ << transitionName << " interface " << name << __E__;
415  __CFG_COUT__ << transitionName << " interface " << name << __E__;
416  __CFG_COUT__ << transitionName << " interface " << name << __E__;
417 
418  preStateMachineExecution(i, transitionName);
419  fe->resume();
420  // only start workloop once transition is done
421  if(postStateMachineExecution(i))
422  fe->startWorkLoop();
423 
424  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
425  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
426  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
427  }
428  postStateMachineExecutionLoop();
429 
430  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
431 
432 } // end resume()
433 
434 //==============================================================================
435 void FEVInterfacesManager::start(std::string runNumber)
436 {
437  const std::string transitionName = "Starting";
438  FEVInterface* fe;
439 
440  preStateMachineExecutionLoop();
441  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
442  {
443  // if one state machine is doing a sub-iteration, then target that one
444  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
445  i != subIterationWorkStateMachineIndex_)
446  continue; // skip those not in the sub-iteration
447 
448  const std::string& name = theFENamesByPriority_[i];
449 
450  fe = getFEInterfaceP(name);
451 
452  if(stateMachinesIterationDone_[name])
453  continue; // skip state machines already done
454 
455  __CFG_COUT__ << transitionName << " interface " << name << __E__;
456  __CFG_COUT__ << transitionName << " interface " << name << __E__;
457  __CFG_COUT__ << transitionName << " interface " << name << __E__;
458 
459  preStateMachineExecution(i, transitionName);
460  fe->start(runNumber);
461  // only start workloop once transition is done
462  if(postStateMachineExecution(i))
463  fe->startWorkLoop();
464 
465  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
466  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
467  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
468  }
469  postStateMachineExecutionLoop();
470 
471  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
472 
473 } // end start()
474 
475 //==============================================================================
476 void FEVInterfacesManager::stop(void)
477 {
478  const std::string transitionName = "Starting";
479  FEVInterface* fe;
480 
481  preStateMachineExecutionLoop();
482  for(unsigned int i = 0; i < theFENamesByPriority_.size(); ++i)
483  {
484  // if one state machine is doing a sub-iteration, then target that one
485  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
486  i != subIterationWorkStateMachineIndex_)
487  continue; // skip those not in the sub-iteration
488 
489  const std::string& name = theFENamesByPriority_[i];
490 
491  fe = getFEInterfaceP(name);
492 
493  if(stateMachinesIterationDone_[name])
494  continue; // skip state machines already done
495 
496  __CFG_COUT__ << transitionName << " interface " << name << __E__;
497  __CFG_COUT__ << transitionName << " interface " << name << __E__;
498  __CFG_COUT__ << transitionName << " interface " << name << __E__;
499 
500  preStateMachineExecution(i, transitionName);
501  fe->stopWorkLoop();
502  fe->stop();
503  postStateMachineExecution(i);
504 
505  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
506  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
507  __CFG_COUT__ << "Done " << transitionName << " interface " << name << __E__;
508  }
509  postStateMachineExecutionLoop();
510 
511  __CFG_COUT__ << "Done " << transitionName << " all interfaces." << __E__;
512 
513 } // end stop()
514 
515 //==============================================================================
517 FEVInterface* FEVInterfacesManager::getFEInterfaceP(const std::string& interfaceID)
518 {
519  try
520  {
521  return theFEInterfaces_.at(interfaceID).get();
522  }
523  catch(...)
524  {
525  __CFG_SS__ << "Interface ID '" << interfaceID
526  << "' not found in configured interfaces." << __E__;
527  __SS_ONLY_THROW__;
528  }
529 } // end getFEInterfaceP()
530 
531 //==============================================================================
534  const std::string& interfaceID) const
535 {
536  try
537  {
538  return *(theFEInterfaces_.at(interfaceID));
539  }
540  catch(...)
541  {
542  __CFG_SS__ << "Interface ID '" << interfaceID
543  << "' not found in configured interfaces." << __E__;
544  __SS_ONLY_THROW__;
545  }
546 } // end getFEInterface()
547 
548 //==============================================================================
552 void FEVInterfacesManager::universalRead(const std::string& interfaceID,
553  char* address,
554  char* returnValue)
555 {
556  getFEInterfaceP(interfaceID)->universalRead(address, returnValue);
557 } // end universalRead()
558 
559 //==============================================================================
563  const std::string& interfaceID)
564 {
565  return getFEInterfaceP(interfaceID)->getUniversalAddressSize();
566 } // end getInterfaceUniversalAddressSize()
567 
568 //==============================================================================
572  const std::string& interfaceID)
573 {
574  return getFEInterfaceP(interfaceID)->getUniversalDataSize();
575 } // end getInterfaceUniversalDataSize()
576 
577 //==============================================================================
580 void FEVInterfacesManager::universalWrite(const std::string& interfaceID,
581  char* address,
582  char* writeValue)
583 {
584  getFEInterfaceP(interfaceID)->universalWrite(address, writeValue);
585 } // end universalWrite()
586 
587 //==============================================================================
592 std::string FEVInterfacesManager::getFEListString(const std::string& supervisorLid)
593 {
594  std::string retList = "";
595 
596  for(const auto& it : theFEInterfaces_)
597  {
598  __CFG_COUT__ << "FE name = " << it.first << __E__;
599 
600  retList += it.second->getInterfaceType() + ":" + supervisorLid + ":" +
601  it.second->getInterfaceUID() + "\n";
602  }
603  return retList;
604 } // end getFEListString()
605 
606 //==============================================================================
623 void FEVInterfacesManager::startMacroMultiDimensional(const std::string& requester,
624  const std::string& interfaceID,
625  const std::string& macroName,
626  const std::string& macroString,
627  const bool enableSavingOutput,
628  const std::string& outputFilePath,
629  const std::string& outputFileRadix,
630  const std::string& inputArgs)
631 {
632  if(requester != "iterator")
633  {
634  __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__;
635  __CFG_SS_THROW__;
636  }
637 
638  __CFG_COUT__ << "Starting multi-dimensional Macro '" << macroName
639  << "' for interface '" << interfaceID << ".'" << __E__;
640 
641  __CFG_COUTV__(macroString);
642 
643  __CFG_COUTV__(inputArgs);
644 
645  // mark active(only one Macro per interface active at any time, for now)
646  { // lock mutex scope
647  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
648  // mark active
649  if(macroMultiDimensionalStatusMap_.find(interfaceID) !=
650  macroMultiDimensionalStatusMap_.end())
651  {
652  __SS__ << "Failed to start multi-dimensional Macro '" << macroName
653  << "' for interface '" << interfaceID
654  << "' - this interface already has an active Macro launch!" << __E__;
655  __SS_THROW__;
656  }
657  macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active"));
658  } // unlock mutex scope
659 
660  // start thread
661  std::thread(
662  [](FEVInterfacesManager* feMgr,
663  const std::string interfaceID,
664  const std::string macroName,
665  const std::string macroString,
666  const bool enableSavingOutput,
667  const std::string outputFilePath,
668  const std::string outputFileRadix,
669  const std::string inputArgsStr) {
670  // create local message facility subject
671  std::string mfSubject_ = "threadMultiD-" + macroName;
672  __GEN_COUT__ << "Thread started." << __E__;
673 
674  std::string statusResult = "Done";
675 
676  try
677  {
678  //-------------------------------
679  // check for interfaceID
680  FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID);
681 
682  //-------------------------------
683  // extract macro object
684  FEVInterface::macroStruct_t macro(macroString);
685 
686  //-------------------------------
687  // create output file pointer
688  FILE* outputFilePointer = 0;
689  if(enableSavingOutput)
690  {
691  // blank (or unset table column) path means $OTSDAQ_DATA, as the
692  // Iterate GUI advertises in its placeholder text
693  std::string basePath = outputFilePath;
694  if(basePath == "" ||
695  basePath == TableViewColumnInfo::DATATYPE_STRING_DEFAULT ||
696  basePath == TableViewColumnInfo::DATATYPE_STRING_ALT_DEFAULT)
697  basePath = std::string(__ENV__("OTSDAQ_DATA"));
698  std::string filename = basePath + "/" + outputFileRadix + macroName +
699  "_" + std::to_string(time(0)) + ".txt";
700  __GEN_COUT__ << "Opening file... " << filename << __E__;
701 
702  outputFilePointer = fopen(filename.c_str(), "w");
703  if(!outputFilePointer)
704  {
705  __GEN_SS__ << "Failed to open output file: " << filename << __E__;
706  __GEN_SS_THROW__;
707  }
708  { // record for the Iterator's completion report
709  std::lock_guard<std::mutex> lock(
711  feMgr->macroMultiDimensionalOutputFileMap_[interfaceID] =
712  filename;
713  }
714  } // at this point output file pointer is valid or null
715 
716  //-------------------------------
717  // setup Macro arguments
718  __GEN_COUTV__(inputArgsStr);
719 
720  // inputs:
721  // - inputArgs: dimensional semi-colon-separated,
722  // comma separated: dimension iterations and arguments
723  //(colon-separated name/value/stepsize sets)
724 
725  // need to extract input arguments
726  // by dimension (by priority)
727  //
728  // two vector by dimension <map of params>
729  // one vector for long and for double
730  //
731  // map of params :=
732  // name => {
733  // <long/double current value>
734  // <long/double init value>
735  // <long/double step size>
736  // }
737 
738  std::vector<unsigned long /*dimension iterations*/> dimensionIterations,
739  dimensionIterationCnt;
740 
741  using longParamMap_t = std::map<
742  std::string /*name*/,
743  std::pair<long /*current value*/,
744  std::pair<long /*initial value*/, long /*step value*/>>>;
745 
746  std::vector<longParamMap_t> longDimensionParameters;
747  // Note: double parameters not allowed for Macro (allowed in FE Macros)
748 
749  // instead of strict inputs and outputs, make a map
750  // and populate with all input and output names
751  std::map<std::string /*name*/, uint64_t /*value*/> variableMap;
752 
753  // std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
754  // std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
755 
756  for(const auto& inputArgName : macro.namesOfInputArguments_)
757  variableMap.emplace( // do not care about input arg value
758  std::pair<std::string /*name*/, uint64_t /*value*/>(inputArgName,
759  0));
760  for(const auto& outputArgName : macro.namesOfOutputArguments_)
761  variableMap.emplace( // do not care about output arg value
762  std::pair<std::string /*name*/, uint64_t /*value*/>(outputArgName,
763  0));
764 
765  if(0) // example
766  {
767  // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3";
768 
769  dimensionIterations.push_back(2);
770  dimensionIterations.push_back(4);
771 
772  longDimensionParameters.push_back(longParamMap_t());
773  longDimensionParameters.push_back(longParamMap_t());
774 
775  longDimensionParameters.back().emplace(std::make_pair(
776  "myOtherArg",
777  std::make_pair(
778  3 /*current value*/,
779  std::make_pair(3 /*initial value*/, 4 /*step value*/))));
780  } // end example
781 
782  std::vector<std::string> dimensionArgs;
784  inputArgsStr, dimensionArgs, {';'} /*delimeter set*/);
785 
786  __GEN_COUTV__(dimensionArgs.size());
787  //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs));
788 
789  if(dimensionArgs.size() == 0)
790  {
791  // just call Macro once!
792  // create dimension with 1 iteration
793  // and no arguments
794  dimensionIterations.push_back(1);
795  longDimensionParameters.push_back(longParamMap_t());
796  }
797  else
798  for(unsigned int d = 0; d < dimensionArgs.size(); ++d)
799  {
800  // for each dimension
801  // get argument and classify as long or double
802 
803  std::vector<std::string> args;
805  dimensionArgs[d], args, {','} /*delimeter set*/);
806 
807  //__GEN_COUTV__(args.size());
808  //__GEN_COUTV__(StringMacros::vectorToString(args));
809 
810  // require first value for number of iterations
811  if(args.size() == 0)
812  {
813  __GEN_SS__ << "Invalid dimensional arguments! "
814  << "Need number of iterations at dimension " << d
815  << __E__;
816  __GEN_SS_THROW__;
817  }
818 
819  unsigned long numOfIterations;
820  StringMacros::getNumber(args[0], numOfIterations);
821  __GEN_COUT__ << "Dimension " << d
822  << " numOfIterations=" << numOfIterations << __E__;
823 
824  // create dimension!
825  {
826  dimensionIterations.push_back(numOfIterations);
827  longDimensionParameters.push_back(longParamMap_t());
828  }
829 
830  // skip iteration value, start at index 1
831  for(unsigned int a = 1; a < args.size(); ++a)
832  {
833  // name may contain ':' (e.g. "Arg (Default := 1)"): split from the right
834  std::vector<std::string> argPieces(3);
836  args[a], argPieces[0], argPieces[1], argPieces[2]))
837  {
838  __GEN_SS__ << "Invalid argument '" << args[a]
839  << "'! Expected name:initialValue:stepSize."
840  << __E__;
841  __GEN_SS_THROW__;
842  }
843  argPieces[0] = StringMacros::decodeURIComponent(argPieces[0]);
844  argPieces[1] = StringMacros::decodeURIComponent(argPieces[1]);
845  argPieces[2] = StringMacros::decodeURIComponent(argPieces[2]);
846 
847  __GEN_COUTV__(StringMacros::vectorToString(argPieces));
848 
849  // check piece 1 and 2 for double hint
850  // a la Iterator::startCommandModifyActive()
851  if((argPieces[1].size() &&
852  (argPieces[1][argPieces[1].size() - 1] == 'f' ||
853  argPieces[1].find('.') != std::string::npos)) ||
854  (argPieces[2].size() &&
855  (argPieces[2][argPieces[2].size() - 1] == 'f' ||
856  argPieces[2].find('.') != std::string::npos)))
857  {
858  // handle as double
859 
860  double startValue = strtod(argPieces[1].c_str(), 0);
861  double stepSize = strtod(argPieces[2].c_str(), 0);
862 
863  __GEN_COUTV__(startValue);
864  __GEN_COUTV__(stepSize);
865 
866  __GEN_SS__
867  << "Error! Only integer aruments allowed for Macros. "
868  << "Double style arugment found: " << argPieces[0]
869  << "' := " << startValue << ", " << stepSize << __E__;
870  __GEN_SS_THROW__;
871  // doubleDimensionParameters.back().emplace(
872  // std::make_pair(argPieces[0],
873  // std::make_pair(
874  // startValue
876  // std::make_pair(
877  // startValue
879  // stepSize
881  }
882  else
883  {
884  // handle as long
885  //__GEN_COUT__ << "Long found" << __E__;
886 
887  long int startValue;
888  long int stepSize;
889 
890  StringMacros::getNumber(argPieces[1], startValue);
891  StringMacros::getNumber(argPieces[2], stepSize);
892 
893  __GEN_COUTV__(startValue);
894  __GEN_COUTV__(stepSize);
895 
896  __GEN_COUT__ << "Creating long argument '" << argPieces[0]
897  << "' := " << startValue << ", " << stepSize
898  << __E__;
899 
900  longDimensionParameters.back().emplace(std::make_pair(
901  argPieces[0],
902  std::make_pair(
903  startValue /*current value*/,
904  std::make_pair(startValue /*initial value*/,
905  stepSize /*step value*/))));
906  }
907 
908  } // end dimensional argument loop
909 
910  } // end dimensions loop
911 
912  if(dimensionIterations.size() != longDimensionParameters.size())
913  {
914  __GEN_SS__ << "Impossible vector size mismatch! "
915  << dimensionIterations.size() << " - "
916  << longDimensionParameters.size() << __E__;
917  __GEN_SS_THROW__;
918  }
919 
920  // output header
921  {
922  std::stringstream outSS;
923  {
924  outSS << "\n==========================\n" << __E__;
925  outSS << "Macro '" << macro.macroName_
926  << "' multi-dimensional scan..." << __E__;
927  outSS << "\t" << StringMacros::getTimestampString() << __E__;
928  outSS << "\t" << dimensionIterations.size()
929  << " dimensions defined." << __E__;
930  for(unsigned int i = 0; i < dimensionIterations.size(); ++i)
931  {
932  outSS << "\t\t"
933  << "dimension[" << i << "] has "
934  << dimensionIterations[i] << " iterations and "
935  << (longDimensionParameters[i].size()) << " arguments."
936  << __E__;
937 
938  for(auto& param : longDimensionParameters[i])
939  outSS << "\t\t\t"
940  << "'" << param.first << "' of type long with "
941  << "initial value and step value [decimal] = "
942  << "\t" << param.second.second.first << " & "
943  << param.second.second.second << __E__;
944  }
945 
946  outSS << "\nInput argument names:" << __E__;
947  for(const auto& inputArgName : macro.namesOfInputArguments_)
948  outSS << "\t" << inputArgName << __E__;
949  outSS << "\nOutput argument names:" << __E__;
950  for(const auto& outputArgName : macro.namesOfOutputArguments_)
951  outSS << "\t" << outputArgName << __E__;
952 
953  outSS << "\n==========================\n" << __E__;
954  } // end outputs stringstream results
955 
956  // if enabled to save to file, do it.
957  __GEN_COUT__ << "\n" << outSS.str();
958  if(outputFilePointer)
959  fprintf(outputFilePointer, "%s", outSS.str().c_str());
960  } // end output header
961 
962  unsigned int iterationCount = 0;
963 
964  // Use lambda recursive function to do arbitrary dimensions
965  //
966  // Note: can not do lambda recursive function if using auto to declare the
967  // function, and must capture reference to the function. Also, must
968  // capture specialFolders reference for use internally (const values
969  // already are captured).
970  std::function<void(const unsigned int /*dimension*/
971  )>
972  localRecurse = [&dimensionIterations,
973  &dimensionIterationCnt,
974  &iterationCount,
975  &longDimensionParameters,
976  &fe,
977  &macro,
978  &variableMap,
979  &outputFilePointer,
980  &localRecurse](const unsigned int dimension) {
981  // create local message facility subject
982  std::string mfSubject_ = "multiD-" + std::to_string(dimension) +
983  "-" + macro.macroName_;
984  __GEN_COUTV__(dimension);
985 
986  if(dimension >= dimensionIterations.size())
987  {
988  __GEN_COUT__ << "Iteration count: " << iterationCount++
989  << __E__;
990  __GEN_COUT__ << "Launching Macro '" << macro.macroName_
991  << "' ..." << __E__;
992 
993  // set argsIn to current value
994  {
995  // scan all dimension parameter objects
996  // note: Although conflicts should not be allowed
997  // at this point, lower dimensions will have priority
998  // over higher dimension with same name argument..
999  // and longs will have priority over doubles
1000 
1001  for(unsigned int j = 0; j < dimensionIterations.size();
1002  ++j)
1003  {
1004  for(auto& longParam : longDimensionParameters[j])
1005  {
1006  __GEN_COUT__
1007  << "Assigning argIn '" << longParam.first
1008  << "' to current long value '"
1009  << longParam.second.first
1010  << "' from dimension " << j << " parameter."
1011  << __E__;
1012  variableMap.at(longParam.first) =
1013  longParam.second.first;
1014  }
1015  } // end long loop
1016 
1017  } // done building argsIn
1018 
1019  // output inputs
1020  {
1021  std::stringstream outSS;
1022  {
1023  outSS << "\n---------------\n" << __E__;
1024  outSS << "Macro '" << macro.macroName_
1025  << "' execution..." << __E__;
1026  outSS << "\t"
1027  << "iteration " << iterationCount << __E__;
1028  for(unsigned int i = 0;
1029  i < dimensionIterationCnt.size();
1030  ++i)
1031  outSS << "\t"
1032  << "dimension[" << i
1033  << "] index := " << dimensionIterationCnt[i]
1034  << __E__;
1035 
1036  outSS << "\n"
1037  << "\t"
1038  << "Input arguments (count: "
1039  << macro.namesOfInputArguments_.size()
1040  << "):" << __E__;
1041  for(auto& argIn : macro.namesOfInputArguments_)
1042  outSS << "\t\t" << argIn << " = "
1043  << variableMap.at(argIn) << __E__;
1044 
1045  } // end outputs stringstream results
1046 
1047  // if enabled to save to file, do it.
1048  __GEN_COUT__ << "\n" << outSS.str();
1049  if(outputFilePointer)
1050  fprintf(outputFilePointer, "%s", outSS.str().c_str());
1051  } // end output inputs
1052 
1053  // have FE and Macro structure, so run it
1054  fe->runMacro(macro, variableMap);
1055 
1056  __GEN_COUT__ << "Macro complete!" << __E__;
1057 
1058  // output results
1059  {
1060  std::stringstream outSS;
1061  {
1062  outSS << "\n"
1063  << "\t"
1064  << "Output arguments (count: "
1065  << macro.namesOfOutputArguments_.size()
1066  << "):" << __E__;
1067  for(auto& argOut : macro.namesOfOutputArguments_)
1068  outSS << "\t\t" << argOut << " = "
1069  << variableMap.at(argOut) << __E__;
1070  } // end outputs stringstream results
1071 
1072  // if enabled to save to file, do it.
1073  __GEN_COUT__ << "\n" << outSS.str();
1074  if(outputFilePointer)
1075  fprintf(outputFilePointer, "%s", outSS.str().c_str());
1076  } // end output results
1077 
1078  return;
1079  }
1080 
1081  // init dimension index
1082  if(dimension >= dimensionIterationCnt.size())
1083  dimensionIterationCnt.push_back(0);
1084 
1085  // if enabled to save to file, do it.
1086  __GEN_COUT__ << "\n"
1087  << "======================================" << __E__
1088  << "dimension[" << dimension
1089  << "] number of iterations := "
1090  << dimensionIterations[dimension] << __E__;
1091 
1092  // update current value to initial value for this dimension's parameters
1093  {
1094  for(auto& longPair : longDimensionParameters[dimension])
1095  {
1096  longPair.second.first = // reset to initial value
1097  longPair.second.second.first;
1098  __GEN_COUT__
1099  << "arg '" << longPair.first
1100  << "' current value: " << longPair.second.first
1101  << __E__;
1102  } // end long loop
1103 
1104  } // end update current value to initial value for all dimensional parameters
1105 
1106  for(dimensionIterationCnt[dimension] =
1107  0; // reset each time through dimension loop
1108  dimensionIterationCnt[dimension] <
1109  dimensionIterations[dimension];
1110  ++dimensionIterationCnt[dimension])
1111  {
1112  __GEN_COUT__ << "dimension[" << dimension << "] index := "
1113  << dimensionIterationCnt[dimension] << __E__;
1114 
1115  localRecurse(dimension + 1);
1116 
1117  // update current value to next value for this dimension's parameters
1118  {
1119  for(auto& longPair : longDimensionParameters[dimension])
1120  {
1121  longPair.second.first += // add step value
1122  longPair.second.second.second;
1123  __GEN_COUT__
1124  << "arg '" << longPair.first
1125  << "' current value: " << longPair.second.first
1126  << __E__;
1127  } // end long loop
1128 
1129  } // end update current value to next value for all dimensional parameters
1130  }
1131  __GEN_COUT__ << "Completed dimension[" << dimension
1132  << "] number of iterations := "
1133  << dimensionIterationCnt[dimension] << " of "
1134  << dimensionIterations[dimension] << __E__;
1135  }; // end local lambda recursive function
1136 
1137  // launch multi-dimensional recursion
1138  localRecurse(0);
1139 
1140  // close output file
1141  if(outputFilePointer)
1142  fclose(outputFilePointer);
1143  }
1144  catch(const std::runtime_error& e)
1145  {
1146  __SS__ << "Error executing multi-dimensional Macro: " << e.what()
1147  << __E__;
1148  statusResult = ss.str();
1149  }
1150  catch(...)
1151  {
1152  __SS__ << "Unknown error executing multi-dimensional Macro. " << __E__;
1153  try
1154  {
1155  throw;
1156  } //one more try to printout extra info
1157  catch(const std::exception& e)
1158  {
1159  ss << "Exception message: " << e.what();
1160  }
1161  catch(...)
1162  {
1163  }
1164  statusResult = ss.str();
1165  }
1166 
1167  __COUTV__(statusResult);
1168 
1169  { // lock mutex scope
1170  std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_);
1171  // change status at completion
1172  feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult;
1173  }
1174  }, // end thread()
1175  this,
1176  interfaceID,
1177  macroName,
1178  macroString,
1179  enableSavingOutput,
1180  outputFilePath,
1181  outputFileRadix,
1182  inputArgs)
1183  .detach();
1184 
1185  __CFG_COUT__ << "Started multi-dimensional Macro '" << macroName
1186  << "' for interface '" << interfaceID << ".'" << __E__;
1187 
1188 } // end startMacroMultiDimensional()
1189 
1190 //==============================================================================
1208  const std::string& requester,
1209  const std::string& interfaceID,
1210  const std::string& feMacroName,
1211  const bool enableSavingOutput,
1212  const std::string& outputFilePath,
1213  const std::string& outputFileRadix,
1214  const std::string& inputArgs)
1215 {
1216  if(requester != "iterator")
1217  {
1218  __CFG_SS__ << "Invalid requester '" << requester << "'" << __E__;
1219  __CFG_SS_THROW__;
1220  }
1221 
1222  __CFG_COUT__ << "Starting multi-dimensional FE Macro '" << feMacroName
1223  << "' for interface '" << interfaceID << ".'" << __E__;
1224  __CFG_COUTV__(inputArgs);
1225 
1226  // mark active(only one FE Macro per interface active at any time, for now)
1227  { // lock mutex scope
1228  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
1229  // mark active
1230  if(macroMultiDimensionalStatusMap_.find(interfaceID) !=
1231  macroMultiDimensionalStatusMap_.end())
1232  {
1233  __SS__ << "Failed to start multi-dimensional FE Macro '" << feMacroName
1234  << "' for interface '" << interfaceID
1235  << "' - this interface already has an active FE Macro launch!"
1236  << __E__;
1237  __SS_THROW__;
1238  }
1239  macroMultiDimensionalStatusMap_.emplace(std::make_pair(interfaceID, "Active"));
1240  }
1241 
1242  // start thread
1243  std::thread(
1244  [](FEVInterfacesManager* feMgr,
1245  const std::string interfaceID,
1246  const std::string feMacroName,
1247  const bool enableSavingOutput,
1248  const std::string outputFilePath,
1249  const std::string outputFileRadix,
1250  const std::string inputArgsStr) {
1251  // create local message facility subject
1252  std::string mfSubject_ = "threadMultiD-" + feMacroName;
1253  __GEN_COUT__ << "Thread started." << __E__;
1254 
1255  std::string statusResult = "Done";
1256 
1257  try
1258  {
1259  //-------------------------------
1260  // check for interfaceID and macro
1261  FEVInterface* fe = feMgr->getFEInterfaceP(interfaceID);
1262 
1263  // have pointer to virtual FEInterface, find Macro structure
1264  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1265  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1266  {
1267  __GEN_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '"
1268  << interfaceID << "' was not found!" << __E__;
1269  __GEN_SS_THROW__;
1270  }
1271  const FEVInterface::frontEndMacroStruct_t& feMacro = FEMacroIt->second;
1272 
1273  //-------------------------------
1274  // create output file pointer
1275  FILE* outputFilePointer = 0;
1276  if(enableSavingOutput)
1277  {
1278  // blank (or unset table column) path means $OTSDAQ_DATA, as the
1279  // Iterate GUI advertises in its placeholder text
1280  std::string basePath = outputFilePath;
1281  if(basePath == "" ||
1282  basePath == TableViewColumnInfo::DATATYPE_STRING_DEFAULT ||
1283  basePath == TableViewColumnInfo::DATATYPE_STRING_ALT_DEFAULT)
1284  basePath = std::string(__ENV__("OTSDAQ_DATA"));
1285  std::string filename = basePath + "/" + outputFileRadix +
1286  feMacroName + "_" + std::to_string(time(0)) +
1287  ".txt";
1288  __GEN_COUT__ << "Opening file... " << filename << __E__;
1289 
1290  outputFilePointer = fopen(filename.c_str(), "w");
1291  if(!outputFilePointer)
1292  {
1293  __GEN_SS__ << "Failed to open output file: " << filename << __E__;
1294  __GEN_SS_THROW__;
1295  }
1296  { // record for the Iterator's completion report
1297  std::lock_guard<std::mutex> lock(
1298  feMgr->macroMultiDimensionalDoneMutex_);
1299  feMgr->macroMultiDimensionalOutputFileMap_[interfaceID] =
1300  filename;
1301  }
1302  } // at this point output file pointer is valid or null
1303 
1304  //-------------------------------
1305  // setup FE macro aruments
1306  __GEN_COUTV__(inputArgsStr);
1307 
1308  // inputs:
1309  // - inputArgs: dimensional semi-colon-separated,
1310  // comma separated: dimension iterations and arguments
1311  //(colon-separated name/value/stepsize sets)
1312 
1313  // need to extract input arguments
1314  // by dimension (by priority)
1315  //
1316  // two vector by dimension <map of params>
1317  // one vector for long and for double
1318  //
1319  // map of params :=
1320  // name => {
1321  // <long/double current value>
1322  // <long/double init value>
1323  // <long/double step size>
1324  // }
1325 
1326  std::vector<unsigned long /*dimension iterations*/> dimensionIterations,
1327  dimensionIterationCnt;
1328 
1329  using longParamMap_t = std::map<
1330  std::string /*name*/,
1331  std::pair<long /*current value*/,
1332  std::pair<long /*initial value*/, long /*step value*/>>>;
1333  using doubleParamMap_t =
1334  std::map<std::string /*name*/,
1335  std::pair<double /*current value*/,
1336  std::pair<double /*initial value*/,
1337  double /*step value*/>>>;
1338  using stringParamMap_t =
1339  std::map<std::string /*name*/, std::string /* value*/>;
1340 
1341  std::vector<longParamMap_t> longDimensionParameters;
1342  std::vector<doubleParamMap_t> doubleDimensionParameters;
1343  std::vector<stringParamMap_t> stringDimensionParameters;
1344 
1345  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
1346  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
1347 
1348  for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size(); ++i)
1349  argsIn.push_back(std::make_pair( // do not care about input arg value
1350  feMacro.namesOfInputArguments_[i],
1351  ""));
1352  for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i)
1353  argsOut.push_back(
1354  std::make_pair( // do not care about output arg value
1355  feMacro.namesOfOutputArguments_[i],
1356  ""));
1357 
1358  if(0) // example
1359  {
1360  // inputArgsStr = "2,fisrD:3:2,fD2:4:1;4,myOtherArg:5:2,sD:10f:1.3";
1361 
1362  argsIn.push_back(std::make_pair("myOtherArg", "3"));
1363 
1364  dimensionIterations.push_back(2);
1365  dimensionIterations.push_back(4);
1366 
1367  longDimensionParameters.push_back(longParamMap_t());
1368  longDimensionParameters.push_back(longParamMap_t());
1369 
1370  doubleDimensionParameters.push_back(doubleParamMap_t());
1371  doubleDimensionParameters.push_back(doubleParamMap_t());
1372 
1373  longDimensionParameters.back().emplace(std::make_pair(
1374  "myOtherArg",
1375  std::make_pair(
1376  3 /*current value*/,
1377  std::make_pair(3 /*initial value*/, 4 /*step value*/))));
1378  } // end example
1379 
1380  std::vector<std::string> dimensionArgs;
1382  inputArgsStr, dimensionArgs, {';'} /*delimeter set*/);
1383 
1384  __GEN_COUTV__(dimensionArgs.size());
1385  //__GEN_COUTV__(StringMacros::vectorToString(dimensionArgs));
1386 
1387  if(dimensionArgs.size() == 0)
1388  {
1389  // just call FE Macro once!
1390  // create dimension with 1 iteration
1391  // and no arguments
1392  dimensionIterations.push_back(1);
1393  longDimensionParameters.push_back(longParamMap_t());
1394  doubleDimensionParameters.push_back(doubleParamMap_t());
1395  stringDimensionParameters.push_back(stringParamMap_t());
1396  }
1397  else
1398  for(unsigned int d = 0; d < dimensionArgs.size(); ++d)
1399  {
1400  // for each dimension
1401  // get argument and classify as long or double
1402 
1403  std::vector<std::string> args;
1405  dimensionArgs[d], args, {','} /*delimeter set*/);
1406 
1407  //__GEN_COUTV__(args.size());
1408  //__GEN_COUTV__(StringMacros::vectorToString(args));
1409 
1410  // require first value for number of iterations
1411  if(args.size() == 0)
1412  {
1413  __GEN_SS__ << "Invalid dimensional arguments! "
1414  << "Need number of iterations at dimension " << d
1415  << __E__;
1416  __GEN_SS_THROW__;
1417  }
1418 
1419  unsigned long numOfIterations;
1420  StringMacros::getNumber(args[0], numOfIterations);
1421  __GEN_COUT__ << "Dimension " << d
1422  << " numOfIterations=" << numOfIterations << __E__;
1423 
1424  // create dimension!
1425  {
1426  dimensionIterations.push_back(numOfIterations);
1427  longDimensionParameters.push_back(longParamMap_t());
1428  doubleDimensionParameters.push_back(doubleParamMap_t());
1429  stringDimensionParameters.push_back(stringParamMap_t());
1430  }
1431 
1432  // skip iteration value, start at index 1
1433  for(unsigned int a = 1; a < args.size(); ++a)
1434  {
1435  // name may contain ':' (e.g. "Arg (Default := 1)"): split from the right
1436  std::vector<std::string> argPieces(3);
1438  args[a], argPieces[0], argPieces[1], argPieces[2]))
1439  {
1440  __GEN_SS__ << "Invalid argument '" << args[a]
1441  << "'! Expected name:initialValue:stepSize."
1442  << __E__;
1443  __GEN_SS_THROW__;
1444  }
1445  argPieces[0] = StringMacros::decodeURIComponent(argPieces[0]);
1446  argPieces[1] = StringMacros::decodeURIComponent(argPieces[1]);
1447  argPieces[2] = StringMacros::decodeURIComponent(argPieces[2]);
1448 
1449  __GEN_COUTV__(StringMacros::vectorToString(argPieces));
1450 
1451  // check piece 1 and 2 for double hint
1452  // a la Iterator::startCommandModifyActive()
1453  double stepAsNumber = 1;
1454  if(argPieces[2] ==
1455  TableViewColumnInfo::DATATYPE_STRING_DEFAULT ||
1456  argPieces[2] ==
1457  TableViewColumnInfo::DATATYPE_STRING_ALT_DEFAULT ||
1458  (argPieces[2].size() &&
1459  StringMacros::getNumber(argPieces[2], stepAsNumber) &&
1460  stepAsNumber == 0))
1461  {
1462  // step DEFAULT or 0: the value never changes, so pass it
1463  // through untouched as a string (e.g. "true" stays "true")
1464 
1465  __GEN_COUT__ << "Creating string argument '"
1466  << argPieces[0] << "' := " << argPieces[1]
1467  << __E__;
1468 
1469  stringDimensionParameters.back().emplace(
1470  std::make_pair(argPieces[0], argPieces[1]));
1471  }
1472  else if((argPieces[1].size() &&
1473  (argPieces[1][argPieces[1].size() - 1] == 'f' ||
1474  argPieces[1].find('.') != std::string::npos)) ||
1475  (argPieces[2].size() &&
1476  (argPieces[2][argPieces[2].size() - 1] == 'f' ||
1477  argPieces[2].find('.') != std::string::npos)))
1478  {
1479  // handle as double
1480  //__GEN_COUT__ << "Double found" << __E__;
1481 
1482  double startValue = strtod(argPieces[1].c_str(), 0);
1483  double stepSize = strtod(argPieces[2].c_str(), 0);
1484 
1485  __GEN_COUTV__(startValue);
1486  __GEN_COUTV__(stepSize);
1487 
1488  __GEN_COUT__ << "Creating double argument '"
1489  << argPieces[0] << "' := " << startValue
1490  << ", " << stepSize << __E__;
1491 
1492  doubleDimensionParameters.back().emplace(std::make_pair(
1493  argPieces[0],
1494  std::make_pair(
1495  startValue /*current value*/,
1496  std::make_pair(startValue /*initial value*/,
1497  stepSize /*step value*/))));
1498  }
1499  else
1500  {
1501  // handle as long
1502  //__GEN_COUT__ << "Long found" << __E__;
1503 
1504  long int startValue;
1505  long int stepSize;
1506 
1507  StringMacros::getNumber(argPieces[1], startValue);
1508  StringMacros::getNumber(argPieces[2], stepSize);
1509 
1510  __GEN_COUTV__(startValue);
1511  __GEN_COUTV__(stepSize);
1512 
1513  __GEN_COUT__ << "Creating long argument '" << argPieces[0]
1514  << "' := " << startValue << ", " << stepSize
1515  << __E__;
1516 
1517  longDimensionParameters.back().emplace(std::make_pair(
1518  argPieces[0],
1519  std::make_pair(
1520  startValue /*current value*/,
1521  std::make_pair(startValue /*initial value*/,
1522  stepSize /*step value*/))));
1523  }
1524 
1525  } // end dimensional argument loop
1526 
1527  } // end dimensions loop
1528 
1529  if(dimensionIterations.size() != longDimensionParameters.size() ||
1530  dimensionIterations.size() != doubleDimensionParameters.size() ||
1531  dimensionIterations.size() != stringDimensionParameters.size())
1532  {
1533  __GEN_SS__ << "Impossible vector size mismatch! "
1534  << dimensionIterations.size() << " - "
1535  << longDimensionParameters.size() << " - "
1536  << doubleDimensionParameters.size() << " - "
1537  << stringDimensionParameters.size() << __E__;
1538  __GEN_SS_THROW__;
1539  }
1540 
1541  // output header
1542  {
1543  std::stringstream outSS;
1544  {
1545  outSS << "\n==========================\n" << __E__;
1546  outSS << "FEMacro '" << feMacro.feMacroName_
1547  << "' multi-dimensional scan..." << __E__;
1548  outSS << "\t" << StringMacros::getTimestampString() << __E__;
1549  outSS << "\t" << dimensionIterations.size()
1550  << " dimensions defined." << __E__;
1551  for(unsigned int i = 0; i < dimensionIterations.size(); ++i)
1552  {
1553  outSS << "\t\t"
1554  << "dimension[" << i << "] has "
1555  << dimensionIterations[i] << " iterations and "
1556  << (longDimensionParameters[i].size() +
1557  doubleDimensionParameters[i].size() +
1558  stringDimensionParameters[i].size())
1559  << " arguments." << __E__;
1560 
1561  for(auto& param : longDimensionParameters[i])
1562  outSS << "\t\t\t"
1563  << "'" << param.first << "' of type long with "
1564  << "initial value and step value [decimal] = "
1565  << "\t" << param.second.second.first << " & "
1566  << param.second.second.second << __E__;
1567 
1568  for(auto& param : doubleDimensionParameters[i])
1569  outSS << "\t\t\t"
1570  << "'" << param.first << "' of type double with "
1571  << "initial value and step value = "
1572  << "\t" << param.second.second.first << " & "
1573  << param.second.second.second << __E__;
1574 
1575  for(auto& param : stringDimensionParameters[i])
1576  outSS << "\t\t\t"
1577  << "'" << param.first << "' of type string with "
1578  << "value = "
1579  << "\t" << param.second << __E__;
1580  }
1581 
1582  outSS << "\nHere are the identified input arguments:" << __E__;
1583  for(unsigned int i = 0; i < feMacro.namesOfInputArguments_.size();
1584  ++i)
1585  outSS << "\t" << feMacro.namesOfInputArguments_[i] << __E__;
1586  outSS << "\nHere are the identified input arguments:" << __E__;
1587  for(unsigned int i = 0;
1588  i < feMacro.namesOfOutputArguments_.size();
1589  ++i)
1590  outSS << "\t" << feMacro.namesOfOutputArguments_[i] << __E__;
1591 
1592  outSS << "\n==========================\n" << __E__;
1593  } // end outputs stringstream results
1594 
1595  // if enabled to save to file, do it.
1596  __GEN_COUT__ << "\n" << outSS.str();
1597  if(outputFilePointer)
1598  fprintf(outputFilePointer, "%s", outSS.str().c_str());
1599  } // end output header
1600 
1601  unsigned int iterationCount = 0;
1602 
1603  // Use lambda recursive function to do arbitrary dimensions
1604  //
1605  // Note: can not do lambda recursive function if using auto to declare the
1606  // function, and must capture reference to the function. Also, must
1607  // capture specialFolders reference for use internally (const values
1608  // already are captured).
1609  std::function<void(const unsigned int /*dimension*/
1610  )>
1611  localRecurse = [&dimensionIterations,
1612  &dimensionIterationCnt,
1613  &iterationCount,
1614  &longDimensionParameters,
1615  &doubleDimensionParameters,
1616  &stringDimensionParameters,
1617  &fe,
1618  &feMacro,
1619  &outputFilePointer,
1620  &argsIn,
1621  &argsOut,
1622  &localRecurse](const unsigned int dimension) {
1623  // create local message facility subject
1624  std::string mfSubject_ = "multiD-" + std::to_string(dimension) +
1625  "-" + feMacro.feMacroName_;
1626  __GEN_COUTV__(dimension);
1627 
1628  if(dimension >= dimensionIterations.size())
1629  {
1630  __GEN_COUT__ << "Iteration count: " << iterationCount++
1631  << __E__;
1632  __GEN_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_
1633  << "' ..." << __E__;
1634 
1635  // set argsIn to current value
1636 
1637  // scan all dimension parameter objects
1638  // note: Although conflicts should not be allowed
1639  // at this point, lower dimensions will have priority
1640  // over higher dimension with same name argument.. and
1641  // longs will have priority over doubles
1642 
1643  bool foundAsLong;
1644  for(unsigned int i = 0; i < argsIn.size(); ++i)
1645  {
1646  foundAsLong = false;
1647  for(unsigned int j = 0; j < dimensionIterations.size();
1648  ++j)
1649  {
1650  auto longIt =
1651  longDimensionParameters[j].find(argsIn[i].first);
1652  if(longIt == longDimensionParameters[j].end())
1653  continue;
1654 
1655  // else found long!
1656  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1657  << "' to current long value '"
1658  << longIt->second.first
1659  << "' from dimension " << j
1660  << " parameter." << __E__;
1661  argsIn[i].second =
1662  std::to_string(longIt->second.first);
1663  foundAsLong = true;
1664  break;
1665  } // end long loop
1666 
1667  if(foundAsLong)
1668  {
1669  continue; // skip double check
1670  }
1671 
1672  for(unsigned int j = 0; j < dimensionIterations.size();
1673  ++j)
1674  {
1675  auto doubleIt = doubleDimensionParameters[j].find(
1676  argsIn[i].first);
1677  if(doubleIt == doubleDimensionParameters[j].end())
1678  continue;
1679 
1680  // else found long!
1681  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1682  << "' to current double value '"
1683  << doubleIt->second.first
1684  << "' from dimension " << j
1685  << " parameter." << __E__;
1686  argsIn[i].second =
1687  std::to_string(doubleIt->second.first);
1688  foundAsLong = true;
1689  break;
1690  } // end double loop
1691 
1692  if(foundAsLong)
1693  {
1694  continue; // skip double check
1695  }
1696 
1697  for(unsigned int j = 0; j < dimensionIterations.size();
1698  ++j)
1699  {
1700  auto stringIt = stringDimensionParameters[j].find(
1701  argsIn[i].first);
1702  if(stringIt == stringDimensionParameters[j].end())
1703  continue;
1704 
1705  // else found long!
1706  __GEN_COUT__ << "Assigning argIn '" << argsIn[i].first
1707  << "' to current string value '"
1708  << stringIt->second
1709  << "' from dimension " << j
1710  << " parameter." << __E__;
1711  argsIn[i].second = stringIt->second;
1712  foundAsLong = true;
1713  break;
1714  } // end double loop
1715 
1716  if(foundAsLong)
1717  {
1718  continue; // skip double check
1719  }
1720 
1721  __GEN_SS__ << "ArgIn '" << argsIn[i].first
1722  << "' was not assigned a value "
1723  << "by any dimensional loop parameter sets. "
1724  "This is illegal. FEMacro '"
1725  << feMacro.feMacroName_ << "' requires '"
1726  << argsIn[i].first
1727  << "' as an input argument. Either remove the "
1728  "input argument from this FEMacro, "
1729  << "or define a value as a dimensional loop "
1730  "parameter."
1731  << __E__;
1732  __GEN_SS_THROW__;
1733  } // done building argsIn
1734 
1735  // have pointer to Macro structure, so run it
1736  (fe->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut);
1737 
1738  __GEN_COUT__ << "FE Macro complete!" << __E__;
1739 
1740  // output results
1741  {
1742  std::stringstream outSS;
1743  {
1744  outSS << "\n---------------\n" << __E__;
1745  outSS << "FEMacro '" << feMacro.feMacroName_
1746  << "' execution..." << __E__;
1747  outSS << "\t"
1748  << "iteration " << iterationCount << __E__;
1749  for(unsigned int i = 0;
1750  i < dimensionIterationCnt.size();
1751  ++i)
1752  outSS << "\t"
1753  << "dimension[" << i
1754  << "] index := " << dimensionIterationCnt[i]
1755  << __E__;
1756 
1757  outSS << "\n"
1758  << "\t"
1759  << "Input arguments (count: " << argsIn.size()
1760  << "):" << __E__;
1761  for(auto& argIn : argsIn)
1762  outSS << "\t\t" << argIn.first << " = "
1763  << argIn.second << __E__;
1764 
1765  outSS << "\n"
1766  << "\t"
1767  << "Output arguments (count: " << argsOut.size()
1768  << "):" << __E__;
1769  for(auto& argOut : argsOut)
1770  outSS << "\t\t" << argOut.first << " = "
1771  << argOut.second << __E__;
1772  } // end outputs stringstream results
1773 
1774  // if enabled to save to file, do it.
1775  __GEN_COUT__ << "\n" << outSS.str();
1776  if(outputFilePointer)
1777  fprintf(outputFilePointer, "%s", outSS.str().c_str());
1778  } // end output results
1779 
1780  return;
1781  }
1782 
1783  // init dimension index
1784  if(dimension >= dimensionIterationCnt.size())
1785  dimensionIterationCnt.push_back(0);
1786 
1787  // if enabled to save to file, do it.
1788  __GEN_COUT__ << "\n"
1789  << "======================================" << __E__
1790  << "dimension[" << dimension
1791  << "] number of iterations := "
1792  << dimensionIterations[dimension] << __E__;
1793 
1794  // update current value to initial value for this dimension's
1795  // parameters
1796  {
1797  for(auto& longPair : longDimensionParameters[dimension])
1798  {
1799  longPair.second.first = // reset to initial value
1800  longPair.second.second.first;
1801  __GEN_COUT__
1802  << "arg '" << longPair.first
1803  << "' current value: " << longPair.second.first
1804  << __E__;
1805  } // end long loop
1806 
1807  for(auto& doublePair : doubleDimensionParameters[dimension])
1808  {
1809  doublePair.second.first = // reset to initial value
1810  doublePair.second.second.first;
1811  __GEN_COUT__
1812  << "arg '" << doublePair.first
1813  << "' current value: " << doublePair.second.first
1814  << __E__;
1815  } // end double loop
1816  } // end update current value to initial value for all
1817  // dimensional parameters
1818 
1819  for(dimensionIterationCnt[dimension] =
1820  0; // reset each time through dimension loop
1821  dimensionIterationCnt[dimension] <
1822  dimensionIterations[dimension];
1823  ++dimensionIterationCnt[dimension])
1824  {
1825  __GEN_COUT__ << "dimension[" << dimension << "] index := "
1826  << dimensionIterationCnt[dimension] << __E__;
1827 
1828  localRecurse(dimension + 1);
1829 
1830  // update current value to next value for this dimension's
1831  // parameters
1832  {
1833  for(auto& longPair : longDimensionParameters[dimension])
1834  {
1835  longPair.second.first += // add step value
1836  longPair.second.second.second;
1837  __GEN_COUT__
1838  << "arg '" << longPair.first
1839  << "' current value: " << longPair.second.first
1840  << __E__;
1841  } // end long loop
1842 
1843  for(auto& doublePair :
1844  doubleDimensionParameters[dimension])
1845  {
1846  doublePair.second.first += // add step value
1847  doublePair.second.second.second;
1848 
1849  __GEN_COUT__
1850  << "arg '" << doublePair.first
1851  << "' current value: " << doublePair.second.first
1852  << __E__;
1853  } // end double loop
1854  } // end update current value to next value for all
1855  // dimensional parameters
1856  }
1857  __GEN_COUT__ << "Completed dimension[" << dimension
1858  << "] number of iterations := "
1859  << dimensionIterationCnt[dimension] << " of "
1860  << dimensionIterations[dimension] << __E__;
1861  }; // end local lambda recursive function
1862 
1863  // launch multi-dimensional recursion
1864  localRecurse(0);
1865 
1866  // close output file
1867  if(outputFilePointer)
1868  fclose(outputFilePointer);
1869  }
1870  catch(const std::runtime_error& e)
1871  {
1872  __SS__ << "Error executing multi-dimensional FE Macro: " << e.what()
1873  << __E__;
1874  statusResult = ss.str();
1875  }
1876  catch(...)
1877  {
1878  __SS__ << "Unknown error executing multi-dimensional FE Macro. " << __E__;
1879  try
1880  {
1881  throw;
1882  } //one more try to printout extra info
1883  catch(const std::exception& e)
1884  {
1885  ss << "Exception message: " << e.what();
1886  }
1887  catch(...)
1888  {
1889  }
1890  statusResult = ss.str();
1891  }
1892 
1893  __COUTV__(statusResult);
1894 
1895  { // lock mutex scope
1896  std::lock_guard<std::mutex> lock(feMgr->macroMultiDimensionalDoneMutex_);
1897  // change status at completion
1898  feMgr->macroMultiDimensionalStatusMap_[interfaceID] = statusResult;
1899  }
1900  }, // end thread()
1901  this,
1902  interfaceID,
1903  feMacroName,
1904  enableSavingOutput,
1905  outputFilePath,
1906  outputFileRadix,
1907  inputArgs)
1908  .detach();
1909 
1910  __CFG_COUT__ << "Started multi-dimensional FE Macro '" << feMacroName
1911  << "' for interface '" << interfaceID << ".'" << __E__;
1912 
1913 } // end startFEMacroMultiDimensional()
1914 
1915 //==============================================================================
1922 bool FEVInterfacesManager::checkMacroMultiDimensional(const std::string& interfaceID,
1923  const std::string& macroName,
1924  std::string* outputFile)
1925 {
1926  // check active(only one FE Macro per interface active at any time, for now)
1927  // lock mutex scope
1928  std::lock_guard<std::mutex> lock(macroMultiDimensionalDoneMutex_);
1929  // check status
1930  auto statusIt = macroMultiDimensionalStatusMap_.find(interfaceID);
1931  if(statusIt == macroMultiDimensionalStatusMap_.end())
1932  {
1933  __CFG_SS__ << "Status missing for multi-dimensional launch of Macro '"
1934  << macroName << "' for interface '" << interfaceID << ".'" << __E__;
1935  __CFG_SS_THROW__;
1936  }
1937  else if(statusIt->second == "Done")
1938  {
1939  __CFG_COUT__ << "Completed multi-dimensional launch of Macro '" << macroName
1940  << "' for interface '" << interfaceID << ".'" << __E__;
1941 
1942  // hand back the saved-output file path (if any) and forget it
1943  auto fileIt = macroMultiDimensionalOutputFileMap_.find(interfaceID);
1944  if(outputFile)
1945  *outputFile = (fileIt != macroMultiDimensionalOutputFileMap_.end())
1946  ? fileIt->second
1947  : std::string();
1948  if(fileIt != macroMultiDimensionalOutputFileMap_.end())
1950 
1951  // erase from map
1952  macroMultiDimensionalStatusMap_.erase(statusIt);
1953  return true;
1954  }
1955  else if(statusIt->second == "Active")
1956  {
1957  __CFG_COUT__ << "Still running multi-dimensional launch of Macro '" << macroName
1958  << "' for interface '" << interfaceID << ".'" << __E__;
1959  return false;
1960  }
1961  // else //assume error
1962 
1963  __CFG_SS__ << "Error occured during multi-dimensional launch of Macro '" << macroName
1964  << "' for interface '" << interfaceID << "':" << statusIt->second << __E__;
1965  __CFG_SS_THROW__;
1966 
1967 } // end checkMacroMultiDimensional()
1968 
1969 //==============================================================================
1981 void FEVInterfacesManager::runFEMacroByFE(const std::string& callingInterfaceID,
1982  const std::string& interfaceID,
1983  const std::string& feMacroName,
1984  const std::string& inputArgs,
1985  std::string& outputArgs)
1986 {
1987  __CFG_COUTV__(callingInterfaceID);
1988 
1989  // check for interfaceID
1990  FEVInterface* fe = getFEInterfaceP(interfaceID);
1991 
1992  // have pointer to virtual FEInterface, find Macro structure
1993  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1994  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1995  {
1996  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
1997  << "' was not found!" << __E__;
1998  ss << "\nHere is the list of available FE Macros:\n";
1999  for(const auto& feMacro : fe->getMapOfFEMacroFunctions())
2000  ss << feMacro.first << "... ";
2001  ss << __E__;
2002  __CFG_COUT_ERR__ << "\n" << ss.str();
2003  __CFG_SS_THROW__;
2004  }
2005 
2006  const FEVInterface::frontEndMacroStruct_t& feMacro = FEMacroIt->second;
2007 
2008  std::set<std::string> allowedFEsSet;
2009  StringMacros::getSetFromString(feMacro.allowedCallingFrontEnds_, allowedFEsSet);
2010 
2011  // check if calling interface is allowed to call macro
2012  if(!StringMacros::inWildCardSet(callingInterfaceID, allowedFEsSet))
2013  {
2014  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
2015  << "' does not allow access to calling interfaceID '"
2016  << callingInterfaceID
2017  << "!' Did the interface add the calling interfaceID "
2018  << "to the access list when registering the front-end macro." << __E__;
2019  __CFG_COUT_ERR__ << "\n" << ss.str();
2020  __CFG_SS_THROW__;
2021  }
2022 
2023  // if here, then access allowed
2024  // build output args list
2025 
2026  outputArgs = "";
2027 
2028  for(unsigned int i = 0; i < feMacro.namesOfOutputArguments_.size(); ++i)
2029  outputArgs += (i ? "," : "") + feMacro.namesOfOutputArguments_[i];
2030 
2031  __CFG_COUTV__(outputArgs);
2032 
2033  runFEMacro(interfaceID, feMacro, inputArgs, outputArgs);
2034 
2035  __CFG_COUTV__(outputArgs);
2036 
2037 } // end runFEMacroByFE()
2038 
2039 //==============================================================================
2050 void FEVInterfacesManager::runMacro(const std::string& interfaceID,
2051  const std::string& macroObjectString,
2052  const std::string& inputArgs,
2053  std::string& outputArgs)
2054 {
2055  //-------------------------------
2056  // extract macro object
2057  FEVInterface::macroStruct_t macro(macroObjectString);
2058 
2059  // check for interfaceID
2060  FEVInterface* fe = getFEInterfaceP(interfaceID);
2061 
2062  // build input arguments
2063  // parse args, semicolon-separated pairs, and then comma-separated
2064  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
2065  {
2066  std::istringstream inputStream(inputArgs);
2067  std::string splitVal, argName, argValue;
2068  while(getline(inputStream, splitVal, ';'))
2069  {
2070  std::istringstream pairInputStream(splitVal);
2071  getline(pairInputStream, argName, ',');
2072  getline(pairInputStream, argValue, ',');
2073  argsIn.push_back(std::make_pair(argName, argValue));
2074  }
2075  }
2076 
2077  // check namesOfInputArguments_
2078  if(macro.namesOfInputArguments_.size() != argsIn.size())
2079  {
2080  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
2081  << "' was attempted on interfaceID '" << interfaceID
2082  << "' with a mismatch in"
2083  << " number of input arguments. " << argsIn.size() << " were given. "
2084  << macro.namesOfInputArguments_.size() << " expected." << __E__;
2085  __CFG_SS_THROW__;
2086  }
2087  for(unsigned int i = 0; i < argsIn.size(); ++i)
2088  if(macro.namesOfInputArguments_.find(argsIn[i].first) ==
2089  macro.namesOfInputArguments_.end())
2090  {
2091  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
2092  << "' was attempted on interfaceID '" << interfaceID
2093  << "' with a mismatch in"
2094  << " a name of an input argument. " << argsIn[i].first
2095  << " was given. Expected: "
2096  << StringMacros::setToString(macro.namesOfInputArguments_)
2097  << __E__;
2098 
2099  __CFG_SS_THROW__;
2100  }
2101 
2102  // build output arguments
2103  std::vector<std::string> returnStrings;
2104  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
2105 
2106  {
2107  std::istringstream inputStream(outputArgs);
2108  std::string argName;
2109  while(getline(inputStream, argName, ','))
2110  {
2111  __CFG_COUT__ << "argName " << argName << __E__;
2112 
2113  returnStrings.push_back("DEFAULT"); // std::string());
2114  argsOut.push_back(FEVInterface::frontEndMacroArg_t(
2115  argName, returnStrings[returnStrings.size() - 1]));
2116  //
2117  // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__;
2118  //__CFG_COUT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1])
2119  // << __E__;
2120  }
2121  }
2122 
2123  // check namesOfOutputArguments_
2124  if(macro.namesOfOutputArguments_.size() != argsOut.size())
2125  {
2126  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
2127  << "' was attempted on interfaceID '" << interfaceID
2128  << "' with a mismatch in"
2129  << " number of output arguments. " << argsOut.size() << " were given. "
2130  << macro.namesOfOutputArguments_.size() << " expected." << __E__;
2131 
2132  __CFG_SS_THROW__;
2133  }
2134  for(unsigned int i = 0; i < argsOut.size(); ++i)
2135  if(macro.namesOfOutputArguments_.find(argsOut[i].first) ==
2136  macro.namesOfOutputArguments_.end())
2137  {
2138  __CFG_SS__ << "MacroMaker Macro '" << macro.macroName_
2139  << "' was attempted on interfaceID '" << interfaceID
2140  << "' with a mismatch in"
2141  << " a name of an output argument. " << argsOut[i].first
2142  << " were given. Expected: "
2143  << StringMacros::setToString(macro.namesOfOutputArguments_)
2144  << __E__;
2145 
2146  __CFG_SS_THROW__;
2147  }
2148 
2149  __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__;
2150 
2151  std::map<std::string /*name*/, uint64_t /*value*/> variableMap;
2152  // fill variable map
2153  for(const auto& outputArgName : macro.namesOfOutputArguments_)
2154  variableMap.emplace( // do not care about output arg value
2155  std::pair<std::string /*name*/, uint64_t /*value*/>(outputArgName, 0));
2156  for(const auto& inputArgName : macro.namesOfInputArguments_)
2157  variableMap.emplace( // do not care about input arg value
2158  std::pair<std::string /*name*/, uint64_t /*value*/>(inputArgName, 0));
2159 
2160  for(auto& argIn : argsIn) // set map values
2161  {
2162  __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__;
2163  StringMacros::getNumber(argIn.second, variableMap.at(argIn.first));
2164  }
2165 
2166  fe->runMacro(macro, variableMap);
2167 
2168  __CFG_COUT__ << "MacroMaker Macro complete!" << __E__;
2169 
2170  __CFG_COUT__ << "# of output args = " << argsOut.size() << __E__;
2171  for(auto& arg : argsOut)
2172  {
2173  std::stringstream numberSs;
2174  numberSs << std::dec << variableMap.at(arg.first) << " (0x" << std::hex
2175  << variableMap.at(arg.first) << ")" << std::dec;
2176  arg.second = numberSs.str();
2177  __CFG_COUT__ << arg.first << ": " << arg.second << __E__;
2178  }
2179 
2180  // Success! at this point so return the output string
2181  outputArgs = "";
2182  for(unsigned int i = 0; i < argsOut.size(); ++i)
2183  {
2184  if(i)
2185  outputArgs += ";";
2186  outputArgs += argsOut[i].first + "," + argsOut[i].second;
2187  }
2188 
2189  __CFG_COUT__ << "outputArgs = " << outputArgs << __E__;
2190 
2191 } // end runMacro()
2192 
2193 //==============================================================================
2204 void FEVInterfacesManager::runFEMacro(const std::string& interfaceID,
2205  const std::string& feMacroName,
2206  const std::string& inputArgs,
2207  std::string& outputArgs)
2208 {
2209  // check for interfaceID
2210  FEVInterface* fe = getFEInterfaceP(interfaceID);
2211 
2212  // have pointer to virtual FEInterface, find Macro structure
2213  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
2214  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
2215  {
2216  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
2217  << "' was not found!" << __E__;
2218  __CFG_COUT_ERR__ << "\n" << ss.str();
2219  __CFG_SS_THROW__;
2220  }
2221 
2222  runFEMacro(interfaceID, FEMacroIt->second, inputArgs, outputArgs);
2223 
2224 } // end runFEMacro()
2225 
2226 //==============================================================================
2237 void FEVInterfacesManager::runFEMacro(const std::string& interfaceID,
2238  const FEVInterface::frontEndMacroStruct_t& feMacro,
2239  const std::string& inputArgs,
2240  std::string& outputArgs)
2241 {
2242  __CFG_COUTV__(inputArgs);
2243 
2244  // build input arguments
2245  // parse args, semicolon-separated pairs, and then comma-separated
2246  std::vector<FEVInterface::frontEndMacroArg_t> argsIn;
2247  {
2248  std::istringstream inputStream(inputArgs);
2249  std::string splitVal, argName, argValue;
2250  while(getline(inputStream, splitVal, ';'))
2251  {
2252  std::istringstream pairInputStream(splitVal);
2253  getline(pairInputStream, argName, ',');
2254  getline(pairInputStream, argValue, ',');
2255  argsIn.push_back(std::make_pair(StringMacros::decodeURIComponent(argName),
2257  }
2258  }
2259 
2260  // check namesOfInputArguments_
2261  if(feMacro.namesOfInputArguments_.size() != argsIn.size())
2262  {
2263  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2264  << interfaceID << "' was attempted with a mismatch in"
2265  << " number of input arguments. " << argsIn.size() << " were given. "
2266  << feMacro.namesOfInputArguments_.size() << " expected." << __E__;
2267  __CFG_COUT_ERR__ << "\n" << ss.str();
2268  __CFG_SS_THROW__;
2269  }
2270  //check input arg names and ignore after ( to allow Defaults/Notes to change over time, while not breaking user history
2271  for(unsigned int i = 0; i < argsIn.size(); ++i)
2272  if(argsIn[i].first.substr(0, argsIn[i].first.find('(')) !=
2273  feMacro.namesOfInputArguments_[i].substr(
2274  0, feMacro.namesOfInputArguments_[i].find('(')))
2275  {
2276  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2277  << interfaceID << "' was attempted with a mismatch in"
2278  << " a name of an input argument. '" << argsIn[i].first
2279  << "' was given. '" << feMacro.namesOfInputArguments_[i]
2280  << "' expected." << __E__;
2281  __CFG_COUT_ERR__ << "\n" << ss.str();
2282  __CFG_SS_THROW__;
2283  }
2284 
2285  // build output arguments
2286  std::vector<std::string> returnStrings;
2287  std::vector<FEVInterface::frontEndMacroArg_t> argsOut;
2288 
2289  const std::string ARG_OUT_DEFAULT = "DEFAULT";
2290 
2291  {
2292  std::istringstream inputStream(outputArgs);
2293  std::string argName;
2294  while(getline(inputStream, argName, ','))
2295  {
2296  __CFG_COUTT__ << "argName " << argName << __E__;
2297 
2298  returnStrings.push_back(ARG_OUT_DEFAULT); // std::string());
2299  argsOut.push_back(FEVInterface::frontEndMacroArg_t(
2301  returnStrings[returnStrings.size() - 1]));
2302  //
2303  // __CFG_COUT__ << argsOut[argsOut.size()-1].first << __E__;
2304  __CFG_COUTT__ << (uint64_t) & (returnStrings[returnStrings.size() - 1])
2305  << __E__;
2306  }
2307  }
2308 
2309  // check namesOfOutputArguments_
2310  if(feMacro.namesOfOutputArguments_.size() != argsOut.size())
2311  {
2312  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2313  << interfaceID << "' was attempted with a mismatch in"
2314  << " number of output arguments. " << argsOut.size() << " were given. "
2315  << feMacro.namesOfOutputArguments_.size() << " expected." << __E__;
2316  __CFG_COUT_ERR__ << "\n" << ss.str();
2317  __CFG_SS_THROW__;
2318  }
2319  for(unsigned int i = 0; i < argsOut.size(); ++i)
2320  if(argsOut[i].first != feMacro.namesOfOutputArguments_[i])
2321  {
2322  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2323  << interfaceID << "' was attempted with a mismatch in"
2324  << " a name of an output argument. " << argsOut[i].first
2325  << " were given. " << feMacro.namesOfOutputArguments_[i]
2326  << " expected." << __E__;
2327  __CFG_COUT_ERR__ << "\n" << ss.str();
2328  __CFG_SS_THROW__;
2329  }
2330 
2331  //always add built-in special output args -----------
2332  const uint16_t BUILT_IN_ARGOUT_COUNT = 1;
2333  {
2334  returnStrings.push_back(ARG_OUT_DEFAULT); // std::string());
2335  argsOut.push_back(FEVInterface::frontEndMacroArg_t(
2336  PLOTLY_PLOT, returnStrings[returnStrings.size() - 1]));
2337  } //end always add built-in special output args -----------
2338 
2339  __CFG_COUT__ << "# of input args = " << argsIn.size() << __E__;
2340  for(auto& argIn : argsIn)
2341  __CFG_COUT__ << argIn.first << ": " << argIn.second << __E__;
2342 
2343  __CFG_COUT__ << "Launching FE Macro '" << feMacro.feMacroName_ << "' ..." << __E__;
2344  // have pointer to Macro structure, so run it
2345  (getFEInterfaceP(interfaceID)->*(feMacro.macroFunction_))(feMacro, argsIn, argsOut);
2346 
2347  __CFG_COUT__ << "FE Macro complete!" << __E__;
2348 
2349  __CFG_COUT__ << "# of output args = " << argsOut.size() << " including "
2350  << BUILT_IN_ARGOUT_COUNT << " built-in args." << __E__;
2351  for(const auto& arg : argsOut)
2352  __CFG_COUT__ << arg.first << ": " << arg.second << __E__;
2353 
2354  // check namesOfOutputArguments_ size
2355  if(feMacro.namesOfOutputArguments_.size() != argsOut.size() - BUILT_IN_ARGOUT_COUNT)
2356  {
2357  __CFG_SS__ << "FE Macro '" << feMacro.feMacroName_ << "' of interfaceID '"
2358  << interfaceID
2359  << "' was attempted but the FE macro "
2360  "manipulated the output arguments vector. It is illegal "
2361  "to add or remove output vector name/value pairs."
2362  << __E__;
2363  __CFG_COUT_ERR__ << "\n" << ss.str();
2364  __CFG_SS_THROW__;
2365  }
2366 
2367  // Success! at this point so return the output string
2368  outputArgs = "";
2369  bool first = true;
2370  for(unsigned int i = 0; i < argsOut.size(); ++i)
2371  {
2372  if(i >= argsOut.size() -
2373  BUILT_IN_ARGOUT_COUNT && //remove built-in args if DEFAULT
2374  argsOut[i].second == ARG_OUT_DEFAULT)
2375  continue;
2376 
2377  if(!first)
2378  outputArgs += ";";
2379  else
2380  first = false;
2381 
2382  // attempt to get number, and output hex version
2383  // otherwise just output result
2384  try
2385  {
2386  uint64_t tmpNumber;
2387  if(StringMacros::getNumber(argsOut[i].second, tmpNumber))
2388  {
2389  std::stringstream outNumberSs;
2390  outNumberSs << std::dec << tmpNumber << " (0x" << std::hex << tmpNumber
2391  << ")" << std::dec;
2392  outputArgs += StringMacros::encodeURIComponent(argsOut[i].first) + "," +
2393  outNumberSs.str();
2394  continue;
2395  }
2396  }
2397  catch(...)
2398  { // ignore error, assume not a number
2399  }
2400 
2401  outputArgs += StringMacros::encodeURIComponent(argsOut[i].first) + "," +
2402  StringMacros::encodeURIComponent(argsOut[i].second);
2403  }
2404 
2405  __CFG_COUTT__ << "outputArgs = " << outputArgs << __E__;
2406 
2407 } // end runFEMacro()
2408 
2409 //==============================================================================
2418 std::string FEVInterfacesManager::getFEMacrosString(const std::string& supervisorName,
2419  const std::string& supervisorLid)
2420 {
2421  std::string retList = "";
2422 
2423  __CFG_COUTV__(theFEInterfaces_.size());
2424 
2425  for(const auto& it : theFEInterfaces_)
2426  {
2427  __CFG_COUTT__ << "FE interface UID = " << it.first << __E__;
2428 
2429  retList += supervisorName + ";" + supervisorLid + ";" +
2430  it.second->getInterfaceType() + ";" + it.second->getInterfaceUID();
2431 
2432  for(const auto& macroPair : it.second->getMapOfFEMacroFunctions())
2433  {
2434  __CFG_COUTT__ << "FE Macro name = " << macroPair.first << __E__;
2435  retList +=
2436  ";" + macroPair.first + ";" + macroPair.second.requiredUserPermissions_;
2437  retList +=
2438  ";" + StringMacros::encodeURIComponent(macroPair.second.feMacroTooltip_);
2439 
2440  retList +=
2441  ";" + std::to_string(macroPair.second.namesOfInputArguments_.size());
2442  for(const auto& name : macroPair.second.namesOfInputArguments_)
2443  retList += ";" + StringMacros::encodeURIComponent(name);
2444 
2445  retList +=
2446  ";" + std::to_string(macroPair.second.namesOfOutputArguments_.size());
2447  for(const auto& name : macroPair.second.namesOfOutputArguments_)
2448  retList += ";" + StringMacros::encodeURIComponent(name);
2449  }
2450 
2451  retList += "\n";
2452  }
2453  return retList;
2454 }
2455 
2456 //==============================================================================
2460 std::map<std::string, std::string> FEVInterfacesManager::getFEMacroInputDefaults(
2461  const std::string& interfaceID,
2462  const std::string& feMacroName,
2463  const std::string& inputArgs)
2464 {
2465  FEVInterface* fe = getFEInterfaceP(interfaceID);
2466  auto macroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
2467  if(macroIt == fe->getMapOfFEMacroFunctions().end())
2468  {
2469  __CFG_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '" << interfaceID
2470  << "' was not found." << __E__;
2471  __CFG_SS_THROW__;
2472  }
2473 
2474  std::map<std::string, std::string> currentInputValues;
2475  if(!inputArgs.empty())
2476  {
2477  std::istringstream inputStream(inputArgs);
2478  std::string splitValue;
2479  while(getline(inputStream, splitValue, ';'))
2480  {
2481  std::istringstream pairInputStream(splitValue);
2482  std::string encodedName, encodedValue;
2483  getline(pairInputStream, encodedName, ',');
2484  getline(pairInputStream, encodedValue, ',');
2485 
2486  const std::string inputName = StringMacros::decodeURIComponent(encodedName);
2487  const std::string inputValue = StringMacros::decodeURIComponent(encodedValue);
2488  if(inputName.empty())
2489  continue;
2490 
2491  // Match on the name before any "(Default/Note)" suffix, the same rule
2492  // runFEMacro() uses, so saved history whose suffix has since changed is
2493  // still accepted; key the map by the CURRENT declared name for the provider.
2494  const std::string inputBase = inputName.substr(0, inputName.find('('));
2495  const std::string* declaredName = nullptr;
2496  for(const auto& candidate : macroIt->second.namesOfInputArguments_)
2497  if(candidate.substr(0, candidate.find('(')) == inputBase)
2498  {
2499  declaredName = &candidate;
2500  break;
2501  }
2502  if(!declaredName)
2503  {
2504  __CFG_SS__ << "Dynamic default request for FE Macro '" << feMacroName
2505  << "' of interfaceID '" << interfaceID
2506  << "' included undeclared input name '" << inputName << "'."
2507  << __E__;
2508  __CFG_SS_THROW__;
2509  }
2510  currentInputValues[*declaredName] = inputValue;
2511  }
2512  }
2513 
2514  auto defaults = fe->getFEMacroInputDefaults(feMacroName, currentInputValues);
2515  for(const auto& defaultValue : defaults)
2516  {
2517  bool declaredInput = false;
2518  for(const auto& inputName : macroIt->second.namesOfInputArguments_)
2519  if(inputName == defaultValue.first)
2520  {
2521  declaredInput = true;
2522  break;
2523  }
2524 
2525  if(!declaredInput)
2526  {
2527  __CFG_SS__ << "Dynamic default provider for FE Macro '" << feMacroName
2528  << "' of interfaceID '" << interfaceID
2529  << "' returned undeclared input name '" << defaultValue.first
2530  << "'." << __E__;
2531  __CFG_SS_THROW__;
2532  }
2533  }
2534  return defaults;
2535 }
2536 
2537 //==============================================================================
2539 {
2540  bool allFEWorkloopsAreDone = true;
2541  bool isActive;
2542 
2543  for(const auto& FEInterface : theFEInterfaces_)
2544  {
2545  isActive = FEInterface.second->WorkLoop::isActive();
2546 
2547  __CFG_COUT__ << FEInterface.second->getInterfaceUID() << " of type "
2548  << FEInterface.second->getInterfaceType() << ": \t"
2549  << "workLoop_->isActive() " << (isActive ? "yes" : "no") << __E__;
2550 
2551  if(isActive) // then not done
2552  {
2553  allFEWorkloopsAreDone = false;
2554  break;
2555  }
2556  }
2557 
2558  return allFEWorkloopsAreDone;
2559 } // end allFEWorkloopsAreDone()
2560 
2561 //==============================================================================
2562 void FEVInterfacesManager::preStateMachineExecutionLoop(void)
2563 {
2564  VStateMachine::clearSubsystemIterationWork();
2565  VStateMachine::clearIterationWork();
2566  VStateMachine::clearSubIterationWork();
2567 
2568  stateMachinesIterationWorkCount_ = 0;
2569 
2570  __CFG_COUT__ << "Number of front ends to transition: " << theFENamesByPriority_.size()
2571  << __E__;
2572 
2574  {
2575  // reset map for iterations done on first iteration
2576 
2577  subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index
2578 
2579  stateMachinesIterationDone_.clear();
2580  for(const auto& FEPair : theFEInterfaces_)
2581  stateMachinesIterationDone_[FEPair.first] = false; // init to not done
2582 
2583  stateMachinesWaitingSubsystemIteration_.clear();
2584  lastSubsystemIterationIndexSeen_ = VStateMachine::getSubsystemIterationIndex();
2585  }
2586  else
2587  {
2588  __CFG_COUT__ << "SubsystemIteration "
2589  << VStateMachine::getSubsystemIterationIndexString() << " Iteration "
2590  << VStateMachine::getIterationIndex() << "."
2591  << VStateMachine::getSubIterationIndex() << "("
2592  << (int)subIterationWorkStateMachineIndex_ << ")" << __E__;
2593 
2594  // a new subsystem-iteration re-arms the FEs that asked for it
2595  if(VStateMachine::getSubsystemIterationIndex() !=
2596  lastSubsystemIterationIndexSeen_)
2597  {
2598  lastSubsystemIterationIndexSeen_ =
2599  VStateMachine::getSubsystemIterationIndex();
2600  for(const auto& name : stateMachinesWaitingSubsystemIteration_)
2601  stateMachinesIterationDone_[name] = false;
2602  stateMachinesWaitingSubsystemIteration_.clear();
2603  }
2604  }
2605 } // end preStateMachineExecutionLoop()
2606 
2607 //==============================================================================
2608 void FEVInterfacesManager::preStateMachineExecution(unsigned int i,
2609  const std::string& transitionName)
2610 {
2611  if(i >= theFENamesByPriority_.size())
2612  {
2613  __CFG_SS__ << "FE Interface " << i << " not found!" << __E__;
2614  __CFG_SS_THROW__;
2615  }
2616 
2617  const std::string& name = theFENamesByPriority_[i];
2618 
2619  FEVInterface* fe = getFEInterfaceP(name);
2620 
2621  fe->VStateMachine::setTransitionName(transitionName);
2622  fe->VStateMachine::setSubsystemIterationIndex(
2623  VStateMachine::getSubsystemIterationIndex());
2624  fe->VStateMachine::setIterationIndex(VStateMachine::getIterationIndex());
2625  fe->VStateMachine::setSubIterationIndex(VStateMachine::getSubIterationIndex());
2626  fe->VStateMachine::setSystemMinReadyForEventGenerationStartIteration(
2627  VStateMachine::getSystemMinReadyForEventGenerationStartIteration());
2628 
2629  fe->VStateMachine::clearSubsystemIterationWork();
2630  fe->VStateMachine::clearIterationWork();
2631  fe->VStateMachine::clearSubIterationWork();
2632 
2633  __CFG_COUT__ << "theStateMachineImplementation SubsystemIteration "
2634  << fe->VStateMachine::getSubsystemIterationIndexString() << " Iteration "
2635  << fe->VStateMachine::getIterationIndex() << "."
2636  << fe->VStateMachine::getSubIterationIndex() << __E__;
2637 } // end preStateMachineExecution()
2638 
2639 //==============================================================================
2642 bool FEVInterfacesManager::postStateMachineExecution(unsigned int i)
2643 {
2644  if(i >= theFENamesByPriority_.size())
2645  {
2646  __CFG_SS__ << "FE Interface index " << i << " not found!" << __E__;
2647  __CFG_SS_THROW__;
2648  }
2649 
2650  const std::string& name = theFENamesByPriority_[i];
2651 
2652  FEVInterface* fe = getFEInterfaceP(name);
2653 
2654  // sub-iteration has highest priority
2655  if(fe->VStateMachine::getSubIterationWork())
2656  {
2657  subIterationWorkStateMachineIndex_ = i;
2658  VStateMachine::indicateSubIterationWork();
2659 
2660  __CFG_COUT__ << "FE Interface '" << name
2661  << "' is flagged for another sub-iteration..." << __E__;
2662  return false; // to indicate state machine is NOT done with transition
2663  }
2664 
2665  subIterationWorkStateMachineIndex_ = -1; // clear sub iteration work index
2666 
2667  if(fe->VStateMachine::getIterationWork())
2668  {
2669  // iteration — this FE needs another iteration within this subsystem
2670  stateMachinesIterationDone_[name] = false;
2671  VStateMachine::indicateIterationWork(); // mark not done at
2672  // FEVInterfacesManager level
2673  ++stateMachinesIterationWorkCount_; // increment still working count
2674 
2675  __CFG_COUT__ << "FE Interface '" << name
2676  << "' is flagged for another iteration..." << __E__;
2677  return false; // to indicate state machine is NOT done with transition
2678  }
2679 
2680  if(fe->VStateMachine::getSubsystemIterationWork())
2681  {
2682  // subsystem-iteration — this FE is done with inner iterations
2683  // but needs another cross-subsystem sync barrier
2684  stateMachinesIterationDone_[name] = true; // done with inner iterations
2685  stateMachinesWaitingSubsystemIteration_.insert(name);
2686  VStateMachine::indicateSubsystemIterationWork();
2687 
2688  __CFG_COUT__ << "FE Interface '" << name
2689  << "' is flagged for another subsystem-iteration..." << __E__;
2690  }
2691  else
2692  {
2693  // fully done
2694  stateMachinesIterationDone_[name] = true;
2695  }
2696 
2697  fe->VStateMachine::setTransitionName(""); // clear transition
2698  return true; // to indicate state machine is done with transition
2699 } // end postStateMachineExecution()
2700 
2701 //==============================================================================
2702 void FEVInterfacesManager::postStateMachineExecutionLoop(void)
2703 {
2704  if(VStateMachine::getSubIterationWork())
2705  __CFG_COUT__ << "FE Interface state machine implementation "
2706  << subIterationWorkStateMachineIndex_
2707  << " is flagged for another sub-iteration..." << __E__;
2708  else if(VStateMachine::getIterationWork())
2709  __CFG_COUT__ << stateMachinesIterationWorkCount_
2710  << " FE Interface state machine implementation(s) flagged for "
2711  "another iteration..."
2712  << __E__;
2713  else if(VStateMachine::getSubsystemIterationWork())
2714  __CFG_COUT__ << "FE Interface state machine implementation(s) flagged for "
2715  "another subsystem-iteration (cross-subsystem sync)..."
2716  << __E__;
2717  else
2718  __CFG_COUT__ << "Done transitioning all state machine implementations..."
2719  << __E__;
2720 } // end postStateMachineExecutionLoop()
std::vector< std::string > getChildrenNames(bool byPriority=false, bool onlyStatusTrue=false) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
const std::string & getValueAsString(bool returnLinkTableValue=false) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
void runMacro(FEVInterface::macroStruct_t &macro, std::map< std::string, uint64_t > &variableMap)
runMacro
virtual void configureSlowControls(void)
end State Machine handlers
virtual void configure(void)
Definition: FEVInterface.h:121
virtual std::map< std::string, std::string > getFEMacroInputDefaults(const std::string &, const std::map< std::string, std::string > &) const
Definition: FEVInterface.h:213
virtual void universalRead(char *address, char *returnValue)=0
throw std::runtime_error exception on error/timeout
const FEVInterface & getFEInterface(const std::string &interfaceID) const
getFEInterface
std::string getFEMacrosString(const std::string &supervisorName, const std::string &supervisorLid)
used by MacroMaker
std::mutex macroMultiDimensionalDoneMutex_
multi-dimensional FE Macro helpers
FEVInterface * getFEInterfaceP(const std::string &interfaceID)
getFEInterfaceP
void runFEMacro(const std::string &interfaceID, const FEVInterface::frontEndMacroStruct_t &feMacro, const std::string &inputArgs, std::string &outputArgs)
used by MacroMaker and FE calling indirectly
unsigned int getInterfaceUniversalAddressSize(const std::string &interfaceID)
used by MacroMaker
void startFEMacroMultiDimensional(const std::string &requester, const std::string &interfaceID, const std::string &feMacroName, const bool enableSavingOutput, const std::string &outputFilePath, const std::string &outputFileRadix, const std::string &inputArgs)
used by iterator calling (i.e. FESupervisor)
void universalWrite(const std::string &interfaceID, char *address, char *writeValue)
used by MacroMaker
bool allFEWorkloopsAreDone(void)
used by Iterator, e.g.
std::map< std::string, std::string > macroMultiDimensionalOutputFileMap_
set when saving outputs; guarded by macroMultiDimensionalDoneMutex_
virtual void configure(void) override
State Machine Methods.
void runFEMacroByFE(const std::string &callingInterfaceID, const std::string &interfaceID, const std::string &feMacroName, const std::string &inputArgs, std::string &outputArgs)
used by FE calling (i.e. FESupervisor)
unsigned int getInterfaceUniversalDataSize(const std::string &interfaceID)
used by MacroMaker
void universalRead(const std::string &interfaceID, char *address, char *returnValue)
used by MacroMaker
std::map< std::string, std::string > getFEMacroInputDefaults(const std::string &interfaceID, const std::string &feMacroName, const std::string &inputArgs)
used by MacroMaker
virtual std::string getStatusProgressDetail(void) override
overriding VStateMachine::getStatusProgressDetail
void startMacroMultiDimensional(const std::string &requester, const std::string &interfaceID, const std::string &macroName, const std::string &macroString, const bool enableSavingOutput, const std::string &outputFilePath, const std::string &outputFileRadix, const std::string &inputArgs)
used by iterator calling (i.e. FESupervisor)
void runMacro(const std::string &interfaceID, const std::string &macroObjectString, const std::string &inputArgs, std::string &outputArgs)
used by MacroMaker
std::string getFEListString(const std::string &supervisorLid)
used by MacroMaker
virtual std::string getStatusProgressDetail(void)
Status.
Definition: VStateMachine.h:51
bool isFirstIteration(void) const
true on the very first call of a transition (all indices at their starting value)
CoreSupervisorBase * parentSupervisor_
defines used also by OtsConfigurationWizardSupervisor
< members fully define a front-end macro function
Definition: FEVInterface.h:180
const frontEndMacroFunction_t macroFunction_
Note: must be called using this instance.
Definition: FEVInterface.h:200
static std::string getTimestampString(const std::string &linuxTimeInSeconds)
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
static bool splitMacroArgTriple(const std::string &inputString, std::string &name, std::string &initValue, std::string &stepValue, char delimiter=':')
static void getSetFromString(const std::string &inputString, std::set< std::string > &setToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'})
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static bool inWildCardSet(const std::string &needle, const std::set< std::string > &haystack)
static std::string decodeURIComponent(const std::string &data)
static bool getNumber(const std::string &s, T &retValue)