otsdaq_utilities  v2_02_00
MacroMakerSupervisor.cc
1 #include "otsdaq-utilities/MacroMaker/MacroMakerSupervisor.h"
2 
3 //#include "otsdaq-core/MessageFacility/MessageFacility.h"
4 //#include "otsdaq-core/Macros/CoutMacros.h"
5 //#include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
6 //#include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
7 //#include "otsdaq-core/SOAPUtilities/SOAPUtilities.h"
8 //#include "otsdaq-core/SOAPUtilities/SOAPParameters.h"
9 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationGroupKey.h"
10 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
11 //#include "otsdaq-core/Macros/CoutMacros.h"
12 
13 
14 #include "otsdaq-core/FECore/FEVInterface.h"
15 
16 
17 #include "otsdaq-core/CodeEditor/CodeEditor.h"
18 
19 //#include <xdaq/NamespaceURI.h>
20 //#include <string>
21 //#include <vector>
22 //#include <iostream>
23 #include <fstream>
24 //#include <sstream>
25 #include <cstdio>
26 #include <stdio.h> //for file rename
27 #include <dirent.h> //for DIR
28 #include <sys/stat.h> //for mkdir
29 #include <thread> //for std::thread
30 
31 #define MACROS_DB_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/MacroData/"
32 #define MACROS_HIST_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/MacroHistory/"
33 #define MACROS_EXPORT_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/MacroExport/"
34 
35 using namespace ots;
36 
37 #undef __MF_SUBJECT__
38 #define __MF_SUBJECT__ "MacroMaker"
39 
40 XDAQ_INSTANTIATOR_IMPL(MacroMakerSupervisor)
41 
42 //========================================================================================================================
43 MacroMakerSupervisor::MacroMakerSupervisor(xdaq::ApplicationStub* stub)
44 : CoreSupervisorBase(stub)
45 {
46  INIT_MF("MacroMaker");
47 
48  //make macro directories in case they don't exist
49  mkdir(((std::string)MACROS_DB_PATH).c_str(), 0755);
50  mkdir(((std::string)MACROS_HIST_PATH).c_str(), 0755);
51  mkdir(((std::string)MACROS_EXPORT_PATH).c_str(), 0755);
52 
53  xoap::bind(this, &MacroMakerSupervisor::frontEndCommunicationRequest,
54  "FECommunication", XDAQ_NS_URI );
55 
56  init();
57 }
58 
59 //========================================================================================================================
60 MacroMakerSupervisor::~MacroMakerSupervisor(void)
61 {
62  destroy();
63 }
64 
65 //========================================================================================================================
66 void MacroMakerSupervisor::init(void)
67 {
68  //called by constructor
69 
70  //MacroMaker should consider all FE compatible types..
71  allFESupervisorInfo_ = allSupervisorInfo_.getAllFETypeSupervisorInfo();
72 }
73 
74 //========================================================================================================================
75 void MacroMakerSupervisor::destroy(void)
76 {
77  //called by destructor
78 }
79 
80 //========================================================================================================================
81 //forceSupervisorPropertyValues
82 // override to force supervisor property values (and ignore user settings)
83 void MacroMakerSupervisor::forceSupervisorPropertyValues()
84 {
85 // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes,
86 // "getPermission");
87 }
88 
89 //========================================================================================================================
90 void MacroMakerSupervisor::request(const std::string& requestType, cgicc::Cgicc& cgiIn,
91  HttpXmlDocument& xmlOut, const WebUsers::RequestUserInfo& userInfo)
92 try
93 {
94  __SUP_COUT__ << "User name is " << userInfo.username_ << "." << __E__;
95  __SUP_COUT__ << "User permission level for request '" << requestType << "' is " <<
96  unsigned(userInfo.permissionLevel_) << "." << __E__;
97 
98 
99  //handle request per requestType
100  if(requestType == "getPermission")
101  {
102  xmlOut.addTextElementToData("Permission", std::to_string(unsigned(userInfo.permissionLevel_)));
103 
104  //create macro maker folders for the user (the first time a user authenticates with macro maker)
105  std::string macroPath = (std::string)MACROS_DB_PATH + userInfo.username_ + "/";
106  mkdir(macroPath.c_str(), 0755);
107  std::string histPath = (std::string)MACROS_HIST_PATH + userInfo.username_ + "/";
108  mkdir(histPath.c_str(), 0755);
109  std::string publicPath = (std::string)MACROS_DB_PATH + "publicMacros/";
110  mkdir(publicPath.c_str(), 0755);
111  std::string exportPath = (std::string)MACROS_EXPORT_PATH + userInfo.username_ + "/";
112  mkdir(exportPath.c_str(), 0755);
113  }
114  else
115  handleRequest(requestType,xmlOut,cgiIn,userInfo.username_);
116 }
117 catch(const std::runtime_error& e)
118 {
119  __SS__ << "Error occurred handling request '" << requestType <<
120  "': " << e.what() << __E__;
121  __SUP_COUT__ << ss.str();
122  xmlOut.addTextElementToData("Error",ss.str());
123 }
124 catch(...)
125 {
126  __SS__ << "Unknown error occurred handling request '" << requestType <<
127  "!'" << __E__;
128  __SUP_COUT__ << ss.str();
129  xmlOut.addTextElementToData("Error",ss.str());
130 }
131 
132 //========================================================================================================================
133 void MacroMakerSupervisor::handleRequest(const std::string Command,
134  HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi,
135  const std::string &username)
136 {
137  if(Command == "FElist")
138  getFElist(xmldoc);
139  else if(Command == "writeData")
140  writeData(xmldoc,cgi,username);
141  else if(Command == "readData")
142  readData(xmldoc,cgi,username);
143  else if(Command == "createMacro")
144  createMacro(xmldoc,cgi,username);
145  else if(Command == "loadMacros")
146  loadMacros(xmldoc,username);
147  else if(Command == "loadHistory")
148  loadHistory(xmldoc,username);
149  else if(Command == "deleteMacro")
150  deleteMacro(xmldoc,cgi,username);
151  else if(Command == "editMacro")
152  editMacro(xmldoc,cgi,username);
153  else if(Command == "clearHistory")
154  clearHistory(username);
155  else if(Command == "exportMacro")
156  exportMacro(xmldoc,cgi,username);
157  else if(Command == "exportFEMacro")
158  exportFEMacro(xmldoc,cgi,username);
159  else if(Command == "getFEMacroList")
160  getFEMacroList(xmldoc,username);
161  else if(Command == "runFEMacro")
162  runFEMacro(xmldoc,cgi);
163  else
164  xmldoc.addTextElementToData("Error","Unrecognized command '" + Command + "'");
165 }
166 
167 
168 //========================================================================================================================
169 xoap::MessageReference MacroMakerSupervisor::frontEndCommunicationRequest(xoap::MessageReference message)
170 try
171 {
172  __SUP_COUT__<< "FE Request received: " << SOAPUtilities::translate(message) << __E__;
173 
174  SOAPParameters typeParameter, rxParameters; //params for xoap to recv
175  typeParameter.addParameter("type");
176  SOAPUtilities::receive(message, typeParameter);
177 
178  std::string type = typeParameter.getValue("type");
179 
180  std::string error = "";
181 
182 
183  if(type == "initFElist") //gateway initializes during configure
184  {
185  __SUP_COUTV__(type);
186 
187  rxParameters.addParameter("groupName");
188  rxParameters.addParameter("groupKey");
189  SOAPUtilities::receive(message, rxParameters);
190 
191  std::string groupName = rxParameters.getValue("groupName");
192  std::string groupKey = rxParameters.getValue("groupKey");
193 
194  __SUP_COUTV__(groupName);
195  __SUP_COUTV__(groupKey);
196 
197  ConfigurationManager cfgMgr;
198  cfgMgr.loadConfigurationGroup(
199  groupName, ConfigurationGroupKey(groupKey), true);
200 
201  //for each FESupervisor
202  // get all front end children
203 
204  const SupervisorInfoMap& feTypeSupervisors =
205  CorePropertySupervisorBase::allSupervisorInfo_.getAllFETypeSupervisorInfo();
206 
207  ConfigurationTree appsNode =
208  cfgMgr.getNode("XDAQApplicationConfiguration");
209 
210  for(auto& feApp:feTypeSupervisors)
211  {
212  __SUP_COUT__ << "FEs for app " << feApp.first << ":" <<
213  feApp.second.getName() << __E__;
214 
215  std::vector<std::string> feChildren =
216  appsNode.getNode(feApp.second.getName()).
217  getNode("LinkToSupervisorTable").
218  getNode("LinkToFEInterfaceTable").getChildrenNames();
219 
220  for(auto& fe:feChildren)
221  {
222  __COUTV__(fe);
223  FEtoSupervisorMap_[fe] = feApp.first;
224  }
225  }
226 
227  __SUP_COUTV__(StringMacros::mapToString(FEtoSupervisorMap_));
228  }
229  else if(type == "feSend" || //from front-ends
230  type == "feMacro" || //from front-ends
231  type == "feMacroMultiDimensionalStart" || //from iterator
232  type == "feMacroMultiDimensionalCheck" || //from iterator
233  type == "macroMultiDimensionalStart" || //from iterator
234  type == "macroMultiDimensionalCheck") //from iterator
235  {
236  __SUP_COUTV__(type);
237 
238  rxParameters.addParameter("targetInterfaceID");
239  SOAPUtilities::receive(message, rxParameters);
240 
241  std::string targetInterfaceID = rxParameters.getValue("targetInterfaceID");
242 
243  __SUP_COUTV__(targetInterfaceID);
244 
245  auto feIt = FEtoSupervisorMap_.find(targetInterfaceID);
246  if(feIt == FEtoSupervisorMap_.end())
247  {
248  __SUP_SS__ << "Destination front end interface ID '" <<
249  targetInterfaceID << "' was not found in the list of front ends." << __E__;
250  __SUP_SS_THROW__;
251  }
252 
253  unsigned int FESupervisorIndex = feIt->second;
254  __SUP_COUT__ << "Found supervisor index: " << FESupervisorIndex << __E__;
255 
256  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
257  if (it == allFESupervisorInfo_.end())
258  {
259  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
260  targetInterfaceID << ":" << FESupervisorIndex << ".' \n\n" <<
261  "The FE Supervisor Index does not exist. Have you configured the state machine properly?" << __E__;
262  __SUP_SS_THROW__;
263  }
264 
265  if(type == "macroMultiDimensionalStart")
266  {
267  //add Macro sequence (and check macro exists)
268 
269 
270  SOAPParameters rxParameters;
271  rxParameters.addParameter("macroName");
272  SOAPUtilities::receive(message, rxParameters);
273  std::string macroName = rxParameters.getValue("macroName");
274  __SUP_COUTV__(macroName);
275 
276  //MacroMakerSupervisor::macroStruct_t macro;
277  std::string macroString;
278  loadMacro(macroName,macroString);
279 
280  SOAPParameters parameters;
281  parameters.addParameter("macroString", macroString);
282  SOAPUtilities::addParameters(message, parameters);
283  }
284 
285 
286  try
287  {
288  __SUP_COUT__ << "Forwarding request: " <<
289  SOAPUtilities::translate(message) << __E__;
290 
291  xoap::MessageReference replyMessage = SOAPMessenger::sendWithSOAPReply(
292  it->second.getDescriptor(),
293  message);
294 
295  if(type != "feSend")
296  {
297  __SUP_COUT__ << "Forwarding FE Macro response: " <<
298  SOAPUtilities::translate(replyMessage) << __E__;
299 
300  return replyMessage;
301  }
302  }
303  catch(const xdaq::exception::Exception& e)
304  {
305  __SUP_SS__ << "Error forwarding FE Communication request to FE Supervisor '" <<
306  targetInterfaceID << ":" << FESupervisorIndex << ".' " <<
307  "Have you configured the state machine properly?\n\n" <<
308  e.what() << __E__;
309  __SUP_SS_THROW__;
310  }
311  }
312  else
313  {
314  __SUP_SS__ << "Unrecognized FE Communication type: " << type << __E__;
315  __SUP_SS_THROW__;
316  }
317 
318  return SOAPUtilities::makeSOAPMessageReference("Received");
319 } //end frontEndCommunicationRequest()
320 catch(const std::runtime_error& e)
321 {
322  xoap::MessageReference returnMessage =
323  SOAPUtilities::makeSOAPMessageReference("Error");
324 
325  SOAPParameters parameters;
326  parameters.addParameter("Error", e.what());
327  SOAPUtilities::addParameters(returnMessage, parameters);
328  return returnMessage;
329 }
330 catch(...)
331 {
332  xoap::MessageReference returnMessage =
333  SOAPUtilities::makeSOAPMessageReference("Error");
334 
335  __SUP_SS__ << "Unknown error processing FE communication request." << __E__;
336  __SUP_COUT_ERR__ << ss.str();
337 
338  SOAPParameters parameters;
339  parameters.addParameter("Error", ss.str());
340  SOAPUtilities::addParameters(returnMessage, parameters);
341  return returnMessage;
342 } //end frontEndCommunicationRequest() catch
343 
344 //========================================================================================================================
345 void MacroMakerSupervisor::getFElist(HttpXmlDocument& xmldoc)
346 {
347  __SUP_COUT__<< "Getting FE list!!!!!!!!!" << __E__;
348  FEtoSupervisorMap_.clear();
349 
350  SOAPParameters txParameters; //params for xoap to send
351  txParameters.addParameter("Request", "GetInterfaces");
352 
353  SOAPParameters rxParameters; //params for xoap to recv
354  rxParameters.addParameter("FEList");
355 
356  SupervisorInfoMap::const_iterator it;
357  std::string oneInterface;
358  std::string rxFEList;
359 
360  size_t lastColonIndex;
361 
362  //for each list of FE Supervisors,
363  // loop through each FE Supervisors and get FE interfaces list
364  for(auto &appInfo:allFESupervisorInfo_)
365  {
366  // __SUP_COUT__ << "Number of " << listPair.first << " = " <<
367  // listPair.second.size() << __E__;
368  //
369  // for (it = listPair.second.begin(); it != listPair.second.end(); it++)
370  // {
371 
372  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId() <<
373  " name = " << appInfo.second.getName() << __E__;
374 
375  try
376  {
377  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
378  appInfo.second.getDescriptor(),
379  "MacroMakerSupervisorRequest",
380  txParameters);
381  SOAPUtilities::receive(retMsg, rxParameters);
382  }
383  catch(const xdaq::exception::Exception& e)
384  {
385  __SS__ << "Error transmitting request to FE Supervisor LID = " << appInfo.second.getId() <<
386  " name = " << appInfo.second.getName() << ". \n\n" << e.what() << __E__;
387  __SUP_COUT_ERR__ << ss.str();
388  return;
389  }
390 
391  rxFEList = rxParameters.getValue("FEList");
392 
393  __SUP_COUT__ << "FE List received: \n" << rxFEList << __E__;
394 
395  std::istringstream allInterfaces(rxFEList);
396  while (std::getline(allInterfaces, oneInterface))
397  {
398  __SUP_COUTV__(oneInterface);
399  xmldoc.addTextElementToData("FE",oneInterface);
400 
401  lastColonIndex = oneInterface.rfind(':');
402  if(lastColonIndex == std::string::npos)
403  {
404  __SUP_SS__ << "Last colon could not be found in " << oneInterface << __E__;
405  __SS_THROW__;
406  }
407  oneInterface = oneInterface.substr(lastColonIndex);
408 
409  __SUP_COUTV__(oneInterface);
410 
411  FEtoSupervisorMap_[oneInterface] = appInfo.second.getId();
412  } //end FE extract loop
413 
414  } //end ask Supervisors for their FE list loop
415 
416 } //end getFEList()
417 
418 
419 //========================================================================================================================
420 void MacroMakerSupervisor::writeData(
421  HttpXmlDocument& xmldoc,
422  cgicc::Cgicc& cgi,
423  const std::string &username)
424 {
425  __SUP_COUT__<< "MacroMaker writing..." << __E__;
426 
427  std::string Address = CgiDataUtilities::getData(cgi, "Address");
428  std::string Data = CgiDataUtilities::getData(cgi, "Data");
429  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
430  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
431  std::string time = CgiDataUtilities::decodeURIComponent(
432  CgiDataUtilities::getData(cgi, "time"));
433  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
434  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
435 
436  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
437 
438  __SUP_COUT__<< "Write Address: " << Address << " Data: " << Data << __E__;
439  __SUP_COUTV__(interfaces);
440 
441  std::string command = "w:" + Address + ":" + Data;
442  std::string format = addressFormatStr + ":" + dataFormatStr;
443  appendCommandToHistory(command,format,time,interfaces,username);
444 
445  SOAPParameters txParameters; //params for xoap to send
446  txParameters.addParameter("Request", "UniversalWrite");
447  txParameters.addParameter("Address",Address);
448  txParameters.addParameter("Data",Data);
449 
450 
451  __SUP_COUT__<< "Here comes the array from multiselect box for WRITE, behold: \n"
452  << supervisorIndexArray << "\n" << interfaceIndexArray << __E__;
453 
455  std::vector<std::string> interfaceIndices;
456  std::istringstream f(interfaceIndexArray);
457  std::string s;
458  while (getline(f, s, ',')) interfaceIndices.push_back(s);
459  std::vector<int> supervisorIndices;
460  std::istringstream g(supervisorIndexArray);
461  std::string t;
462  while (getline(g, t, ',')) supervisorIndices.push_back(std::stoi(t));
463 
464 
465  for(unsigned int i=0; i < supervisorIndices.size(); i++)
466  {
467  unsigned int FESupervisorIndex = supervisorIndices[i];
468  std::string interfaceIndex = interfaceIndices[i];
469 
470  txParameters.addParameter("InterfaceID",interfaceIndex);
471 
472  __SUP_COUT__<< "The index of the supervisor instance is: " << FESupervisorIndex << __E__;
473  __SUP_COUT__<< "...and the interface ID is: " << interfaceIndex << __E__;
474 
475  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
476  if (it == allFESupervisorInfo_.end())
477  {
478  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
479  interfaceIndex << ":" << FESupervisorIndex << ".' \n\n" <<
480  "The FE Index doesn't exist. Have you configured the state machine properly?" << __E__;
481  __SUP_SS_THROW__;
482  }
483 
484  try
485  {
486  xoap::MessageReference replyMessage = SOAPMessenger::sendWithSOAPReply(
487  it->second.getDescriptor(),
488  "MacroMakerSupervisorRequest",
489  txParameters);
490 
491  __SUP_COUT__ << "Response received: " <<
492  SOAPUtilities::translate(replyMessage) << __E__;
493 
494  SOAPParameters rxParameters;
495  rxParameters.addParameter("Error");
496  SOAPUtilities::receive(replyMessage,rxParameters);
497 
498  std::string error = rxParameters.getValue("Error");
499  __SUP_COUTV__(error);
500 
501  if(error != "")
502  {
503  //error occurred!
504  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
505  interfaceIndex << ":" << FESupervisorIndex << ".' " <<
506  "Have you configured the state machine properly?\n\n" <<
507  error << __E__;
508  __SUP_SS_THROW__;
509  }
510  }
511  catch(const xdaq::exception::Exception& e)
512  {
513  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
514  interfaceIndex << ":" << FESupervisorIndex << ".' " <<
515  "Have you configured the state machine properly?\n\n" <<
516  e.what() << __E__;
517  __SUP_SS_THROW__;
518  }
519 
520 
521  } //end FE Supervisor loop
522 } //end writeData()
523 
524 //========================================================================================================================
525 void MacroMakerSupervisor::readData(HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi, const std::string &username)
526 {
527  __SUP_COUT__<< "@@@@@@@ MacroMaker wants to read data @@@@@@@@" << __E__;
528  std::string Address = CgiDataUtilities::getData(cgi, "Address");
529  std::string interfaceIndexArray = CgiDataUtilities::getData(cgi, "interfaceIndex");
530  std::string supervisorIndexArray = CgiDataUtilities::getData(cgi, "supervisorIndex");
531  std::string time = CgiDataUtilities::decodeURIComponent(
532  CgiDataUtilities::getData(cgi, "time"));
533  std::string addressFormatStr = CgiDataUtilities::getData(cgi, "addressFormatStr");
534  std::string dataFormatStr = CgiDataUtilities::getData(cgi, "dataFormatStr");
535 
536  std::string interfaces = CgiDataUtilities::postData(cgi, "interfaces");
537 
538 
539  __SUP_COUT__<< "Read Address: " << Address << __E__;
540  __SUP_COUTV__(interfaces);
541 
542  SOAPParameters txParameters; //params for xoap to send
543  txParameters.addParameter("Request", "UniversalRead");
544  txParameters.addParameter("Address",Address);
545 
546  SOAPParameters rxParameters;
547  rxParameters.addParameter("dataResult");
548  rxParameters.addParameter("Error");
549  __SUP_COUT__<< "Here comes the array from multiselect box for READ, behold: "
550  << supervisorIndexArray << "," << interfaceIndexArray << __E__;
551 
552 
554  std::vector<std::string> interfaceIndices;
555  std::istringstream f(interfaceIndexArray);
556  std::string s;
557  while (getline(f, s, ',')) interfaceIndices.push_back(s);
558  std::vector<int> supervisorIndices;
559  std::istringstream g(supervisorIndexArray);
560  std::string t;
561  while (getline(g, t, ',')) supervisorIndices.push_back(std::stoi(t));
562 
563  for(unsigned int i=0; i < supervisorIndices.size(); i++)
564  {
565  unsigned int FESupervisorIndex = supervisorIndices[i];
566  std::string interfaceIndex = interfaceIndices[i];
567 
568  txParameters.addParameter("InterfaceID",interfaceIndex);
569 
570 
571  __SUP_COUT__ << "The index of the supervisor instance is: " << FESupervisorIndex << __E__;
572  __SUP_COUT__ << "...and the interface ID is: " << interfaceIndex << __E__;
573 
574  SupervisorInfoMap::iterator it = allFESupervisorInfo_.find(FESupervisorIndex);
575  if (it == allFESupervisorInfo_.end())
576  {
577  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
578  interfaceIndex << ":" << FESupervisorIndex << ".' \n\n" <<
579  "The FE Index doesn't exist. Have you configured the state machine properly?" << __E__;
580  __SUP_SS_THROW__;
581  }
582 
583  try
584  {
585  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
586  it->second.getDescriptor(),
587  "MacroMakerSupervisorRequest",
588  txParameters);
589 
590  __SUP_COUT__ << "Response received: " <<
591  SOAPUtilities::translate(retMsg) << __E__;
592 
593  //SOAPParameters rxParameters;
594  //rxParameters.addParameter("Error");
595  SOAPUtilities::receive(retMsg,rxParameters);
596 
597  std::string error = rxParameters.getValue("Error");
598  __SUP_COUTV__(error);
599 
600  if(error != "")
601  {
602  //error occurred!
603  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
604  interfaceIndex << ":" << FESupervisorIndex << ".' " <<
605  "Have you configured the state machine properly?\n\n" <<
606  error << __E__;
607  __SUP_SS_THROW__;
608  }
609  }
610  catch(const xdaq::exception::Exception& e)
611  {
612  __SUP_SS__ << "Error transmitting request to FE Supervisor '" <<
613  interfaceIndex << ":" << FESupervisorIndex << ".' " <<
614  "Have you configured the state machine properly?\n\n" <<
615  e.what() << __E__;
616  __SUP_SS_THROW__;
617  }
618 
619  std::string dataReadResult = rxParameters.getValue("dataResult");
620  __SUP_COUT__<< "Data reading result received: " << dataReadResult << __E__;
621  xmldoc.addTextElementToData("readData",dataReadResult);
622  std::string command = "r:" + Address + ":" + dataReadResult;
623  std::string format = addressFormatStr + ":" + dataFormatStr;
624  appendCommandToHistory(command,format,time,interfaces,username);
625  }
626 }
627 
628 //========================================================================================================================
629 void MacroMakerSupervisor::createMacro(HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi, const std::string &username)
630 {
631  __SUP_COUT__<< "MacroMaker wants to create a macro!!!!!!!!!" << __E__;
632  std::string Name = CgiDataUtilities::postData(cgi, "Name");
633  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
634  std::string Time = CgiDataUtilities::postData(cgi, "Time");
635  std::string Notes = CgiDataUtilities::decodeURIComponent(
636  CgiDataUtilities::postData(cgi, "Notes"));
637  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
638  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
639 
640  __SUP_COUTV__(Name);
641  __SUP_COUTV__(Sequence);
642  __SUP_COUTV__(Notes);
643  __SUP_COUTV__(Time);
644  __SUP_COUTV__(isMacroPublic);
645  __SUP_COUTV__(isMacroLSBF);
646 
647  __SUP_COUTV__(MACROS_DB_PATH);
648 
649  std::string fileName = Name + ".dat";
650  std::string fullPath;
651  if (isMacroPublic == "true") fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
652  else fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
653 
654  __SUP_COUTV__(fullPath);
655 
656  std::ofstream macrofile (fullPath.c_str());
657  if (macrofile.is_open())
658  {
659  macrofile << "{\n";
660  macrofile << "\"name\":\"" << Name << "\",\n";
661  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
662  macrofile << "\"time\":\"" << Time << "\",\n";
663  macrofile << "\"notes\":\"" << Notes << "\",\n";
664  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
665  macrofile << "}@" << __E__;
666  macrofile.close();
667  }
668  else
669  __SUP_COUT__<< "Unable to open file" << __E__;
670 } //end createMacro()
671 
672 //========================================================================================================================
673 //loadMacro
674 // Load macro string from file.
675 // look in public macros and username (if given)
676 // for the macroName.
677 //
678 // If found, return by reference
679 // Else, throw exception
680 void MacroMakerSupervisor::loadMacro(
681  const std::string& macroName,
682  std::string& macroString,
683  const std::string &username /*=""*/)
684 {
685  __SUP_COUTV__(macroName);
686 
687  //first check public folder, then user
688  std::string fullPath, line;
689  macroString = "";
690  for(unsigned int i=0;i<2;++i)
691  {
692  if(i == 1)
693  fullPath = (std::string)MACROS_DB_PATH + username + "/";
694  else
695  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
696 
697  fullPath += macroName + ".dat";
698  __SUP_COUTV__(fullPath);
699 
700  std::ifstream read (fullPath.c_str());//reading a file
701  if (read.is_open())
702  {
703  while (! read.eof() )
704  {
705  getline (read,line);
706  macroString += line;
707  }
708 
709  read.close();
710  }
711  else //file does not exist
712  {
713  __SUP_COUT__<< "Unable to open file: " << fullPath << __E__;
714  continue;
715  }
716 
717  if(macroString != "") break; //macro has been found!
718  } //end load from path loop
719 
720  if(macroString == "")
721  {
722  __SUP_SS__<< "Unable to locate file for macro '" << macroName <<
723  "'... does it exist?" << __E__;
724  if(username != "")
725  ss << " Attempted username was '" << username << ".'" << __E__;
726  __SUP_SS_THROW__;
727  }
728 
729  __SUP_COUTV__(macroString);
730 } //end loadMacro()
731 
732 //========================================================================================================================
733 void MacroMakerSupervisor::loadMacros(HttpXmlDocument& xmldoc, const std::string &username)
734 {
735  DIR *dir;
736  struct dirent *ent;
737  std::string returnStr = "";
738  std::string fullPath = (std::string)MACROS_DB_PATH + username + "/";
739  if ((dir = opendir (fullPath.c_str())) != NULL)
740  {
741  /* print all the files and directories within directory */
742  while ((ent = readdir (dir)) != NULL)
743  {
744  /* File name validation check */
745  if ((unsigned)strlen(ent->d_name) > 4)
746  {
747  std::string line;
748  std::ifstream read (((fullPath + (std::string)ent->d_name)).c_str());//reading a file
749  if (read.is_open())
750  {
751  std::stringstream buffer;
752  while (! read.eof() )
753  {
754  getline (read,line);
755  buffer << line;
756  //__SUP_COUT__ << line << __E__;
757  }
758  returnStr += buffer.str();
759 
760  read.close();
761  }
762  else
763  __SUP_COUT__<< "Unable to open file" << __E__;
764  }
765  }
766  std::string returnMacroStr = returnStr.substr(0, returnStr.size()-1);
767 
768  __SUP_COUT__<< "Loading existing macros! " << returnMacroStr << __E__;
769 
770  closedir (dir);
771  xmldoc.addTextElementToData("returnMacroStr",returnMacroStr);
772  }
773  else
774  {
775  __SUP_COUT__<< "Looping through privateMacros folder failed! Wrong directory" << __E__;
776  }
777  fullPath = (std::string)MACROS_DB_PATH + "publicMacros/";
778  returnStr = "";
779  if ((dir = opendir (fullPath.c_str())) != NULL)
780  {
781  /* print all the files and directories within directory */
782  while ((ent = readdir (dir)) != NULL)
783  {
784  /* File name validation check */
785  if ((unsigned)strlen(ent->d_name) > 4)
786  {
787  std::string line;
788  std::ifstream read (((fullPath + (std::string)ent->d_name)).c_str());//reading a file
789  if (read.is_open())
790  {
791  std::stringstream buffer;
792  while (! read.eof() )
793  {
794  getline (read,line);
795  buffer << line;
796  //__SUP_COUT__ << line << __E__;
797  }
798  returnStr += buffer.str();
799  read.close();
800  }
801  else
802  __SUP_COUT__<< "Unable to open file" << __E__;
803  }
804  }
805  std::string returnPublicStr = returnStr.substr(0, returnStr.size()-1);
806  __SUP_COUT__<< "Loading existing public macros: " << returnPublicStr << __E__;
807  closedir (dir);
808  xmldoc.addTextElementToData("returnPublicStr",returnPublicStr);
809  }
810  else
811  {
812  __SUP_COUT__ << fullPath << __E__;
813  __SUP_COUT__<< "Looping through MacroData folder failed! Wrong directory" << __E__;
814 
815  }
816 } //end loadMacros()
817 
818 //========================================================================================================================
819 void MacroMakerSupervisor::appendCommandToHistory(std::string Command,
820  std::string Format, std::string Time, std::string Interfaces, const std::string &username)
821 {
822  std::string fileName = "history.hist";
823  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
824  __SUP_COUT__ << fullPath << __E__;
825  std::ofstream histfile (fullPath.c_str(),std::ios::app);
826  if (histfile.is_open())
827  {
828  histfile << "{\n";
829  histfile << "\"Command\":\"" << Command << "\",\n";
830  histfile << "\"Format\":\"" << Format << "\",\n";
831  histfile << "\"Time\":\"" << Time << "\",\n";
832  histfile << "\"Interfaces\":\"" << Interfaces << "\"\n";
833  histfile << "}#" << __E__;
834  histfile.close();
835  }
836  else
837  __SUP_COUT__<< "Unable to open history.hist" << __E__;
838 }
839 
840 //========================================================================================================================
841 void MacroMakerSupervisor::loadHistory(HttpXmlDocument& xmldoc, const std::string &username)
842 {
843  std::string fileName = MACROS_HIST_PATH + username + "/" + "history.hist";
844 
845  std::ifstream read (fileName.c_str());//reading a file
846  __SUP_COUT__<< fileName << __E__;
847 
848  if (read.is_open())
849  {
850  std::string line;
851  char * returnStr;
852  unsigned long long fileSz, i = 0, MAX_HISTORY_SIZE = 100000;
853 
854 
855  //get length of file to reserve the string size
856  // and to cap history size
857  read.seekg(0, std::ios::end);
858  fileSz = read.tellg();
859  returnStr = new char[fileSz+1];
860  returnStr[fileSz] = '\0';
861  read.seekg(0, std::ios::beg);
862 
863 
864  // read data as a block:
865  read.read(returnStr,fileSz);
866  read.close();
867 
868 
869  //find i such that new string size is less than
870  if(fileSz > MAX_HISTORY_SIZE)
871  {
872  i = fileSz - MAX_HISTORY_SIZE;
873  for(;i<fileSz;++i)
874  if(returnStr[i] == '#')
875  {
876  i += 2; break; //skip new line character also to get to next record
877  }
878  if(i > fileSz) i = fileSz;
879 
880  //write back to file truncated history
881  FILE *fp = fopen(fileName.c_str(),"w");
882  if(!fp)
883  {
884  __SS__ << "Big problem with macromaker history file: " << fileName << __E__;
885  __SS_THROW__;
886  }
887  fwrite(&returnStr[i],fileSz-i,1,fp);
888  fclose(fp);
889  }
890 
891  __SUP_COUT__<< "Loading user history! " << __E__;
892 
893  if(fileSz > 1)
894  returnStr[fileSz-2] = '\0'; //remove final newline and last #
895 
896  xmldoc.addTextElementToData("returnHistStr",&returnStr[i]);
897 
898 
899  delete[] returnStr;
900  }
901  else
902 
903  __SUP_COUT__<< "Unable to open history.hist" << __E__;
904 
905 }
906 
907 //========================================================================================================================
908 void MacroMakerSupervisor::deleteMacro(HttpXmlDocument& xmldoc,cgicc::Cgicc& cgi, const std::string &username)
909 {
910  std::string MacroName = CgiDataUtilities::getData(cgi, "MacroName");
911  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
912 
913 
914  std::string fileName = MacroName + ".dat";
915  std::string fullPath;
916  if (isMacroPublic == "true") fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
917  else fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
918 
919  __SUP_COUT__<< fullPath << __E__;
920 
921  std::remove(fullPath.c_str());
922  __SUP_COUT__ << "Successfully deleted " << MacroName;
923  xmldoc.addTextElementToData("deletedMacroName",MacroName);
924 }
925 
926 //========================================================================================================================
927 void MacroMakerSupervisor::editMacro(HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi, const std::string &username)
928 {
929  std::string oldMacroName = CgiDataUtilities::postData(cgi, "oldMacroName");
930  std::string newMacroName = CgiDataUtilities::postData(cgi, "newMacroName");
931  std::string Sequence = CgiDataUtilities::postData(cgi, "Sequence");
932  std::string Time = CgiDataUtilities::postData(cgi, "Time");
933  std::string Notes = CgiDataUtilities::decodeURIComponent(
934  CgiDataUtilities::postData(cgi, "Notes"));
935 
936  std::string isMacroPublic = CgiDataUtilities::getData(cgi, "isPublic");
937  std::string isMacroLSBF = CgiDataUtilities::getData(cgi, "isLSBF");
938 
939  __SUP_COUTV__(oldMacroName);
940  __SUP_COUTV__(newMacroName);
941  __SUP_COUTV__(Sequence);
942  __SUP_COUTV__(Notes);
943  __SUP_COUTV__(Time);
944  __SUP_COUTV__(isMacroPublic);
945  __SUP_COUTV__(isMacroLSBF);
946 
947  __SUP_COUTV__(MACROS_DB_PATH);
948 
949  std::string fileName = oldMacroName + ".dat";
950  std::string fullPath;
951  if (isMacroPublic == "true") fullPath = (std::string)MACROS_DB_PATH + "publicMacros/" + fileName;
952  else fullPath = (std::string)MACROS_DB_PATH + username + "/" + fileName;
953 
954  __SUP_COUTV__(fullPath);
955 
956  std::ofstream macrofile (fullPath.c_str());
957  if (macrofile.is_open())
958  {
959  macrofile << "{\n";
960  macrofile << "\"name\":\"" << newMacroName << "\",\n";
961  macrofile << "\"sequence\":\"" << Sequence << "\",\n";
962  macrofile << "\"time\":\"" << Time << "\",\n";
963  macrofile << "\"notes\":\"" << Notes << "\",\n";
964  macrofile << "\"LSBF\":\"" << isMacroLSBF << "\"\n";
965  macrofile << "}@" << __E__;
966  macrofile.close();
967  }
968  else
969  __SUP_COUT__<< "Unable to open file" << __E__;
970 
971  if(oldMacroName != newMacroName) //renaming macro
972  {
973  int result;
974  result = rename((MACROS_DB_PATH + username + "/" + oldMacroName + ".dat").c_str(), (MACROS_DB_PATH + username + "/" + newMacroName + ".dat").c_str());
975  if (result == 0)
976  xmldoc.addTextElementToData("newMacroName",newMacroName);
977  else
978  xmldoc.addTextElementToData("newMacroName","ERROR");
979  }
980 }
981 
982 //========================================================================================================================
983 void MacroMakerSupervisor::clearHistory(const std::string &username)
984 {
985  std::string fileName = "history.hist";
986  std::string fullPath = (std::string)MACROS_HIST_PATH + username + "/" + fileName;
987 
988  std::remove(fullPath.c_str());
989  __SUP_COUT__<< "Successfully deleted " << fullPath;
990 }
991 
992 //========================================================================================================================
993 void MacroMakerSupervisor::exportFEMacro(HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi,
994  const std::string &username)
995 {
996  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
997  std::string pluginName = CgiDataUtilities::getData(cgi, "PluginName");
998  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
999  std::string macroNotes = CgiDataUtilities::decodeURIComponent(
1000  CgiDataUtilities::postData(cgi, "MacroNotes"));
1001 
1002  __SUP_COUTV__(pluginName);
1003  __SUP_COUTV__(macroName);
1004  __SUP_COUTV__(macroSequence);
1005 
1006  //replace all special characters with white space
1007  for(unsigned int i=0;i<macroNotes.length();++i)
1008  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
1009  macroNotes[i] = ' ';
1010  __SUP_COUTV__(macroNotes);
1011 
1012  std::stringstream ss(macroSequence);
1013  std::string command;
1014  std::vector<std::string> commands;
1015 
1016  while (getline(ss, command, ',')) commands.push_back(command);
1017 
1018  __SUP_COUTV__(StringMacros::vectorToString(commands));
1019 
1020  std::map<std::string /*special type*/,std::set<std::string> /*special file paths*/>
1021  specialsCodeMap = CodeEditor::getSpecialsMap();
1022 
1023  //__SUP_COUTV__(StringMacros::mapToString(specialsCodeMap));
1024  auto specialsCodeMapIt = specialsCodeMap.find(CodeEditor::SPECIAL_TYPE_FEInterface);
1025  if(specialsCodeMapIt == specialsCodeMap.end())
1026  {
1027  __SS__ << "Could not find any FE Interface plugins in source code. Does MacroMaker " <<
1028  "have access to the source code? Check that the Supervisor context places MacroMaker in a " <<
1029  "location with access to the source code." << __E__;
1030  __SS_THROW__;
1031  }
1032 
1033  //find first .h and .cc with the plugin name
1034  std::string headerFile = pluginName + ".h";
1035  std::string sourceFile = pluginName + "_interface.cc";
1036  bool foundHeaderFile = false;
1037  bool foundSourceFile = false;
1038  for(const auto& filePath : specialsCodeMapIt->second)
1039  {
1040  if(!foundHeaderFile &&
1041  filePath.find(headerFile) != std::string::npos)
1042  {
1043  foundHeaderFile = true;
1044  headerFile = filePath;
1045  __SUP_COUT__ << "found headerFile=" << filePath << __E__;
1046  }
1047  if(!foundSourceFile &&
1048  filePath.find(sourceFile) != std::string::npos)
1049  {
1050  foundSourceFile = true;
1051  sourceFile = filePath;
1052  __SUP_COUT__ << "found sourceFile=" << filePath << __E__;
1053  }
1054 
1055  if(foundSourceFile && foundHeaderFile) break;
1056  } //end file search loop
1057 
1058  if(!foundHeaderFile)
1059  {
1060  __SS__ << "Could not find the header file for the FE Interface plugins at '" <<
1061  headerFile << ".' Does MacroMaker " <<
1062  "have access to the source code? Check that the Supervisor context places MacroMaker in a " <<
1063  "location with access to the source code." << __E__;
1064  __SS_THROW__;
1065  }
1066  if(!foundSourceFile)
1067  {
1068  __SS__ << "Could not find the source file for the FE Interface plugins at '" <<
1069  sourceFile << ".' Does MacroMaker " <<
1070  "have access to the source code? Check that the Supervisor context places MacroMaker in a " <<
1071  "location with access to the source code." << __E__;
1072  __SS_THROW__;
1073  }
1074 
1075  //at this point have header and source file, now add FE Macro
1076  //Steps for each file:
1077  // - read current file
1078  // - find insert point
1079  // - open file for writing
1080  // - write original file up to insert point
1081  // - insert new code
1082  // - write remaining original file
1083 
1084  char timeBuffer[100];
1085  { //get time string
1086  time_t rawtime;
1087  struct tm * timeinfo;
1088 
1089  time (&rawtime);
1090  timeinfo = localtime(&rawtime);
1091 
1092  strftime(timeBuffer,100,"%b-%d-%Y %I:%M:%S",timeinfo);
1093  }
1094 
1095  std::string contents;
1096  std::string insert;
1097 
1099  //handle source file modifications
1100  CodeEditor::readFile(sourceFile,contents);
1101  //__SUP_COUTV__(contents);
1102 
1103  //return file locations, for the user to inspect on error
1104  xmldoc.addTextElementToData("sourceFile",sourceFile);
1105  xmldoc.addTextElementToData("headerFile",headerFile);
1106 
1107  //check for duplicate functions
1108  if(contents.find(pluginName + "::" + macroName) !=
1109  std::string::npos)
1110  {
1111  __SS__ << "The function definition '" << (pluginName + "::" + macroName) <<
1112  "(...)' already exists in the source file '" << sourceFile <<
1113  ".' Duplicate functions are not allowed - please rename the macro or modify the source file." << __E__;
1114  __SS_THROW__;
1115  }
1116 
1117 
1118 
1119  std::stringstream codess;
1120  std::set<std::string> inArgNames, outArgNames;
1121  createCode(codess,commands,"\t" /*tabOffset*/, true /*forFeMacro*/,
1122  &inArgNames,&outArgNames);
1123  __SUP_COUTV__(StringMacros::setToString(inArgNames));
1124  __SUP_COUTV__(StringMacros::setToString(outArgNames));
1125 
1126  //find start of constructor and register macro
1127  {
1128  auto insertPos = contents.find(pluginName + "::" + pluginName);
1129  if(insertPos == std::string::npos)
1130  {
1131  __SS__ << "Could not find the code insert position in the source file '" <<
1132  sourceFile << ".' The FE plugin class constructor must be '" <<
1133  pluginName << ":" << pluginName <<"' - is this the case?" << __E__;
1134  __SS_THROW__;
1135  }
1136  __SUP_COUTV__(insertPos);
1137  //find opening bracket after constructor name
1138  insertPos = contents.find("{",insertPos);
1139  if(insertPos == std::string::npos)
1140  {
1141  __SS__ << "Could not find the code insert position in the source file '" <<
1142  sourceFile << ".' The FE plugin class constructor must begin with '{" <<
1143  "' - is this the case?" << __E__;
1144  __SS_THROW__;
1145  }
1146  ++insertPos; //go past {
1147  __SUP_COUTV__(insertPos);
1148 
1149  insert = "\n\t//registration of FEMacro '" + macroName + "' generated, " +
1150  timeBuffer + ", by '" + username + "' using MacroMaker.\n\t" +
1151  "FEVInterface::registerFEMacroFunction(\"" + macroName + "\",//feMacroName \n\t\t" +
1152  "static_cast<FEVInterface::frontEndMacroFunction_t>(&" +
1153  pluginName + "::" + macroName + "), //feMacroFunction \n\t\t" +
1154  "std::vector<std::string>{";
1155  { //insert input argument names
1156  bool first = true;
1157  for(const auto& inArg:inArgNames)
1158  {
1159  if(first)
1160  first = false;
1161  else
1162  insert += ",";
1163  insert += "\"" + inArg + "\"";
1164  }
1165  }
1166  insert += "}, //namesOfInputArgs \n\t\t";
1167  insert += "std::vector<std::string>{";
1168  { //insert output argument names
1169  bool first = true;
1170  for(const auto& outArg:outArgNames)
1171  {
1172  if(first)
1173  first = false;
1174  else
1175  insert += ",";
1176  insert += "\"" + outArg + "\"";
1177  }
1178  }
1179  insert += "}, //namesOfOutputArgs \n\t\t";
1180  insert += "1); //requiredUserPermissions \n\n";
1181 
1182  __SUP_COUTV__(insert);
1183  contents = contents.substr(0,insertPos) + insert + contents.substr(insertPos);
1184  }
1185 
1186  //find end of source to append FE Macro function
1187  {
1188  auto insertPos = contents.rfind("DEFINE_OTS_INTERFACE");
1189  if(insertPos == std::string::npos)
1190  {
1191  __SS__ << "Could not find the code insert position in the source file '" <<
1192  sourceFile << ".' The FE plugin class must end with a 'DEFINE_OTS_INTERFACE(" <<
1193  pluginName << ")' - is this the case?" << __E__;
1194  __SS_THROW__;
1195  }
1196  __SUP_COUTV__(insertPos);
1197 
1198  insert = "\n//========================================================================================================================\n//" +
1199  macroName + "\n" +
1200  "//\tFEMacro '" + macroName + "' generated, " +
1201  timeBuffer + ", by '" + username + "' using MacroMaker.\n" +
1202  "//\tMacro Notes: " + macroNotes + "\n" +
1203  "void " + pluginName + "::" + macroName + "(__ARGS__)\n{\n\t" +
1204  "__CFG_COUT__ << \"# of input args = \" << argsIn.size() << __E__; \n\t" +
1205  "__CFG_COUT__ << \"# of output args = \" << argsOut.size() << __E__; \n\t" +
1206  "for(auto &argIn:argsIn) \n\t\t" +
1207  "__CFG_COUT__ << argIn.first << \": \" << argIn.second << __E__; \n\n\t" +
1208  "//macro commands section \n" +
1209  codess.str() +
1210  "\n\n\t" +
1211  "for(auto &argOut:argsOut) \n\t\t" +
1212  "__CFG_COUT__ << argOut.first << \": \" << argOut.second << __E__; \n\n" +
1213  "} //end " + macroName + "()\n\n";
1214 
1215  //__SUP_COUTV__(insert);
1216  CodeEditor::writeFile(sourceFile,contents,insertPos,insert);
1217  }
1218 
1219 
1220 
1222  //handle include file insertions
1223  CodeEditor::readFile(headerFile,contents);
1224  //__SUP_COUTV__(contents);
1225 
1226 
1227  //find end of class by looking for last };
1228  {
1229  auto insertPos = contents.rfind("};");
1230  if(insertPos == std::string::npos)
1231  {
1232  __SS__ << "Could not find the code insert position in the header file '" <<
1233  headerFile << ".' The FE plugin class must end with a '};' - is this the case?" << __E__;
1234  __SS_THROW__;
1235  }
1236 
1237  __SUP_COUTV__(insertPos);
1238 
1239  insert = "\npublic: // FEMacro '" + macroName + "' generated, " +
1240  timeBuffer + ", by '" + username + "' using MacroMaker.\n\t" +
1241  "void " + macroName +
1242  "\t(__ARGS__);\n";
1243 
1244  __SUP_COUTV__(insert);
1245  CodeEditor::writeFile(headerFile,contents,insertPos,insert);
1246  }
1247 
1248 
1249 } //end exportFEMacro ()
1250 
1251 //========================================================================================================================
1252 void MacroMakerSupervisor::exportMacro(HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi, const std::string &username)
1253 {
1254  std::string macroName = CgiDataUtilities::getData(cgi, "MacroName");
1255  std::string macroSequence = CgiDataUtilities::postData(cgi, "MacroSequence");
1256  std::string macroNotes = CgiDataUtilities::decodeURIComponent(
1257  CgiDataUtilities::postData(cgi, "MacroNotes"));
1258 
1259  __SUP_COUTV__(macroName);
1260  __SUP_COUTV__(macroSequence);
1261 
1262  //replace all special characters with white space
1263  for(unsigned int i=0;i<macroNotes.length();++i)
1264  if(macroNotes[i] == '\r' || macroNotes[i] == '\n')
1265  macroNotes[i] = ' ';
1266  __SUP_COUTV__(macroNotes);
1267 
1268  std::stringstream ss(macroSequence);
1269  std::string command;
1270  std::vector<std::string> commands;
1271 
1272  while (getline(ss, command, ',')) commands.push_back(command);
1273 
1274  std::string fileName = macroName + ".cc";
1275 
1276 
1277  std::string fullPath = (std::string)MACROS_EXPORT_PATH + username + "/" + fileName;
1278  __SUP_COUT__ << fullPath << __E__;
1279  std::ofstream exportFile (fullPath.c_str(),std::ios::trunc);
1280  if (exportFile.is_open())
1281  {
1282  exportFile << "//Generated Macro Name:\t" << macroName << "\n";
1283  exportFile << "//Macro Notes: " << macroNotes << "\n";
1284 
1285  {
1286  time_t rawtime;
1287  struct tm * timeinfo;
1288  char buffer[100];
1289 
1290  time (&rawtime);
1291  timeinfo = localtime(&rawtime);
1292 
1293  strftime(buffer,100,"%b-%d-%Y %I:%M:%S",timeinfo);
1294  exportFile << "//Generated Time: \t\t" << buffer << "\n";
1295  }
1296 
1297  exportFile << "//Paste this whole file into an interface to transfer Macro functionality.\n";
1298 
1299  createCode(exportFile,commands);
1300 
1301  exportFile.close();
1302 
1303  xmldoc.addTextElementToData("ExportFile",fullPath);
1304  }
1305  else
1306  __SUP_COUT__ << "Unable to open file" << __E__;
1307 }
1308 
1309 
1310 //========================================================================================================================
1311 //createCode
1312 void MacroMakerSupervisor::createCode(std::ostream& out,
1313  const std::vector<std::string>& commands,
1314  const std::string& tabOffset,
1315  bool forFeMacro,
1316  std::set<std::string>* inArgNames,
1317  std::set<std::string>* outArgNames)
1318 {
1319  int numOfHexBytes;
1320  std::set<std::string /*argInName*/> argInHasBeenInitializedSet;
1321  bool addressIsVariable, dataIsVariable;
1322 
1323  out << tabOffset << "{";
1324 
1325  out << "\n" << tabOffset << "\t" << "char *address \t= new char[universalAddressSize_]{0}; //create address buffer of interface size and init to all 0";
1326  out << "\n" << tabOffset << "\t" << "char *data \t\t= new char[universalDataSize_]{0}; //create data buffer of interface size and init to all 0";
1327 
1328  out << "\n" << tabOffset << "\t" << "uint64_t macroAddress; //create macro address buffer (size 8 bytes)";
1329  out << "\n" << tabOffset << "\t" << "uint64_t macroData; //create macro address buffer (size 8 bytes)";
1330 
1331  out << "\n" << tabOffset << "\t" << "std::map<std::string /*arg name*/,uint64_t /*arg val*/> macroArgs; //create map from arg name to 64-bit number";
1332 
1333  //loop through each macro command
1334  for(unsigned int i = 0; i < commands.size(); i++)
1335  {
1336  std::stringstream sst(commands[i]);
1337  std::string tokens;
1338  std::vector<std::string> oneCommand; //4 fields: cmd index | cmd type | addr | data
1339  while (getline(sst, tokens, ':')) oneCommand.push_back(tokens);
1340  while(oneCommand.size() < 4) oneCommand.push_back(""); //fill out the 4 fields
1341 
1342  __SUP_COUTV__(StringMacros::vectorToString(oneCommand));
1343 
1344  //make this:
1345  // std::map<std::string,uint64_t> macroArgs;
1346  // {
1347  // uint64_t address = 0x1001; //create address buffer
1348  // uint64_t data = 0x100203; //create data buffer
1349  //
1350  // universalWrite(address,data);
1351  // universalRead(address,data);
1352  // }
1353  //
1354  // //if variable, first time init
1355  // {
1356  // address = theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode("variableName").getValue<uint64_t>();
1357  // or
1358  // address = __GET_ARG_IN__("variableName",uint64_t);
1359  // }
1360  //
1361  // //if variable, second time use macroArgs
1362  // {
1363  // address = macroArgs["variableName"];
1364  // data = macroArgs["variableName"];
1365  // }
1366 
1367  addressIsVariable = isArgumentVariable(oneCommand[2]);
1368  dataIsVariable = isArgumentVariable(oneCommand[3]);
1369 
1370  __SUP_COUTV__(addressIsVariable);
1371  __SUP_COUTV__(dataIsVariable);
1372 
1373  out << "\n\n" << tabOffset << "\t// command-#" << i << ": ";
1374 
1375  if(oneCommand[1][0] == 'w' || oneCommand[1][0] == 'r')
1376  {
1377  if (oneCommand[1][0] == 'w')
1378  out << "Write(";
1379  else if (oneCommand[1][0] == 'r')
1380  out << "Read(";
1381 
1382  if(addressIsVariable)
1383  out << oneCommand[2];
1384  else //literal hex address
1385  out << "0x" << oneCommand[2];
1386  out << " /*address*/,";
1387 
1388  if(dataIsVariable) //read or write can have variable data, sink or source respectively
1389  out << oneCommand[3] << " /*data*/";
1390  else if (oneCommand[1][0] == 'w')//literal hex data
1391  out << "0x" << oneCommand[3] << " /*data*/";
1392  else if (oneCommand[1][0] == 'r')//just reading to buffer
1393  out << "data";
1394  out << ");\n";
1395  }
1396  else if (oneCommand[1][0] == 'd')
1397  {
1398  out << "delay(" << oneCommand[2] << ");\n";
1399  out << tabOffset << "\t" << "__CFG_COUT__ << \"Sleeping for... \" << " << oneCommand[2] <<
1400  " << \" milliseconds \" << __E__;\n";
1401  out << tabOffset << "\t" << "usleep(" << oneCommand[2] << "*1000 /* microseconds */);\n";
1402  continue;
1403  }
1404  else
1405  {
1406  __SS__ << "FATAL ERROR: Unknown command '" << oneCommand[1] <<
1407  "'... command is not w, r or d" << __E__;
1408  __SS_THROW__;
1409  }
1410 
1412  //handle address
1413  if(addressIsVariable) //handle address as variable
1414  {
1415  if(argInHasBeenInitializedSet.find(oneCommand[2]) ==
1416  argInHasBeenInitializedSet.end()) //only initialize input argument once
1417  {
1418  argInHasBeenInitializedSet.emplace(oneCommand[2]);
1419 
1420  if(!forFeMacro)
1421  {
1422  //get address from configuration Tree
1423  out << tabOffset << "\t" <<
1424  "macroArgs[\"" <<
1425  oneCommand[2] << "\"] = theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode(" <<
1426  "\n" << tabOffset << "\t\t\"" <<
1427  oneCommand[2] << "\").getValue<uint64_t>();";
1428  }
1429  else
1430  {
1431  if(inArgNames) inArgNames->emplace(oneCommand[2]);
1432 
1433  //get address from arguments
1434  out << tabOffset << "\t" <<
1435  "macroArgs[\"" <<
1436  oneCommand[2] << "\"] = __GET_ARG_IN__(\"" <<
1437  oneCommand[2] << "\", uint64_t);";
1438  }
1439  }
1440  out << "\t//get macro address argument";
1441  out << "\n" << tabOffset << "\tmemcpy(address,&macroArgs[\"" <<
1442  oneCommand[2] << "\"],8); //copy macro address argument to buffer";
1443 
1444  }
1445  else //handle address as literal
1446  {
1447  out << tabOffset << "\t" <<
1448  "macroAddress = 0x" << oneCommand[2] << "; memcpy(address,&macroAddress,8);" <<
1449  "\t//copy macro address to buffer";
1450  }
1451 
1453  //handle data
1454  if (oneCommand[1] == "w") //if write, handle data too
1455  {
1456  if(dataIsVariable) //handle data as variable
1457  {
1458  if(argInHasBeenInitializedSet.find(oneCommand[3]) ==
1459  argInHasBeenInitializedSet.end()) //only initialize input argument once
1460  {
1461  argInHasBeenInitializedSet.emplace(oneCommand[3]);
1462 
1463  if(forFeMacro)
1464  {
1465 
1466  if(inArgNames) inArgNames->emplace(oneCommand[3]);
1467 
1468  //get data from arguments
1469  out << "\n" << tabOffset << "\t" <<
1470  "macroArgs[\"" <<
1471  oneCommand[3] << "\"] = __GET_ARG_IN__(\"" <<
1472  oneCommand[3] << "\", uint64_t); //initialize from input arguments";
1473 
1474 
1475  }
1476  else
1477  {
1478  //get data from configuration Tree
1479  out << "\n" << tabOffset << "\t" <<
1480  "macroArgs[\"" <<
1481  oneCommand[3] << "\"] = theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode(" <<
1482  "\n" << tabOffset << "\t\t\"" <<
1483  oneCommand[3] << "\").getValue<uint64_t>(); //initialize from configuration tree";
1484  }
1485  }
1486  out << "\t//get macro data argument";
1487  out << "\n" << tabOffset << "\tmemcpy(data,&macroArgs[\"" <<
1488  oneCommand[3] << "\"],8); //copy macro data argument to buffer";
1489  }
1490  else //handle data as literal
1491  {
1492  out << "\n" << tabOffset << "\t" <<
1493  "macroData = 0x" << oneCommand[3] << "; memcpy(data,&macroData,8);" <<
1494  "\t//copy macro data to buffer";
1495  }
1496  out << "\n" << tabOffset << "\t" <<
1497  "universalWrite(address,data);";
1498  }
1499  else
1500  {
1501  out << "\n" << tabOffset << "\t" <<
1502  "universalRead(address,data);";
1503 
1504 
1505  std::string outputArgName;
1506 
1507  if(dataIsVariable) //handle data as variable
1508  outputArgName = oneCommand[3];
1509  else //give each read data a unique argument name
1510  {
1511  char str[20];
1512  sprintf(str,"outArg%d",i);
1513  outputArgName = str; //use command index for uniqueness
1514  }
1515  __SUP_COUTV__(outputArgName);
1516 
1517  out << tabOffset << "\t" <<
1518  "memcpy(&macroArgs[\"" <<
1519  outputArgName << "\"],data,8); //copy buffer to argument map";
1520 
1521  //copy read data to output args
1522  if(forFeMacro)
1523  out << "\n" << tabOffset << "\t" <<
1524  "__SET_ARG_OUT__(\"" <<
1525  outputArgName << "\",macroArgs[\"" <<
1526  outputArgName << "\"]); //update output argument result";
1527 
1528  if(outArgNames) outArgNames->emplace(outputArgName);
1529  argInHasBeenInitializedSet.emplace(outputArgName); //mark initialized since value has been read
1530  }
1531  } //end command loop
1532 
1533  out << "\n\n" << tabOffset << "\tdelete[] address; //free the memory";
1534  out << "\n" << tabOffset << "\tdelete[] data; //free the memory";
1535  out << "\n" << tabOffset << "}";
1536 
1537  __SUP_COUT__ << "Done with code generation." << __E__;
1538 } // end createCode()
1539 
1540 //========================================================================================================================
1541 //isArgumentVariable
1542 // returns true if string should be interpreted as a variable for MacroMaker
1543 bool MacroMakerSupervisor::isArgumentVariable(const std::string &argumentString)
1544 {
1545  for(unsigned int i=0; i<argumentString.length(); ++i)
1546  {
1547  //detect non-hex
1548  if(!((argumentString[i] >= '0' && argumentString[i] <= '9') ||
1549  (argumentString[i] >= 'a' && argumentString[i] <= 'f')||
1550  (argumentString[i] >= 'A' && argumentString[i] <= 'F')))
1551  return true;
1552  }
1553  return false;
1554 } //end isArgumentVariable()
1555 //========================================================================================================================
1556 //generateHexArray
1557 // returns a char array initializer
1558 // something like this
1559 // "[8] = {0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09};"
1560 // ..depending a size of source string
1561 //
1562 //FIXME -- identify variables in a better way from macromaker...!
1563 // for now just assume a non hex is a variable name
1564 // return -1 size
1565 std::string MacroMakerSupervisor::generateHexArray(const std::string &sourceHexString,
1566  int &numOfBytes)
1567 {
1568  std::stringstream retSs;
1569 
1570  std::string srcHexStr = sourceHexString;
1571  __SUP_COUT__<< "Translating: \n";
1572  __SUP_COUT__ << srcHexStr << __E__;
1573 
1574  if(srcHexStr.size()%2) //if odd, make even
1575  srcHexStr = "0" + srcHexStr;
1576 
1577  numOfBytes = srcHexStr.size()/2;
1578  retSs << "[" << numOfBytes << "] = {";
1579 
1580  for(int i=0; i<numOfBytes*2; i+=2)
1581  {
1582  //detect non-hex
1583  if(!((srcHexStr[i] >= '0' && srcHexStr[i] <= '9') ||
1584  (srcHexStr[i] >= 'a' && srcHexStr[i] <= 'f')||
1585  (srcHexStr[i] >= 'A' && srcHexStr[i] <= 'F')) ||
1586  !((srcHexStr[i+1] >= '0' && srcHexStr[i+1] <= '9') ||
1587  (srcHexStr[i+1] >= 'a' && srcHexStr[i+1] <= 'f')||
1588  (srcHexStr[i+1] >= 'A' && srcHexStr[i+1] <= 'F'))
1589  )
1590  {
1591  numOfBytes = -1;
1592  return srcHexStr;
1593  }
1594 
1595  if(i != 0) retSs << ", ";
1596  retSs << "0x" <<
1597  srcHexStr[srcHexStr.size()-1-i-1] <<
1598  srcHexStr[srcHexStr.size()-1-i];
1599  }
1600  retSs << "};";
1601 
1602  __SUP_COUT__ << retSs.str() << __E__;
1603 
1604  return retSs.str();
1605 }
1606 
1607 //========================================================================================================================
1608 void MacroMakerSupervisor::runFEMacro(HttpXmlDocument& xmldoc, cgicc::Cgicc& cgi)
1609 {
1610  __SUP_COUT__<< __E__;
1611 
1612  unsigned int feSupervisorID = CgiDataUtilities::getDataAsInt(cgi, "feSupervisorID");
1613  std::string feUID = CgiDataUtilities::getData(cgi, "feUID");
1614  std::string macroName = CgiDataUtilities::getData(cgi, "macroName");
1615  std::string inputArgs = CgiDataUtilities::postData(cgi, "inputArgs");
1616  std::string outputArgs = CgiDataUtilities::postData(cgi, "outputArgs");
1617 
1618  __SUP_COUTV__(feSupervisorID);
1619  __SUP_COUTV__(feUID);
1620  __SUP_COUTV__(macroName);
1621  __SUP_COUTV__(inputArgs);
1622  __SUP_COUTV__(outputArgs);
1623 
1624  //send command to chosen FE and await response
1625  SOAPParameters txParameters; //params for xoap to send
1626  txParameters.addParameter("Request", "RunInterfaceMacro");
1627  txParameters.addParameter("InterfaceID", feUID);
1628  txParameters.addParameter("feMacroName", macroName);
1629  txParameters.addParameter("inputArgs", inputArgs);
1630  txParameters.addParameter("outputArgs", outputArgs);
1631 
1632  SOAPParameters rxParameters; //params for xoap to recv
1633  rxParameters.addParameter("success");
1634  rxParameters.addParameter("outputArgs");
1635 
1636 
1637 
1638  //find feSupervisorID in target list
1639  auto supervisorDescriptorPairIt = allFESupervisorInfo_.find(feSupervisorID);
1640  if(supervisorDescriptorPairIt == allFESupervisorInfo_.end())
1641  {
1642  __SS__ << "Targeted Supervisor Descriptor was not found. Attempted target " <<
1643  "was UID=" << feUID << " at feSupervisorID=" << feSupervisorID << "." << __E__;
1644  __SUP_COUT_ERR__ << "\n" << ss.str();
1645  xmldoc.addTextElementToData("Error",ss.str());
1646  return;
1647  }
1648 
1649  //have FE supervisor descriptor, so send
1650  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
1651  supervisorDescriptorPairIt->second.getDescriptor(), //supervisor descriptor
1652  "MacroMakerSupervisorRequest",
1653  txParameters);
1654  SOAPUtilities::receive(retMsg, rxParameters);
1655 
1656  __SUP_COUT__ << "Received it " << __E__;
1657 
1658  bool success = rxParameters.getValue("success") == "1";
1659  outputArgs = rxParameters.getValue("outputArgs");
1660 
1661  __SUP_COUT__ << "rx success = " << success << __E__;
1662  __SUP_COUT__ << "outputArgs = " << outputArgs << __E__;
1663 
1664  if(!success)
1665  {
1666  __SS__ << "Attempted FE Macro Failed. Attempted target " <<
1667  "was UID=" << feUID << " at feSupervisorID=" << feSupervisorID << "." << __E__;
1668  ss << "\n\n The error was:\n\n" << outputArgs << __E__;
1669  __SUP_COUT_ERR__ << "\n" << ss.str();
1670  xmldoc.addTextElementToData("Error",ss.str());
1671  return;
1672  }
1673 
1674 
1675  //build output arguments
1676  // parse args, colon-separated pairs, and then comma-separated
1677  {
1678  std::istringstream inputStream(outputArgs);
1679  std::string splitVal, argName, argValue;
1680  while (getline(inputStream, splitVal, ';'))
1681  {
1682  std::istringstream pairInputStream(splitVal);
1683  getline(pairInputStream, argName, ',');
1684  getline(pairInputStream, argValue, ',');
1685  xmldoc.addTextElementToData("outputArgs_name",argName);
1686  xmldoc.addTextElementToData("outputArgs_value",argValue);
1687  __SUP_COUT__ << argName << ": " << argValue << __E__;
1688  }
1689  }
1690 
1691 }
1692 
1693 //========================================================================================================================
1694 void MacroMakerSupervisor::getFEMacroList(HttpXmlDocument& xmldoc, const std::string &username)
1695 {
1696  __SUP_COUT__<< "Getting FE Macro list" << __E__;
1697 
1698  SOAPParameters txParameters; //params for xoap to send
1699  txParameters.addParameter("Request", "GetInterfaceMacros");
1700 
1701  SOAPParameters rxParameters; //params for xoap to recv
1702  rxParameters.addParameter("FEMacros");
1703 
1704  std::string oneInterface;
1705  std::string rxFEMacros;
1706 
1707 
1708  // for each list of FE Supervisors,
1709  // get all FE specific macros
1710  for(auto &appInfo:allFESupervisorInfo_)
1711  {
1712  __SUP_COUT__ << "FESupervisor LID = " << appInfo.second.getId() <<
1713  " name = " << appInfo.second.getName() << __E__;
1714 
1715  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(
1716  appInfo.second.getDescriptor(),
1717  "MacroMakerSupervisorRequest",
1718  txParameters);
1719  SOAPUtilities::receive(retMsg, rxParameters);
1720 
1721  rxFEMacros = rxParameters.getValue("FEMacros");
1722 
1723  __SUP_COUT__ << "FE Macros received: \n" << rxFEMacros << __E__;
1724 
1725  std::istringstream allInterfaces(rxFEMacros);
1726  while (std::getline(allInterfaces, oneInterface))
1727  {
1728  //__SUP_COUT__ << oneInterface << __E__;
1729  //__SUP_COUT__ << appInfo.second.getId() << __E__;
1730  xmldoc.addTextElementToData("FEMacros",oneInterface);
1731  //xmldoc.outputXmlDocument(0,true);
1732  }
1733  }
1734 
1735  //add macros to response
1736  loadMacros(xmldoc, username);
1737 
1738  return;
1739 }
1740 
1741 
1742 
1743 
1744