otsdaq  3.11.00
FESupervisor.cc
1 #include "otsdaq/CoreSupervisors/FESupervisor.h"
2 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
3 #include "otsdaq/FECore/FEVInterfacesManager.h"
4 #include "otsdaq/TablePlugins/ARTDAQTableBase/ARTDAQTableBase.h"
5 
6 #include "artdaq/DAQdata/Globals.hh" // instantiates artdaq::Globals::metricMan_
7 
8 #include <unistd.h> //DIAG: for gettid() in FE macro latency investigation
9 #include <cstring>
10 #include <iostream>
11 #include <string>
12 
13 #include "artdaq-core/Utilities/ExceptionHandler.hh" /*for artdaq::ExceptionHandler*/
14 
37 using namespace ots;
38 
39 XDAQ_INSTANTIATOR_IMPL(FESupervisor)
40 
41 //==============================================================================
42 FESupervisor::FESupervisor(xdaq::ApplicationStub* stub)
43  : CoreSupervisorBase(stub)
44  , dp_context_{1} // 1 I/O thread – sufficient for most tests
45  , dp_socket_{dp_context_, zmq::socket_type::pub}
46 {
47  __SUP_COUT__ << "Constructing..." << __E__;
48 
49  xoap::bind(this,
50  &FESupervisor::macroMakerSupervisorRequest,
51  "MacroMakerSupervisorRequest",
52  XDAQ_NS_URI);
53 
54  xoap::bind(
55  this, &FESupervisor::workLoopStatusRequest, "WorkLoopStatusRequest", XDAQ_NS_URI);
56 
57  xoap::bind(this,
58  &FESupervisor::frontEndCommunicationRequest,
59  "FECommunication",
60  XDAQ_NS_URI);
61 
62  std::string dataPublishingEndpoint;
63  try
64  {
65  dataPublishingEndpoint = getSupervisorProperty(
66  "data_publishing_endpoint"); //like "tcp://0.0.0.0:$((OTS_MAIN_PORT-2))"
67  }
68  catch(const std::runtime_error& e)
69  {
70  __SUP_COUT__ << "Data publishing property 'data_publishing_endpoint' not set. "
71  "Defaulting to data publishing disabled."
72  << __E__;
73 
74  try
75  {
76  dataPublishingEndpoint = __ENV__(
77  "DATA_PUBLISHING_ENDPOINT"); //like "tcp://0.0.0.0:$((OTS_MAIN_PORT-2))"
78  }
79  catch(const std::runtime_error& e)
80  {
81  __SUP_COUT__
82  << "Data publishing environment variable 'DATA_PUBLISHING_ENDPOINT' "
83  "not set. Defaulting to data publishing disabled."
84  << __E__;
85  }
86  }
87  __SUP_COUT_INFO__ << "dataPublishingEndpoint = " << dataPublishingEndpoint << __E__;
88 
89  if(dataPublishingEndpoint.size())
90  {
91  __SUP_COUT__ << "Initializing data publishing to endpoint '"
92  << dataPublishingEndpoint << "'..." << __E__;
93 
94  initDataPublishing(dataPublishingEndpoint,
95  getSupervisorProperty("data_publishing_topic", ""));
96  }
97 
98  try
99  {
100  CoreSupervisorBase::theStateMachineImplementation_.push_back(
102  CorePropertySupervisorBase::getContextTreeNode(),
103  CorePropertySupervisorBase::getSupervisorConfigurationPath()));
104  }
105  catch(...)
106  {
107  if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
108  {
109  __SUP_COUT_WARN__ << "Error caught constructing FE Interface Manager. In "
110  "Macro Maker mode, the input fhicl defines the "
111  "configuration tree, make sure you specified a valid "
112  "fcl file path."
113  << __E__;
114  try
115  {
116  throw;
117  }
118  catch(const std::runtime_error& e)
119  {
120  __SUP_COUT_WARN__ << e.what() << __E__;
121  throw;
122  }
123  }
124  throw;
125  }
126 
127  extractFEInterfacesManager();
128 
129  __SUP_COUT__ << "Constructed." << __E__;
130 
131  if(CorePropertySupervisorBase::allSupervisorInfo_.isMacroMakerMode())
132  {
133  __SUP_COUT_INFO__ << "Macro Maker mode, so configuring at startup!" << __E__;
134  if(!theFEInterfacesManager_)
135  {
136  __SUP_SS__ << "Missing FE Interface manager!" << __E__;
137  __SUP_SS_THROW__;
138  }
139 
140  // copied from CoreSupervisorBase::transitionConfiguring()
141 
142  // Now that the configuration manager has all the necessary configurations,
143  // create all objects that depend on the configuration (the first iteration)
144 
145  try
146  {
147  __SUP_COUT__ << "Configuring all state machine implementations..." << __E__;
148  __SUP_COUTV__(stateMachinesIterationDone_.size());
149  preStateMachineExecutionLoop();
150  __SUP_COUTV__(stateMachinesIterationDone_.size());
151  for(unsigned int i = 0; i < theStateMachineImplementation_.size(); ++i)
152  {
153  __SUP_COUT__ << "Configuring state machine i " << i << __E__;
154 
155  // if one state machine is doing a sub-iteration, then target that one
156  if(subIterationWorkStateMachineIndex_ != (unsigned int)-1 &&
157  i != subIterationWorkStateMachineIndex_)
158  continue; // skip those not in the sub-iteration
159 
160  if(stateMachinesIterationDone_[i])
161  continue; // skip state machines already done
162 
163  preStateMachineExecution(i);
164  theStateMachineImplementation_[i]->parentSupervisor_ =
165  this; // for backwards compatibility, kept out of configure
166  // parameters
167  theStateMachineImplementation_[i]->configure(); // e.g. for FESupervisor,
168  // this is configure of
169  // FEVInterfacesManager
170  postStateMachineExecution(i);
171  }
172  postStateMachineExecutionLoop();
173 
174  //ony indicate alive after configure
175  CorePropertySupervisorBase::indicateOtsAlive(0);
176  }
177  catch(const std::runtime_error& e)
178  {
179  __SUP_SS__ << "Error was caught while configuring: " << e.what() << __E__;
180  __SUP_COUT_ERR__ << "\n" << ss.str();
181  throw;
182  }
183  catch(...)
184  {
185  __SUP_SS__
186  << "Unknown error was caught while configuring. Please checked the logs."
187  << __E__;
188  try
189  {
190  throw;
191  } //one more try to printout extra info
192  catch(const std::exception& e)
193  {
194  ss << "Exception message: " << e.what();
195  }
196  catch(...)
197  {
198  }
199  __SUP_COUT_ERR__ << "\n" << ss.str();
200  throw;
201  }
202  } // end Macro Maker mode initial configure
203 } // end constructor
204 
205 //==============================================================================
206 FESupervisor::~FESupervisor(void)
207 {
208  __SUP_COUT__ << "Destroying..." << __E__;
209  // theStateMachineImplementation_ is reset and the object it points to deleted in
210  // ~CoreSupervisorBase()
211 
212  // Destructor must never throw, so we swallow any zmq_error.
213  try
214  {
216  }
217  catch(...)
218  {
219  // nothing – best‑effort cleanup.
220  }
221 
222  artdaq::Globals::CleanUpGlobals(); // destruct metricManager (among other things)
223 
224  __SUP_COUT__ << "Destructed." << __E__;
225 } // end destructor
226 
227 //==============================================================================
228 xoap::MessageReference FESupervisor::frontEndCommunicationRequest(
229  xoap::MessageReference message)
230 try
231 {
232  __SUP_COUT_INFO__ << "DIAG ms=" << StringMacros::nowEpochMs() << " tid=" << gettid()
233  << " frontEndCommunicationRequest received: "
234  << SOAPUtilities::translate(message) << __E__;
235 
236  if(!theFEInterfacesManager_)
237  {
238  __SUP_SS__ << "No FE Interface Manager!" << __E__;
239  __SUP_SS_THROW__;
240  }
241  SOAPParameters typeParameter, rxParameters; // params for xoap to recv
242  typeParameter.addParameter("type");
243  SOAPUtilities::receive(message, typeParameter);
244 
245  std::string type = typeParameter.getValue("type");
246 
247  // types
248  // feSend
249  // feMacro
250  // feMacroMultiDimensionalStart
251  // macroMultiDimensionalStart
252  // feMacroMultiDimensionalCheck
253  // macroMultiDimensionalCheck
254 
255  rxParameters.addParameter("requester");
256  rxParameters.addParameter("targetInterfaceID");
257 
258  if(type == "feSend")
259  {
260  __SUP_COUTV__(type);
261 
262  rxParameters.addParameter("value");
263  SOAPUtilities::receive(message, rxParameters);
264 
265  std::string requester = rxParameters.getValue("requester");
266  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
267  std::string value = rxParameters.getValue("value");
268 
269  __SUP_COUTV__(requester);
270  __SUP_COUTV__(targetInterfaceID);
271  __SUP_COUTV__(value);
272 
273  // test that the interface exists
274  theFEInterfacesManager_->getFEInterface(targetInterfaceID);
275 
276  // mutex scope
277  {
278  std::lock_guard<std::mutex> lock(
279  theFEInterfacesManager_->frontEndCommunicationReceiveMutex_);
280 
281  theFEInterfacesManager_
282  ->frontEndCommunicationReceiveBuffer_[targetInterfaceID][requester]
283  .emplace(value);
284 
285  __SUP_COUT__ << "Number of target interface ID '" << targetInterfaceID
286  << "' buffers: "
287  << theFEInterfacesManager_
288  ->frontEndCommunicationReceiveBuffer_[targetInterfaceID]
289  .size()
290  << __E__;
291  __SUP_COUT__
292  << "Number of source interface ID '" << requester << "' values received: "
293  << theFEInterfacesManager_
294  ->frontEndCommunicationReceiveBuffer_[targetInterfaceID][requester]
295  .size()
296  << __E__;
297  }
298  return SOAPUtilities::makeSOAPMessageReference("Received");
299  } // end type feSend
300  else if(type == "feMacro")
301  {
302  __SUP_COUTV__(type);
303 
304  rxParameters.addParameter("feMacroName");
305  rxParameters.addParameter("inputArgs");
306 
307  SOAPUtilities::receive(message, rxParameters);
308 
309  std::string requester = rxParameters.getValue("requester");
310  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
311  std::string feMacroName = rxParameters.getValue("feMacroName");
312  std::string inputArgs = rxParameters.getValue("inputArgs");
313 
314  __SUP_COUTV__(requester);
315  __SUP_COUTV__(targetInterfaceID);
316  __SUP_COUTV__(feMacroName);
317  __SUP_COUTV__(inputArgs);
318 
319  std::string outputArgs;
320  try
321  {
322  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
323  << " runFEMacroByFE starting, macro='" << feMacroName
324  << "' target='" << targetInterfaceID << "'" << __E__;
325  theFEInterfacesManager_->runFEMacroByFE(
326  requester, targetInterfaceID, feMacroName, inputArgs, outputArgs);
327  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
328  << " runFEMacroByFE done, macro='" << feMacroName << "'"
329  << __E__;
330  }
331  catch(std::runtime_error& e)
332  {
333  __SUP_SS__ << "In Supervisor with LID="
334  << getApplicationDescriptor()->getLocalId()
335  << " the FE Macro named '" << feMacroName << "' with target FE '"
336  << targetInterfaceID << "' failed. Here is the error:\n\n"
337  << e.what() << __E__;
338  __SUP_SS_THROW__;
339  }
340  catch(...)
341  {
342  __SUP_SS__ << "In Supervisor with LID="
343  << getApplicationDescriptor()->getLocalId()
344  << " the FE Macro named '" << feMacroName << "' with target FE '"
345  << targetInterfaceID << "' failed due to an unknown error."
346  << __E__;
347  try
348  {
349  throw;
350  } //one more try to printout extra info
351  catch(const std::exception& e)
352  {
353  ss << "Exception message: " << e.what();
354  }
355  catch(...)
356  {
357  }
358  __SUP_SS_THROW__;
359  }
360 
361  __SUP_COUTV__(outputArgs);
362 
363  xoap::MessageReference replyMessage =
364  SOAPUtilities::makeSOAPMessageReference("feMacrosResponse");
365  SOAPParameters txParameters;
366  txParameters.addParameter("requester", requester);
367  txParameters.addParameter("targetInterfaceID", targetInterfaceID);
368  txParameters.addParameter("feMacroName", feMacroName);
369  txParameters.addParameter("outputArgs", outputArgs);
370  SOAPUtilities::addParameters(replyMessage, txParameters);
371 
372  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
373  << " Sending FE macro result: "
374  << SOAPUtilities::translate(replyMessage) << __E__;
375 
376  return replyMessage;
377  } // end type feMacro
378  else if(type == "feMacroMultiDimensionalStart" || // from iterator
379  type == "macroMultiDimensionalStart") // from iterator
380  {
381  __SUP_COUTV__(type);
382 
383  if(type[0] == 'm')
384  {
385  rxParameters.addParameter("macroString");
386  rxParameters.addParameter("macroName");
387  }
388  else
389  rxParameters.addParameter("feMacroName");
390 
391  rxParameters.addParameter("enableSavingOutput");
392  rxParameters.addParameter("outputFilePath");
393  rxParameters.addParameter("outputFileRadix");
394  rxParameters.addParameter("inputArgs");
395 
396  SOAPUtilities::receive(message, rxParameters);
397 
398  std::string requester = rxParameters.getValue("requester");
399  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
400  std::string macroName, macroString;
401  if(type[0] == 'm')
402  {
403  macroName = rxParameters.getValue("macroName");
404  macroString = rxParameters.getValue("macroString");
405  __SUP_COUTV__(macroString);
406  }
407  else
408  macroName = rxParameters.getValue("feMacroName");
409  bool enableSavingOutput = rxParameters.getValue("enableSavingOutput") == "1";
410  std::string outputFilePath = rxParameters.getValue("outputFilePath");
411  std::string outputFileRadix = rxParameters.getValue("outputFileRadix");
412  std::string inputArgs = rxParameters.getValue("inputArgs");
413 
414  __SUP_COUTV__(requester);
415  __SUP_COUTV__(targetInterfaceID);
416  __SUP_COUTV__(macroName);
417  __SUP_COUTV__(enableSavingOutput);
418  __SUP_COUTV__(outputFilePath);
419  __SUP_COUTV__(outputFileRadix);
420  __SUP_COUTV__(inputArgs);
421 
422  if(type[0] == 'm') // start Macro
423  {
424  try
425  {
426  theFEInterfacesManager_->startMacroMultiDimensional(requester,
427  targetInterfaceID,
428  macroName,
429  macroString,
430  enableSavingOutput,
431  outputFilePath,
432  outputFileRadix,
433  inputArgs);
434  }
435  catch(std::runtime_error& e)
436  {
437  __SUP_SS__ << "In Supervisor with LID="
438  << getApplicationDescriptor()->getLocalId()
439  << " the Macro named '" << macroName << "' with target FE '"
440  << targetInterfaceID
441  << "' failed to start multi-dimensional launch. "
442  << "Here is the error:\n\n"
443  << e.what() << __E__;
444  __SUP_SS_THROW__;
445  }
446  catch(...)
447  {
448  __SUP_SS__ << "In Supervisor with LID="
449  << getApplicationDescriptor()->getLocalId()
450  << " the Macro named '" << macroName << "' with target FE '"
451  << targetInterfaceID
452  << "' failed to start multi-dimensional launch "
453  << "due to an unknown error." << __E__;
454  try
455  {
456  throw;
457  } //one more try to printout extra info
458  catch(const std::exception& e)
459  {
460  ss << "Exception message: " << e.what();
461  }
462  catch(...)
463  {
464  }
465  __SUP_SS_THROW__;
466  }
467  }
468  else // start FE Macro
469  {
470  try
471  {
472  theFEInterfacesManager_->startFEMacroMultiDimensional(requester,
473  targetInterfaceID,
474  macroName,
475  enableSavingOutput,
476  outputFilePath,
477  outputFileRadix,
478  inputArgs);
479  }
480  catch(std::runtime_error& e)
481  {
482  __SUP_SS__ << "In Supervisor with LID="
483  << getApplicationDescriptor()->getLocalId()
484  << " the FE Macro named '" << macroName << "' with target FE '"
485  << targetInterfaceID
486  << "' failed to start multi-dimensional launch. "
487  << "Here is the error:\n\n"
488  << e.what() << __E__;
489  __SUP_SS_THROW__;
490  }
491  catch(...)
492  {
493  __SUP_SS__ << "In Supervisor with LID="
494  << getApplicationDescriptor()->getLocalId()
495  << " the FE Macro named '" << macroName << "' with target FE '"
496  << targetInterfaceID
497  << "' failed to start multi-dimensional launch "
498  << "due to an unknown error." << __E__;
499  try
500  {
501  throw;
502  } //one more try to printout extra info
503  catch(const std::exception& e)
504  {
505  ss << "Exception message: " << e.what();
506  }
507  catch(...)
508  {
509  }
510  __SUP_SS_THROW__;
511  }
512  }
513 
514  xoap::MessageReference replyMessage =
515  SOAPUtilities::makeSOAPMessageReference(type + "Done");
516  SOAPParameters txParameters;
517  // txParameters.addParameter("started", "1");
518  SOAPUtilities::addParameters(replyMessage, txParameters);
519 
520  __SUP_COUT__ << "Sending FE macro result: "
521  << SOAPUtilities::translate(replyMessage) << __E__;
522 
523  return replyMessage;
524  } // end type (fe)MacroMultiDimensionalStart
525  else if(type == "feMacroMultiDimensionalCheck" || // from iterator
526  type == "macroMultiDimensionalCheck")
527  {
528  // LORE__SUP_COUTV__(type);
529  if(type[0] == 'm')
530  rxParameters.addParameter("macroName");
531  else
532  rxParameters.addParameter("feMacroName");
533  rxParameters.addParameter("targetInterfaceID");
534 
535  SOAPUtilities::receive(message, rxParameters);
536 
537  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
538  std::string macroName;
539  if(type[0] == 'm')
540  macroName = rxParameters.getValue("macroName");
541  else
542  macroName = rxParameters.getValue("feMacroName");
543 
544  // LORE__SUP_COUTV__(targetInterfaceID);
545  // LORE__SUP_COUTV__(macroName);
546 
547  bool done = false;
548  std::string outputFile; // saved-output file path, filled on Done when saving
549  try
550  {
551  done = theFEInterfacesManager_->checkMacroMultiDimensional(
552  targetInterfaceID, macroName, &outputFile);
553  }
554  catch(std::runtime_error& e)
555  {
556  __SUP_SS__ << "In Supervisor with LID="
557  << getApplicationDescriptor()->getLocalId()
558  << " the FE Macro named '" << macroName << "' with target FE '"
559  << targetInterfaceID
560  << "' failed to check multi-dimensional launch. "
561  << "Here is the error:\n\n"
562  << e.what() << __E__;
563  __SUP_SS_THROW__;
564  }
565  catch(...)
566  {
567  __SUP_SS__ << "In Supervisor with LID="
568  << getApplicationDescriptor()->getLocalId()
569  << " the FE Macro named '" << macroName << "' with target FE '"
570  << targetInterfaceID
571  << "' failed to check multi-dimensional launch "
572  << "due to an unknown error." << __E__;
573  try
574  {
575  throw;
576  } //one more try to printout extra info
577  catch(const std::exception& e)
578  {
579  ss << "Exception message: " << e.what();
580  }
581  catch(...)
582  {
583  }
584  __SUP_SS_THROW__;
585  }
586 
587  xoap::MessageReference replyMessage =
588  SOAPUtilities::makeSOAPMessageReference(type + "Done");
589  SOAPParameters txParameters;
590  txParameters.addParameter("Done", done ? "1" : "0");
591  txParameters.addParameter("OutputFile", outputFile); // "" when not saving
592  SOAPUtilities::addParameters(replyMessage, txParameters);
593 
594  // LORE__SUP_COUT__ << "Sending FE macro result: " << SOAPUtilities::translate(replyMessage) << __E__;
595 
596  return replyMessage;
597  } // end type (fe)MacroMultiDimensionalCheck
598  else
599  {
600  __SUP_SS__ << "Unrecognized FE Communication type: " << type << __E__;
601  __SUP_SS_THROW__;
602  }
603 }
604 catch(const std::runtime_error& e)
605 {
606  __SUP_SS__ << "Error encountered processing FE communication request: " << e.what()
607  << __E__;
608  __SUP_COUT_ERR__ << ss.str();
609 
610  SOAPParameters parameters;
611  parameters.addParameter("Error", ss.str());
612  return SOAPUtilities::makeSOAPMessageReference(
613  supervisorClassNoNamespace_ + "FailFECommunicationRequest", parameters);
614 }
615 catch(...)
616 {
617  __SUP_SS__ << "Unknown error encountered processing FE communication request."
618  << __E__;
619  try
620  {
621  throw;
622  } //one more try to printout extra info
623  catch(const std::exception& e)
624  {
625  ss << "Exception message: " << e.what();
626  }
627  catch(...)
628  {
629  }
630  __SUP_COUT_ERR__ << ss.str();
631 
632  SOAPParameters parameters;
633  parameters.addParameter("Error", ss.str());
634  return SOAPUtilities::makeSOAPMessageReference(
635  supervisorClassNoNamespace_ + "FailFECommunicationRequest", parameters);
636 } // end frontEndCommunicationRequest()
637 
638 //==============================================================================
646  xoap::MessageReference message)
647 {
648  __SUP_COUT__ << "$$$$$$$$$$$$$$$$$" << __E__;
649 
650  // receive request parameters
651  SOAPParameters parameters;
652  parameters.addParameter("Request");
653 
654  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs() << " tid=" << gettid()
655  << " Received Macro Maker message: " << SOAPUtilities::translate(message)
656  << __E__;
657 
658  SOAPUtilities::receive(message, parameters);
659  std::string request = parameters.getValue("Request");
660 
661  __SUP_COUT__ << "request: " << request << __E__;
662 
663  // request types:
664  // GetInterfaces
665  // UniversalWrite
666  // UniversalRead
667  // GetInterfaceMacros
668  // GetInterfaceMacroInputDefaults
669  // RunInterfaceMacro
670  // RunMacroMakerMacro
671 
672  SOAPParameters retParameters;
673 
674  try
675  {
676  if(request == "GetInterfaces")
677  {
678  if(theFEInterfacesManager_)
679  retParameters.addParameter(
680  "FEList",
681  theFEInterfacesManager_->getFEListString(
682  std::to_string(getApplicationDescriptor()->getLocalId())));
683  else // if no FE interfaces, return empty string
684  retParameters.addParameter("FEList", "");
685 
686  // if errors in state machine, send also
687  if(theStateMachine_.getErrorMessage() != "")
688  retParameters.addParameter("frontEndError",
689  theStateMachine_.getErrorMessage());
690 
691  return SOAPUtilities::makeSOAPMessageReference(
692  supervisorClassNoNamespace_ + "Response", retParameters);
693  }
694  else if(request == "UniversalWrite")
695  {
696  if(!theFEInterfacesManager_)
697  {
698  __SUP_SS__ << "No FE Interface Manager! Are you configured?" << __E__;
699  __SUP_SS_THROW__;
700  }
701  // params for running macros
702  SOAPParameters requestParameters;
703  requestParameters.addParameter("InterfaceID");
704  requestParameters.addParameter("Address");
705  requestParameters.addParameter("Data");
706  SOAPUtilities::receive(message, requestParameters);
707  std::string interfaceID = requestParameters.getValue("InterfaceID");
708  std::string addressStr = requestParameters.getValue("Address");
709  std::string dataStr = requestParameters.getValue("Data");
710 
711  __SUP_COUT__ << "Address: " << addressStr << " Data: " << dataStr
712  << " InterfaceID: " << interfaceID << __E__;
713 
714  // parameters interface index!
715  // unsigned int index = stoi(indexStr); // As long as the supervisor has only
716  // one interface, this index will remain 0?
717 
718  __SUP_COUT__
719  << "theFEInterfacesManager_->getInterfaceUniversalAddressSize(index) "
720  << theFEInterfacesManager_->getInterfaceUniversalAddressSize(interfaceID)
721  << __E__;
722  __SUP_COUT__
723  << "theFEInterfacesManager_->getInterfaceUniversalDataSize(index) "
724  << theFEInterfacesManager_->getInterfaceUniversalDataSize(interfaceID)
725  << __E__;
726 
727  // Converting std::string to char*
728  // char address
729 
730  char tmpHex[3]; // for use converting hex to binary
731  tmpHex[2] = '\0';
732 
733  __SUP_COUT__ << "Translating address: ";
734 
735  std::string addressTmp;
736  addressTmp.reserve(
737  theFEInterfacesManager_->getInterfaceUniversalAddressSize(interfaceID));
738  char* address = &addressTmp[0];
739 
740  if(addressStr.size() % 2) // if odd, make even
741  addressStr = "0" + addressStr;
742  unsigned int i = 0;
743  for(; i < addressStr.size() &&
744  i / 2 < theFEInterfacesManager_->getInterfaceUniversalAddressSize(
745  interfaceID);
746  i += 2)
747  {
748  tmpHex[0] = addressStr[addressStr.size() - 1 - i - 1];
749  tmpHex[1] = addressStr[addressStr.size() - 1 - i];
750  sscanf(tmpHex, "%hhX", (unsigned char*)&address[i / 2]);
751  printf("%2.2X", (unsigned char)address[i / 2]);
752  }
753  // finish and fill with 0s
754  for(; i / 2 <
755  theFEInterfacesManager_->getInterfaceUniversalAddressSize(interfaceID);
756  i += 2)
757  {
758  address[i / 2] = 0;
759  printf("%2.2X", (unsigned char)address[i / 2]);
760  }
761 
762  std::cout << __E__;
763 
764  __SUP_COUT__ << "Translating data: ";
765 
766  std::string dataTmp;
767  dataTmp.reserve(
768  theFEInterfacesManager_->getInterfaceUniversalDataSize(interfaceID));
769  char* data = &dataTmp[0];
770 
771  if(dataStr.size() % 2) // if odd, make even
772  dataStr = "0" + dataStr;
773 
774  i = 0;
775  for(; i < dataStr.size() &&
776  i / 2 <
777  theFEInterfacesManager_->getInterfaceUniversalDataSize(interfaceID);
778  i += 2)
779  {
780  tmpHex[0] = dataStr[dataStr.size() - 1 - i - 1];
781  tmpHex[1] = dataStr[dataStr.size() - 1 - i];
782  sscanf(tmpHex, "%hhX", (unsigned char*)&data[i / 2]);
783  printf("%2.2X", (unsigned char)data[i / 2]);
784  }
785  // finish and fill with 0s
786  for(; i / 2 <
787  theFEInterfacesManager_->getInterfaceUniversalDataSize(interfaceID);
788  i += 2)
789  {
790  data[i / 2] = 0;
791  printf("%2.2X", (unsigned char)data[i / 2]);
792  }
793 
794  std::cout << __E__;
795 
796  // char* address = new char[addressStr.size() + 1];
797  // std::copy(addressStr.begin(), addressStr.end(), address);
798  // address[addressStr.size()] = '\0';
799  // char* data = new char[dataStr.size() + 1];
800  // std::copy(dataStr.begin(), dataStr.end(), data);
801  // data[dataStr.size()] = '\0';
802 
803  theFEInterfacesManager_->universalWrite(interfaceID, address, data);
804 
805  // delete[] address;
806  // delete[] data;
807 
808  return SOAPUtilities::makeSOAPMessageReference(
809  supervisorClassNoNamespace_ + "DataWritten", retParameters);
810  }
811  else if(request == "UniversalRead")
812  {
813  if(!theFEInterfacesManager_)
814  {
815  __SUP_SS__ << "No FE Interface Manager! Are you configured?" << __E__;
816  __SUP_SS_THROW__;
817  }
818 
819  // params for running macros
820  SOAPParameters requestParameters;
821  requestParameters.addParameter("InterfaceID");
822  requestParameters.addParameter("Address");
823  SOAPUtilities::receive(message, requestParameters);
824  std::string interfaceID = requestParameters.getValue("InterfaceID");
825  std::string addressStr = requestParameters.getValue("Address");
826 
827  __SUP_COUT__ << "Address: " << addressStr << " InterfaceID: " << interfaceID
828  << __E__;
829 
830  // parameters interface index!
831  // parameter address and data
832  // unsigned int index = stoi(indexStr); // As long as the supervisor has only
833  // one interface, this index will remain 0?
834 
835  __SUP_COUT__
836  << "theFEInterfacesManager_->getInterfaceUniversalAddressSize(index) "
837  << theFEInterfacesManager_->getInterfaceUniversalAddressSize(interfaceID)
838  << __E__;
839  __SUP_COUT__
840  << "theFEInterfacesManager_->getInterfaceUniversalDataSize(index) "
841  << theFEInterfacesManager_->getInterfaceUniversalDataSize(interfaceID)
842  << __E__;
843 
844  char tmpHex[3]; // for use converting hex to binary
845  tmpHex[2] = '\0';
846 
847  __SUP_COUT__ << "Translating address: ";
848 
849  std::string addressTmp;
850  addressTmp.reserve(
851  theFEInterfacesManager_->getInterfaceUniversalAddressSize(interfaceID));
852  char* address = &addressTmp[0];
853 
854  if(addressStr.size() % 2) // if odd, make even
855  addressStr = "0" + addressStr;
856 
857  unsigned int i = 0;
858  for(; i < addressStr.size() &&
859  i / 2 < theFEInterfacesManager_->getInterfaceUniversalAddressSize(
860  interfaceID);
861  i += 2)
862  {
863  tmpHex[0] = addressStr[addressStr.size() - 1 - i - 1];
864  tmpHex[1] = addressStr[addressStr.size() - 1 - i];
865  sscanf(tmpHex, "%hhX", (unsigned char*)&address[i / 2]);
866  printf("%2.2X", (unsigned char)address[i / 2]);
867  }
868  // finish and fill with 0s
869  for(; i / 2 <
870  theFEInterfacesManager_->getInterfaceUniversalAddressSize(interfaceID);
871  i += 2)
872  {
873  address[i / 2] = 0;
874  printf("%2.2X", (unsigned char)address[i / 2]);
875  }
876 
877  std::cout << __E__;
878 
879  unsigned int dataSz =
880  theFEInterfacesManager_->getInterfaceUniversalDataSize(interfaceID);
881  std::string dataStr;
882  dataStr.resize(dataSz);
883  char* data = &dataStr[0];
884 
885  // std::string result =
886  // theFEInterfacesManager_->universalRead(index,address,data);
887  // __SUP_COUT__<< result << __E__ << __E__;
888 
889  try
890  {
891  theFEInterfacesManager_->universalRead(interfaceID, address, data);
892  }
893  catch(const std::runtime_error& e)
894  {
895  // do not allow read exception to crash everything when a macromaker
896  // command
897  __SUP_COUT_ERR__ << "Exception caught during read: " << e.what() << __E__;
898  retParameters.addParameter("dataResult", "Time Out Error");
899  return SOAPUtilities::makeSOAPMessageReference(
900  supervisorClassNoNamespace_ + "aa", retParameters);
901  }
902  catch(...)
903  {
904  // do not allow read exception to crash everything when a macromaker
905  // command
906  __SUP_COUT_ERR__ << "Exception caught during read." << __E__;
907  retParameters.addParameter("dataResult", "Time Out Error");
908  return SOAPUtilities::makeSOAPMessageReference(
909  supervisorClassNoNamespace_ + "aa", retParameters);
910  }
911 
912  // if dataSz is less than 8 show what the unsigned number would be
913  if(dataSz <= 8)
914  {
915  std::string str8(data);
916  str8.resize(8);
917  __SUP_COUT__ << "decResult[" << dataSz
918  << " bytes]: " << *((unsigned long long*)(&str8[0]))
919  << __E__;
920  }
921 
922  std::string hexResultStr;
923  hexResultStr.reserve(dataSz * 2 + 1);
924  char* hexResult = &hexResultStr[0];
925  // go through each byte and convert it to hex value (i.e. 2 0-F chars)
926  // go backwards through source data since should be provided in host order
927  // (i.e. a cast to unsigned long long should acquire expected value)
928  for(unsigned int i = 0; i < dataSz; ++i)
929  {
930  sprintf(&hexResult[i * 2], "%2.2X", (unsigned char)data[dataSz - 1 - i]);
931  }
932 
933  __SUP_COUT__ << "hexResult[" << strlen(hexResult)
934  << " nibbles]: " << std::string(hexResult) << __E__;
935 
936  retParameters.addParameter("dataResult", hexResult);
937  return SOAPUtilities::makeSOAPMessageReference(
938  supervisorClassNoNamespace_ + "aa", retParameters);
939  }
940  else if(request == "GetInterfaceMacros")
941  {
942  if(theFEInterfacesManager_)
943  {
944  __SUP_COUT__ << "Getting FE Macros from FE Interface Manager..." << __E__;
945  retParameters.addParameter(
946  "FEMacros",
947  theFEInterfacesManager_->getFEMacrosString(
948  CorePropertySupervisorBase::getSupervisorUID(),
949  std::to_string(CoreSupervisorBase::getSupervisorLID())));
950  }
951  else
952  {
953  __SUP_COUT__ << "No FE Macros because there is no FE Interface Manager..."
954  << __E__;
955  retParameters.addParameter("FEMacros", "");
956  }
957 
958  return SOAPUtilities::makeSOAPMessageReference(
959  supervisorClassNoNamespace_ + "Response", retParameters);
960  }
961  else if(request == "GetInterfaceMacroInputDefaults")
962  {
963  if(!theFEInterfacesManager_)
964  {
965  __SUP_SS__ << "Missing FE Interface Manager! Are you configured?"
966  << __E__;
967  __SUP_SS_THROW__;
968  }
969 
970  SOAPParameters requestParameters;
971  requestParameters.addParameter("InterfaceID");
972  requestParameters.addParameter("feMacroName");
973  requestParameters.addParameter("inputArgs");
974  requestParameters.addParameter("userPermissions");
975  SOAPUtilities::receive(message, requestParameters);
976 
977  const std::string interfaceID = requestParameters.getValue("InterfaceID");
978  const std::string feMacroName = requestParameters.getValue("feMacroName");
979  const std::string inputArgs = requestParameters.getValue("inputArgs");
980  const std::string userPermissions =
981  requestParameters.getValue("userPermissions");
982 
983  FEVInterface* fe = theFEInterfacesManager_->getFEInterfaceP(interfaceID);
984  auto macroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
985  if(macroIt == fe->getMapOfFEMacroFunctions().end())
986  {
987  __SUP_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '"
988  << interfaceID << "' was not found!" << __E__;
989  __SUP_SS_THROW__;
990  }
991 
992  std::map<std::string, WebUsers::permissionLevel_t> userPermissionLevelsMap;
994  userPermissions, userPermissionLevelsMap);
995  std::map<std::string, WebUsers::permissionLevel_t>
996  requiredPermissionLevelsMap;
998  macroIt->second.requiredUserPermissions_, requiredPermissionLevelsMap);
1000  userPermissionLevelsMap, requiredPermissionLevelsMap))
1001  {
1002  __SUP_SS__ << "Invalid user permission for FE Macro '" << feMacroName
1003  << "' of interfaceID '" << interfaceID << "'." << __E__;
1004  __SUP_SS_THROW__;
1005  }
1006 
1007  const auto defaults = theFEInterfacesManager_->getFEMacroInputDefaults(
1008  interfaceID, feMacroName, inputArgs);
1009  std::string encodedDefaults;
1010  for(const auto& defaultValue : defaults)
1011  {
1012  if(!encodedDefaults.empty())
1013  encodedDefaults += ";";
1014  encodedDefaults += StringMacros::encodeURIComponent(defaultValue.first) +
1015  "," +
1016  StringMacros::encodeURIComponent(defaultValue.second);
1017  }
1018  retParameters.addParameter("InputDefaults", encodedDefaults);
1019  return SOAPUtilities::makeSOAPMessageReference(
1020  supervisorClassNoNamespace_ + "Response", retParameters);
1021  }
1022  else if(request == "RunInterfaceMacro")
1023  {
1024  if(!theFEInterfacesManager_)
1025  {
1026  __SUP_SS__ << "Missing FE Interface Manager! Are you configured?"
1027  << __E__;
1028  __SUP_SS_THROW__;
1029  }
1030 
1031  // params for running macros
1032  SOAPParameters requestParameters;
1033  requestParameters.addParameter("feMacroName");
1034  requestParameters.addParameter("inputArgs");
1035  requestParameters.addParameter("outputArgs");
1036  requestParameters.addParameter("InterfaceID");
1037  requestParameters.addParameter("userPermissions");
1038  requestParameters.addParameter("AsyncSupported");
1039  SOAPUtilities::receive(message, requestParameters);
1040  std::string interfaceID = requestParameters.getValue("InterfaceID");
1041  std::string feMacroName = requestParameters.getValue("feMacroName");
1042  std::string inputArgs = requestParameters.getValue("inputArgs");
1043  std::string outputArgs = requestParameters.getValue("outputArgs");
1044  std::string userPermissions = requestParameters.getValue("userPermissions");
1045  bool asyncSupported = requestParameters.getValue("AsyncSupported") == "1";
1046 
1047  // check user permission
1048  // userPermissions = "allUsers:1";
1049  // userPermissions = "allUsers:1 & TDAQ:255";
1050  __COUTV__(userPermissions);
1051  std::map<std::string, WebUsers::permissionLevel_t> userPermissionLevelsMap;
1053  userPermissions, userPermissionLevelsMap);
1054  __COUTV__(StringMacros::mapToString(userPermissionLevelsMap));
1055 
1056  // outputArgs must be filled with the proper argument names
1057  // and then the response output values will be returned in the string.
1058 
1059  // check for interfaceID
1060  FEVInterface* fe = theFEInterfacesManager_->getFEInterfaceP(interfaceID);
1061 
1062  // have pointer to virtual FEInterface, find Macro structure
1063  auto FEMacroIt = fe->getMapOfFEMacroFunctions().find(feMacroName);
1064  if(FEMacroIt == fe->getMapOfFEMacroFunctions().end())
1065  {
1066  __SUP_SS__ << "FE Macro '" << feMacroName << "' of interfaceID '"
1067  << interfaceID << "' was not found!" << __E__;
1068  __SUP_SS_THROW__;
1069  }
1070  const FEVInterface::frontEndMacroStruct_t& FEMacro = FEMacroIt->second;
1071 
1072  __COUTV__(FEMacro.requiredUserPermissions_);
1073  std::map<std::string, WebUsers::permissionLevel_t>
1074  FERequiredUserPermissionsMap;
1076  FEMacro.requiredUserPermissions_, FERequiredUserPermissionsMap);
1077  __COUTV__(StringMacros::mapToString(FERequiredUserPermissionsMap));
1078 
1080  userPermissionLevelsMap, FERequiredUserPermissionsMap))
1081  {
1082  __SUP_SS__ << "Invalid user permission for FE Macro '" << feMacroName
1083  << "' of interfaceID '" << interfaceID << "'!\n\n"
1084  << "Must have access level of at least '"
1085  << StringMacros::mapToString(FERequiredUserPermissionsMap)
1086  << ".' Users permissions level is only '" << userPermissions
1087  << ".'" << __E__;
1088  __SUP_SS_THROW__;
1089  }; // skip icon if no access
1090 
1091  if(asyncSupported)
1092  {
1093  // Async path: launch macro in a thread, return NotDoneTaskID immediately
1094  auto task = std::make_shared<AsyncMacroTask>();
1095  {
1096  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1097  task->taskID = ++asyncMacroTaskIDCounter_;
1098  if(asyncMacroTaskIDCounter_ == 0)
1099  task->taskID = ++asyncMacroTaskIDCounter_;
1100  task->interfaceID = interfaceID;
1101  task->startTime = time(0);
1102  asyncMacroTasks_.push_back(task);
1103  }
1104 
1105  FEVInterface::frontEndMacroStruct_t localFEMacro = FEMacro;
1106  std::thread([this,
1107  task,
1108  interfaceID,
1109  localFEMacro,
1110  inputArgs,
1111  outputArgs]() mutable {
1112  {
1113  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1114  task->threadID = std::this_thread::get_id();
1115  }
1116  // Clear stale progress in case thread ID was reused
1117  try
1118  {
1119  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1120  ->clearFEMacroPercentDone(std::this_thread::get_id());
1121  }
1122  catch(...)
1123  {
1124  }
1125 
1126  try
1127  {
1128  __COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1129  << " async FE Macro thread starting runFEMacro, taskID="
1130  << task->taskID << __E__;
1131  theFEInterfacesManager_->runFEMacro(
1132  interfaceID, localFEMacro, inputArgs, outputArgs);
1133  __COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1134  << " async FE Macro thread finished runFEMacro, taskID="
1135  << task->taskID << __E__;
1136  try
1137  {
1138  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1139  ->clearFEMacroPercentDone(std::this_thread::get_id());
1140  }
1141  catch(...)
1142  {
1143  }
1144  {
1145  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1146  task->outputArgs = outputArgs;
1147  task->doneTime = time(0);
1148  task->done = true;
1149  }
1150  }
1151  catch(const std::exception& e)
1152  {
1153  try
1154  {
1155  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1156  ->clearFEMacroPercentDone(std::this_thread::get_id());
1157  }
1158  catch(...)
1159  {
1160  }
1161  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1162  task->error =
1163  "In Supervisor with LID=" +
1164  std::to_string(getApplicationDescriptor()->getLocalId()) +
1165  " the FE Macro named '" + interfaceID +
1166  "' failed. Here is the error:\n\n" + e.what();
1167  task->doneTime = time(0);
1168  task->done = true;
1169  }
1170  catch(...)
1171  {
1172  try
1173  {
1174  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1175  ->clearFEMacroPercentDone(std::this_thread::get_id());
1176  }
1177  catch(...)
1178  {
1179  }
1180  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1181  task->error =
1182  "In Supervisor with LID=" +
1183  std::to_string(getApplicationDescriptor()->getLocalId()) +
1184  " the FE Macro named '" + interfaceID +
1185  "' failed due to an unknown error.";
1186  task->doneTime = time(0);
1187  task->done = true;
1188  }
1189  }).detach();
1190 
1191  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1192  << " Launched async FE Macro '" << feMacroName
1193  << "' for interfaceID '" << interfaceID
1194  << "' with taskID=" << task->taskID << __E__;
1195 
1196  // Wait briefly to see if macro finishes quickly (avoids unnecessary polling)
1197  {
1198  size_t sleepUs = 100;
1199  for(int i = 0; i < 10; ++i)
1200  {
1201  usleep(sleepUs);
1202  {
1203  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1204  if(task->done)
1205  {
1206  if(!task->error.empty())
1207  {
1208  std::string errorCopy = task->error;
1209  for(size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1210  if(asyncMacroTasks_[j]->taskID == task->taskID)
1211  {
1212  asyncMacroTasks_.erase(
1213  asyncMacroTasks_.begin() + j);
1214  break;
1215  }
1216  __SUP_SS__ << errorCopy;
1217  __SUP_SS_THROW__;
1218  }
1219  __SUP_COUT__
1220  << "DIAG ms=" << StringMacros::nowEpochMs()
1221  << " async macro finished within quick-wait,"
1222  << " returning synchronously, taskID=" << task->taskID
1223  << __E__;
1224  retParameters.addParameter("outputArgs",
1225  task->outputArgs);
1226  for(size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1227  if(asyncMacroTasks_[j]->taskID == task->taskID)
1228  {
1229  asyncMacroTasks_.erase(asyncMacroTasks_.begin() +
1230  j);
1231  break;
1232  }
1233  return SOAPUtilities::makeSOAPMessageReference(
1234  supervisorClassNoNamespace_ + "Response",
1235  retParameters);
1236  }
1237  }
1238  sleepUs *= 2;
1239  if(sleepUs > 50000)
1240  sleepUs = 50000;
1241  }
1242  }
1243 
1244  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1245  << " async macro NOT done within quick-wait,"
1246  << " returning NotDoneTaskID=" << task->taskID << __E__;
1247  retParameters.addParameter("NotDoneTaskID", std::to_string(task->taskID));
1248  return SOAPUtilities::makeSOAPMessageReference(
1249  supervisorClassNoNamespace_ + "Response", retParameters);
1250  }
1251  else
1252  {
1253  // Synchronous path: run macro and return result (backward compatible)
1254  try
1255  {
1256  theFEInterfacesManager_->runFEMacro(
1257  interfaceID, FEMacro, inputArgs, outputArgs);
1258  }
1259  catch(std::runtime_error& e)
1260  {
1261  __SUP_SS__ << "In Supervisor with LID="
1262  << getApplicationDescriptor()->getLocalId()
1263  << " the FE Macro named '" << feMacroName
1264  << "' with target FE '" << interfaceID
1265  << "' failed. Here is the error:\n\n"
1266  << e.what() << __E__;
1267  __SUP_SS_THROW__;
1268  }
1269  catch(std::exception& e)
1270  {
1271  __SUP_SS__ << "In Supervisor with LID="
1272  << getApplicationDescriptor()->getLocalId()
1273  << " the FE Macro named '" << feMacroName
1274  << "' with target FE '" << interfaceID
1275  << "' failed. Here is the error:\n\n"
1276  << e.what() << __E__;
1277  __SUP_SS_THROW__;
1278  }
1279  catch(...)
1280  {
1281  __SUP_SS__ << "In Supervisor with LID="
1282  << getApplicationDescriptor()->getLocalId()
1283  << " the FE Macro named '" << feMacroName
1284  << "' with target FE '" << interfaceID
1285  << "' failed due to an unknown error." << __E__;
1286  try
1287  {
1288  throw;
1289  } //one more try to printout extra info
1290  catch(const std::exception& e)
1291  {
1292  ss << "Exception message: " << e.what();
1293  }
1294  catch(...)
1295  {
1296  }
1297  __SUP_SS_THROW__;
1298  }
1299 
1300  retParameters.addParameter("outputArgs", outputArgs);
1301  return SOAPUtilities::makeSOAPMessageReference(
1302  supervisorClassNoNamespace_ + "Response", retParameters);
1303  }
1304  }
1305  else if(request == "RunMacroMakerMacro")
1306  {
1307  if(!theFEInterfacesManager_)
1308  {
1309  __SUP_SS__ << "Missing FE Interface Manager! Are you configured?"
1310  << __E__;
1311  __SUP_SS_THROW__;
1312  }
1313 
1314  // params for running macros
1315  SOAPParameters requestParameters;
1316  requestParameters.addParameter("macroName");
1317  requestParameters.addParameter("macroString");
1318  requestParameters.addParameter("inputArgs");
1319  requestParameters.addParameter("outputArgs");
1320  requestParameters.addParameter("InterfaceID");
1321  requestParameters.addParameter("AsyncSupported");
1322  SOAPUtilities::receive(message, requestParameters);
1323  std::string interfaceID = requestParameters.getValue("InterfaceID");
1324  std::string macroName = requestParameters.getValue("macroName");
1325  std::string macroString = requestParameters.getValue("macroString");
1326  std::string inputArgs = requestParameters.getValue("inputArgs");
1327  std::string outputArgs = requestParameters.getValue("outputArgs");
1328  bool asyncSupported = requestParameters.getValue("AsyncSupported") == "1";
1329 
1330  if(asyncSupported)
1331  {
1332  // Async path: launch macro in a thread, return NotDoneTaskID immediately
1333  auto task = std::make_shared<AsyncMacroTask>();
1334  {
1335  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1336  task->taskID = ++asyncMacroTaskIDCounter_;
1337  if(asyncMacroTaskIDCounter_ == 0)
1338  task->taskID = ++asyncMacroTaskIDCounter_;
1339  task->interfaceID = interfaceID;
1340  task->startTime = time(0);
1341  asyncMacroTasks_.push_back(task);
1342  }
1343 
1344  std::thread([this,
1345  task,
1346  interfaceID,
1347  macroName,
1348  macroString,
1349  inputArgs,
1350  outputArgs]() mutable {
1351  {
1352  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1353  task->threadID = std::this_thread::get_id();
1354  }
1355  try
1356  {
1357  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1358  ->clearFEMacroPercentDone(std::this_thread::get_id());
1359  }
1360  catch(...)
1361  {
1362  }
1363 
1364  try
1365  {
1366  theFEInterfacesManager_->runMacro(
1367  interfaceID, macroString, inputArgs, outputArgs);
1368  try
1369  {
1370  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1371  ->clearFEMacroPercentDone(std::this_thread::get_id());
1372  }
1373  catch(...)
1374  {
1375  }
1376  {
1377  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1378  task->outputArgs = outputArgs;
1379  task->doneTime = time(0);
1380  task->done = true;
1381  }
1382  }
1383  catch(const std::exception& e)
1384  {
1385  try
1386  {
1387  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1388  ->clearFEMacroPercentDone(std::this_thread::get_id());
1389  }
1390  catch(...)
1391  {
1392  }
1393  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1394  task->error =
1395  "In Supervisor with LID=" +
1396  std::to_string(getApplicationDescriptor()->getLocalId()) +
1397  " the MacroMaker Macro named '" + macroName +
1398  "' with target FE '" + interfaceID +
1399  "' failed. Here is the error:\n\n" + e.what();
1400  task->doneTime = time(0);
1401  task->done = true;
1402  }
1403  catch(...)
1404  {
1405  try
1406  {
1407  theFEInterfacesManager_->getFEInterfaceP(interfaceID)
1408  ->clearFEMacroPercentDone(std::this_thread::get_id());
1409  }
1410  catch(...)
1411  {
1412  }
1413  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1414  task->error =
1415  "In Supervisor with LID=" +
1416  std::to_string(getApplicationDescriptor()->getLocalId()) +
1417  " the MacroMaker Macro named '" + macroName +
1418  "' with target FE '" + interfaceID +
1419  "' failed due to an unknown error.";
1420  task->doneTime = time(0);
1421  task->done = true;
1422  }
1423  }).detach();
1424 
1425  __SUP_COUT__ << "Launched async MacroMaker Macro '" << macroName
1426  << "' for interfaceID '" << interfaceID
1427  << "' with taskID=" << task->taskID << __E__;
1428 
1429  // Wait briefly to see if macro finishes quickly (avoids unnecessary polling)
1430  {
1431  size_t sleepUs = 100;
1432  for(int i = 0; i < 10; ++i)
1433  {
1434  usleep(sleepUs);
1435  {
1436  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1437  if(task->done)
1438  {
1439  if(!task->error.empty())
1440  {
1441  std::string errorCopy = task->error;
1442  for(size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1443  if(asyncMacroTasks_[j]->taskID == task->taskID)
1444  {
1445  asyncMacroTasks_.erase(
1446  asyncMacroTasks_.begin() + j);
1447  break;
1448  }
1449  __SUP_SS__ << errorCopy;
1450  __SUP_SS_THROW__;
1451  }
1452  __SUP_COUT__
1453  << "DIAG ms=" << StringMacros::nowEpochMs()
1454  << " async macro finished within quick-wait,"
1455  << " returning synchronously, taskID=" << task->taskID
1456  << __E__;
1457  retParameters.addParameter("outputArgs",
1458  task->outputArgs);
1459  for(size_t j = 0; j < asyncMacroTasks_.size(); ++j)
1460  if(asyncMacroTasks_[j]->taskID == task->taskID)
1461  {
1462  asyncMacroTasks_.erase(asyncMacroTasks_.begin() +
1463  j);
1464  break;
1465  }
1466  return SOAPUtilities::makeSOAPMessageReference(
1467  supervisorClassNoNamespace_ + "Response",
1468  retParameters);
1469  }
1470  }
1471  sleepUs *= 2;
1472  if(sleepUs > 50000)
1473  sleepUs = 50000;
1474  }
1475  }
1476 
1477  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1478  << " async macro NOT done within quick-wait,"
1479  << " returning NotDoneTaskID=" << task->taskID << __E__;
1480  retParameters.addParameter("NotDoneTaskID", std::to_string(task->taskID));
1481  return SOAPUtilities::makeSOAPMessageReference(
1482  supervisorClassNoNamespace_ + "Response", retParameters);
1483  }
1484  else
1485  {
1486  // Synchronous path: run macro and return result (backward compatible)
1487  try
1488  {
1489  theFEInterfacesManager_->runMacro(
1490  interfaceID, macroString, inputArgs, outputArgs);
1491  }
1492  catch(std::runtime_error& e)
1493  {
1494  __SUP_SS__ << "In Supervisor with LID="
1495  << getApplicationDescriptor()->getLocalId()
1496  << " the MacroMaker Macro named '" << macroName
1497  << "' with target FE '" << interfaceID
1498  << "' failed. Here is the error:\n\n"
1499  << e.what() << __E__;
1500  __SUP_SS_THROW__;
1501  }
1502  catch(...)
1503  {
1504  __SUP_SS__ << "In Supervisor with LID="
1505  << getApplicationDescriptor()->getLocalId()
1506  << " the MacroMaker Macro named '" << macroName
1507  << "' with target FE '" << interfaceID
1508  << "' failed due to an unknown error." << __E__;
1509  try
1510  {
1511  throw;
1512  } //one more try to printout extra info
1513  catch(const std::exception& e)
1514  {
1515  ss << "Exception message: " << e.what();
1516  }
1517  catch(...)
1518  {
1519  }
1520  __SUP_SS_THROW__;
1521  }
1522 
1523  retParameters.addParameter("outputArgs", outputArgs);
1524  return SOAPUtilities::makeSOAPMessageReference(
1525  supervisorClassNoNamespace_ + "Response", retParameters);
1526  }
1527  }
1528  else if(request == "CheckMacro")
1529  {
1530  SOAPParameters requestParameters;
1531  requestParameters.addParameter("TaskID");
1532  SOAPUtilities::receive(message, requestParameters);
1533  uint64_t taskID = std::stoull(requestParameters.getValue("TaskID"));
1534 
1535  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1536 
1537  // Cleanup old completed tasks (>5 minutes after completion)
1538  time_t now = time(0);
1539  for(size_t i = 0; i < asyncMacroTasks_.size();)
1540  {
1541  auto& t = asyncMacroTasks_[i];
1542  if(t->done && t->doneTime > 0 && (now - t->doneTime) > 5 * 60)
1543  asyncMacroTasks_.erase(asyncMacroTasks_.begin() + i);
1544  else
1545  ++i;
1546  }
1547 
1548  // Find the requested task
1549  std::shared_ptr<AsyncMacroTask> foundTask;
1550  for(auto& t : asyncMacroTasks_)
1551  {
1552  if(t->taskID == taskID)
1553  {
1554  foundTask = t;
1555  break;
1556  }
1557  }
1558 
1559  if(!foundTask)
1560  {
1561  __SUP_SS__ << "Async macro task with ID=" << taskID
1562  << " was not found. Perhaps it completed more than 5 "
1563  "minutes ago?"
1564  << __E__;
1565  __SUP_SS_THROW__;
1566  }
1567 
1568  if(foundTask->done)
1569  {
1570  if(!foundTask->error.empty())
1571  {
1572  std::string errorCopy = foundTask->error;
1573  // Remove completed task
1574  for(size_t i = 0; i < asyncMacroTasks_.size(); ++i)
1575  {
1576  if(asyncMacroTasks_[i]->taskID == taskID)
1577  {
1578  asyncMacroTasks_.erase(asyncMacroTasks_.begin() + i);
1579  break;
1580  }
1581  }
1582  __SUP_SS__ << errorCopy;
1583  __SUP_SS_THROW__;
1584  }
1585 
1586  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1587  << " CheckMacro found task DONE (doneTime="
1588  << foundTask->doneTime << "), taskID=" << taskID << __E__;
1589  retParameters.addParameter("outputArgs", foundTask->outputArgs);
1590 
1591  // Remove completed task
1592  for(size_t i = 0; i < asyncMacroTasks_.size(); ++i)
1593  {
1594  if(asyncMacroTasks_[i]->taskID == taskID)
1595  {
1596  asyncMacroTasks_.erase(asyncMacroTasks_.begin() + i);
1597  break;
1598  }
1599  }
1600 
1601  return SOAPUtilities::makeSOAPMessageReference(
1602  supervisorClassNoNamespace_ + "Response", retParameters);
1603  }
1604  else
1605  {
1606  // Still running — check for real progress from the FE macro
1607  if(theFEInterfacesManager_ && foundTask->threadID != std::thread::id())
1608  {
1609  try
1610  {
1611  int progress = theFEInterfacesManager_
1612  ->getFEInterfaceP(foundTask->interfaceID)
1613  ->getFEMacroPercentDone(foundTask->threadID);
1614  if(progress >= 0)
1615  retParameters.addParameter("Progress",
1616  std::to_string(progress));
1617  }
1618  catch(...)
1619  {
1620  }
1621  }
1622  __SUP_COUT__ << "DIAG ms=" << StringMacros::nowEpochMs()
1623  << " CheckMacro found task still RUNNING, taskID=" << taskID
1624  << __E__;
1625  retParameters.addParameter("NotDoneTaskID", std::to_string(taskID));
1626  return SOAPUtilities::makeSOAPMessageReference(
1627  supervisorClassNoNamespace_ + "Response", retParameters);
1628  }
1629  }
1630  else
1631  {
1632  __SUP_SS__ << "Unrecognized request received! '" << request << "'" << __E__;
1633  __SUP_SS_THROW__;
1634  }
1635  }
1636  catch(const std::runtime_error& e)
1637  {
1638  __SUP_SS__ << "Error occurred handling request: " << e.what() << __E__;
1639  __SUP_COUT_ERR__ << ss.str();
1640  retParameters.addParameter("Error", ss.str());
1641  }
1642  catch(...)
1643  {
1644  __SUP_SS__ << "Error occurred handling request." << __E__;
1645  try
1646  {
1647  throw;
1648  } //one more try to printout extra info
1649  catch(const std::exception& e)
1650  {
1651  ss << "Exception message: " << e.what();
1652  }
1653  catch(...)
1654  {
1655  }
1656  __SUP_COUT_ERR__ << ss.str();
1657  retParameters.addParameter("Error", ss.str());
1658  }
1659 
1660  return SOAPUtilities::makeSOAPMessageReference(
1661  supervisorClassNoNamespace_ + "FailRequest", retParameters);
1662 
1663 } // end macroMakerSupervisorRequest()
1664 
1665 //==============================================================================
1666 xoap::MessageReference FESupervisor::workLoopStatusRequest(
1667  xoap::MessageReference /*message*/)
1668 {
1669  if(!theFEInterfacesManager_)
1670  {
1671  __SUP_SS__ << "Invalid request for front-end workloop status from Supervisor "
1672  "without a FEVInterfacesManager."
1673  << __E__;
1674  __SUP_SS_THROW__;
1675  }
1676 
1677  return SOAPUtilities::makeSOAPMessageReference(
1678  (theFEInterfacesManager_->allFEWorkloopsAreDone()
1679  ? CoreSupervisorBase::WORK_LOOP_DONE
1680  : CoreSupervisorBase::WORK_LOOP_WORKING));
1681 } // end workLoopStatusRequest()
1682 
1683 //==============================================================================
1691 FEVInterfacesManager* FESupervisor::extractFEInterfacesManager()
1692 {
1693  theFEInterfacesManager_ = 0;
1694 
1695  for(unsigned int i = 0; i < theStateMachineImplementation_.size(); ++i)
1696  {
1697  try
1698  {
1699  theFEInterfacesManager_ =
1700  dynamic_cast<FEVInterfacesManager*>(theStateMachineImplementation_[i]);
1701  if(!theFEInterfacesManager_)
1702  {
1703  // dynamic_cast returns null pointer on failure
1704  __SUP_SS__ << "Dynamic cast failure!" << __E__;
1705  __SUP_SS_THROW__;
1706  }
1707  __SUP_COUT__ << "State Machine " << i << " WAS of type FEVInterfacesManager"
1708  << __E__;
1709 
1710  break;
1711  }
1712  catch(...)
1713  {
1714  __SUP_COUT__ << "State Machine " << i
1715  << " was NOT of type FEVInterfacesManager" << __E__;
1716  }
1717  }
1718 
1719  __SUP_COUT__ << "theFEInterfacesManager pointer = " << theFEInterfacesManager_
1720  << __E__;
1721 
1722  return theFEInterfacesManager_;
1723 } // end extractFEInterfaceManager()
1724 
1725 //==============================================================================
1726 void FESupervisor::transitionConfiguring(toolbox::Event::Reference /*event*/)
1727 {
1728  __SUP_COUT__ << "transitionConfiguring" << __E__;
1729  CoreSupervisorBase::configureInit();
1730 
1731  // get pset from Board Reader metric manager table
1732  try
1733  {
1734  __COUTV__(CorePropertySupervisorBase::getSupervisorConfigurationPath());
1735 
1736  ConfigurationTree feSupervisorNode =
1737  CorePropertySupervisorBase::getSupervisorTableNode();
1738 
1739  std::string metric_string = "";
1740  bool metricStringSetup = true;
1741  try
1742  {
1743  std::ostringstream oss;
1744  std::string tabString = "";
1745  std::string commentsString = "";
1747  oss, tabString, commentsString, "" /* parentPath*/, feSupervisorNode);
1748  metric_string = oss.str();
1749  }
1750  catch(...)
1751  {
1752  metricStringSetup = false;
1753  metric_string = "";
1754  } // ignore error
1755 
1756  if(!metricMan)
1757  {
1758  __SUP_COUT__ << "Metric manager is not instantiated! Attempting to fix."
1759  << __E__;
1760  metricMan = std::make_unique<artdaq::MetricManager>();
1761  }
1762  std::string metricNamePreamble =
1763  feSupervisorNode.getNode("/SlowControlsMetricManagerChannelNamePreamble")
1764  .getValueWithDefault<std::string>("");
1765  __SUP_COUTV__(metricNamePreamble);
1766 
1767  // std::string metric_string = "epics: {metricPluginType:epics level:3 channel_name_prefix:Mu2e}";
1768  fhicl::ParameterSet metric_pset = fhicl::ParameterSet::make(metric_string);
1769 
1770  __SUP_COUTV__(metricNamePreamble);
1771  try
1772  {
1773  metricMan->initialize(metric_pset.get<fhicl::ParameterSet>("metrics"),
1774  metricNamePreamble);
1775  }
1776  catch(...)
1777  {
1778  if(metricStringSetup)
1779  throw;
1780  else
1781  __SUP_COUT__ << "Ignore metric manager initialize error because metric "
1782  "string is not setup."
1783  << __E__;
1784  }
1785  __SUP_COUT__ << "transitionConfiguring metric manager(" << metricMan
1786  << ") initialized = " << metricMan->Initialized() << __E__;
1787  }
1788  catch(const std::runtime_error& e)
1789  {
1790  __SS__ << "Error loading metrics in FESupervisor::transitionConfiguring(): "
1791  << e.what() << __E__;
1792  __SUP_COUT_ERR__ << ss.str();
1793  // ExceptionHandler(ExceptionHandlerRethrow::no, ss.str());
1794 
1795  //__SS_THROW_ONLY__;
1796  theStateMachine_.setErrorMessage(ss.str());
1797  throw toolbox::fsm::exception::Exception(
1798  "Transition Error" /*name*/,
1799  ss.str() /* message*/,
1800  "FESupervisor::transitionConfiguring" /*module*/,
1801  __LINE__ /*line*/,
1802  __FUNCTION__ /*function*/
1803  );
1804  }
1805  catch(...)
1806  {
1807  __SS__ << "Error loading metrics in FESupervisor::transitionConfiguring()"
1808  << __E__;
1809  try
1810  {
1811  throw;
1812  } //one more try to printout extra info
1813  catch(const std::exception& e)
1814  {
1815  ss << "Exception message: " << e.what();
1816  }
1817  catch(...)
1818  {
1819  }
1820  __SUP_COUT_ERR__ << ss.str();
1821  // ExceptionHandler(ExceptionHandlerRethrow::no, ss.str());
1822 
1823  //__SS_THROW_ONLY__;
1824  theStateMachine_.setErrorMessage(ss.str());
1825  throw toolbox::fsm::exception::Exception(
1826  "Transition Error" /*name*/,
1827  ss.str() /* message*/,
1828  "FESupervisor::transitionConfiguring" /*module*/,
1829  __LINE__ /*line*/,
1830  __FUNCTION__ /*function*/
1831  );
1832  }
1833 
1834  CoreSupervisorBase::transitionConfiguringFSMs();
1835 
1836  __SUP_COUT__ << "transitionConfiguring done." << __E__;
1837 } // end transitionConfiguring()
1838 
1839 //==============================================================================
1840 void FESupervisor::transitionHalting(toolbox::Event::Reference event)
1841 {
1842  __SUP_COUT__ << "transitionHalting" << __E__;
1843  TLOG_DEBUG(7) << "transitionHalting";
1844 
1845  // Wait for any in-flight async macro tasks before tearing down FE interfaces
1846  {
1847  const int timeoutSeconds = 30;
1848  const time_t deadline = time(0) + timeoutSeconds;
1849  bool hasOutstanding = true;
1850  while(hasOutstanding && time(0) < deadline)
1851  {
1852  {
1853  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1854  hasOutstanding = false;
1855  for(const auto& t : asyncMacroTasks_)
1856  {
1857  if(!t->done)
1858  {
1859  hasOutstanding = true;
1860  break;
1861  }
1862  }
1863  }
1864  if(hasOutstanding)
1865  {
1866  __SUP_COUT__ << "Waiting for outstanding async macro tasks to complete "
1867  "before halting..."
1868  << __E__;
1869  usleep(500 * 1000);
1870  }
1871  }
1872  if(hasOutstanding)
1873  __SUP_COUT_WARN__ << "Timed out waiting for async macro tasks; "
1874  "proceeding with halt."
1875  << __E__;
1876  std::lock_guard<std::mutex> lock(asyncMacroMutex_);
1877  asyncMacroTasks_.clear();
1878  }
1879 
1880  // shutdown workloops first, then shutdown metric manager
1882 
1883  try
1884  {
1885  if(metricMan && metricMan->Initialized())
1886  {
1887  TLOG_DEBUG(7) << "Metric manager(" << metricMan << ") shutting down..."
1888  << __E__;
1889  metricMan
1890  ->shutdown(); // will set initilized_ to false with mutex, which should prevent races
1891  TLOG_DEBUG(7) << "Metric manager shutdown." << __E__;
1892  }
1893  else
1894  __SUP_COUT__ << "Metric manager(" << metricMan << ") already shutdown."
1895  << __E__;
1896 
1897  metricMan.reset(nullptr);
1898  }
1899  catch(...)
1900  {
1901  __SS__ << "Error shutting down metrics in FESupervisor::transitionHalting()"
1902  << __E__;
1903  try
1904  {
1905  throw;
1906  } //one more try to printout extra info
1907  catch(const std::exception& e)
1908  {
1909  ss << "Exception message: " << e.what();
1910  }
1911  catch(...)
1912  {
1913  }
1914  __SUP_COUT_ERR__ << ss.str();
1915  // ExceptionHandler(ExceptionHandlerRethrow::no, ss.str());
1916 
1917  //__SS_THROW_ONLY__;
1918  theStateMachine_.setErrorMessage(ss.str());
1919  throw toolbox::fsm::exception::Exception(
1920  "Transition Error" /*name*/,
1921  ss.str() /* message*/,
1922  "FESupervisor::transitionHalting" /*module*/,
1923  __LINE__ /*line*/,
1924  __FUNCTION__ /*function*/
1925  );
1926  }
1927 
1928  __SUP_COUT__ << "transitionHalting done." << __E__;
1929 } // end transitionHalting()
1930 
1931 //==============================================================================
1932 void FESupervisor::initDataPublishing(const std::string& endpoint,
1933  const std::string& topic)
1934 {
1935  if(dp_isInitialized_)
1936  {
1937  // silently re‑initialise – close old socket first.
1938  closeDataPublishing(false);
1939  }
1940 
1941  // Store for later use.
1942  dp_endpoint_ = endpoint;
1943  dp_topic_ = topic;
1944 
1945  // Bind the PUB socket.
1946  try
1947  {
1948  dp_socket_.bind(dp_endpoint_);
1949  }
1950  catch(const zmq::error_t& e)
1951  {
1952  __SUP_SS__ << "initDataPublishing() - bind to zmq '" + dp_endpoint_ +
1953  "' failed: " + e.what()
1954  << __E__;
1955  __SUP_SS_THROW__;
1956  }
1957 
1958  dp_isInitialized_ = true;
1959 } //end initDataPublishing()
1960 
1961 //==============================================================================
1962 void FESupervisor::closeDataPublishing(bool alsoCloseContext /* = true */)
1963 {
1964  if(dp_isInitialized_)
1965  {
1966  try
1967  {
1968  dp_socket_.set(zmq::sockopt::linger, 0); // discard unsent messages on close
1969  dp_socket_.close(); // close the PUB socket
1970  }
1971  catch(const zmq::error_t&)
1972  {
1973  // ignore – we are cleaning up.
1974  }
1975  try
1976  {
1977  if(alsoCloseContext)
1978  dp_context_.close(); // close the ZMQ context
1979  }
1980  catch(const zmq::error_t&)
1981  {
1982  // ignore.
1983  }
1984  dp_isInitialized_ = false;
1985  }
1986 } //end closeDataPublishing()
1987 
1988 //==============================================================================
1996 void FESupervisor::publishData(const char* dataPtr, size_t dataSize)
1997 {
1998  if(!dp_isInitialized_)
1999  {
2000  __SUP_SS__ << "publishData() called before zmq init()" << __E__;
2001  __SUP_SS_THROW__;
2002  }
2003 
2004  // ---- Topic frame (must be sent with sndmore) ----
2005  // Using zmq::buffer prevents an extra copy – it just points at the data.
2006  auto rc_topic = dp_socket_.send(zmq::buffer(dp_topic_), zmq::send_flags::sndmore);
2007  if(!rc_topic)
2008  {
2009  __SUP_SS__ << "publishData() - failed to send zmq topic" << __E__;
2010  __SUP_SS_THROW__;
2011  }
2012 
2013  // ---- Payload frame (final frame) ----
2014  // `dataPtr` may be nullptr only if `dataSize == 0` – ZeroMQ accepts an empty frame.
2015  if(dataPtr == nullptr && dataSize > 0)
2016  {
2017  __SUP_SS__ << "FESupervisor::publishData() - dataPtr is nullptr but dataSize is "
2018  << dataSize << __E__;
2019  __SUP_SS_THROW__;
2020  }
2021  auto rc_payload =
2022  dp_socket_.send(zmq::buffer(dataPtr, dataSize), zmq::send_flags::none);
2023  if(!rc_payload)
2024  {
2025  __SUP_SS__ << "publishData() - failed to send zmq payload" << __E__;
2026  __SUP_SS_THROW__;
2027  }
2028 } //end publishData()
static void insertMetricsBlock(std::ostream &out, std::string &tabStr, std::string &commentStr, const std::string &parentPath, ConfigurationTree daqNode)
insertMetricsBlock
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
T getValueWithDefault(const T &defaultValue) const
static void extractPermissionsMapFromString(const std::string &permissionsString, std::map< std::string, WebUsers::permissionLevel_t > &permissionsMap)
static bool doPermissionsGrantAccess(std::map< std::string, WebUsers::permissionLevel_t > &permissionLevelsMap, std::map< std::string, WebUsers::permissionLevel_t > &permissionThresholdsMap)
virtual void transitionHalting(toolbox::Event::Reference event)
virtual void request(const std::string &requestType, cgicc::Cgicc &cgiIn, HttpXmlDocument &xmlOut, const WebUsers::RequestUserInfo &userInfo)
void publishData(const char *dataPtr, size_t dataSize)
virtual void transitionHalting(toolbox::Event::Reference event) override
void initDataPublishing(const std::string &endpoint, const std::string &topic="test")
void closeDataPublishing(bool alsoCloseContext=true)
xoap::MessageReference macroMakerSupervisorRequest(xoap::MessageReference message)
const FEVInterface & getFEInterface(const std::string &interfaceID) const
getFEInterface
std::string getFEMacrosString(const std::string &supervisorName, const std::string &supervisorLid)
used by MacroMaker
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.
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)
bool checkMacroMultiDimensional(const std::string &interfaceID, const std::string &macroName, std::string *outputFile=nullptr)
used by iterator calling (i.e. FESupervisor); on Done, outputFile receives the saved-output path ("" ...
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
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)
std::mutex frontEndCommunicationReceiveMutex_
FE communication helpers.
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
defines used also by OtsConfigurationWizardSupervisor
< members fully define a front-end macro function
Definition: FEVInterface.h:180
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")