otsdaq  v2_00_00
FEVInterface.cc
1 #include "otsdaq-core/FECore/FEVInterface.h"
2 #include "otsdaq-core/Macros/CoutHeaderMacros.h"
3 
4 #include "otsdaq-core/NetworkUtilities/UDPDataStreamerBase.h"
5 
6 
7 #include <iostream>
8 #include <sstream>
9 
10 using namespace ots;
11 
12 //========================================================================================================================
13 void FEVInterface::configureSlowControls(void)
14 {
15  ConfigurationTree slowControlsGroupLink =
16  theXDAQContextConfigTree_.getBackNode(
17  theConfigurationPath_).getNode("LinkToSlowControlChannelsConfiguration");
18 
19  if(slowControlsGroupLink.isDisconnected())
20  {
21  __COUT__ << "slowControlsGroupLink is disconnected, so done configuring slow controls." <<
22  std::endl;
23  return;
24  }
25  __COUT__ << "slowControlsGroupLink is valid! Configuring slow controls..." <<
26  std::endl;
27 
28  mapOfSlowControlsChannels_.clear();
29  std::vector<std::pair<std::string,ConfigurationTree> > groupLinkChildren =
30  slowControlsGroupLink.getChildren();
31  for(auto &groupLinkChild: groupLinkChildren)
32  {
33  //skip channels that are off
34  if(!(groupLinkChild.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())) continue;
35 
36  __COUT__ << "Channel:" << getInterfaceUID() <<
37  "/" << groupLinkChild.first << "\t Type:" <<
38  groupLinkChild.second.getNode("ChannelDataType") <<
39  std::endl;
40 
41  mapOfSlowControlsChannels_.insert(
42  std::pair<std::string,FESlowControlsChannel>(
43  groupLinkChild.first,
45  getInterfaceUID(),
46  groupLinkChild.first,
47  groupLinkChild.second.getNode("ChannelDataType").getValue<std::string>(),
48  universalDataSize_,
49  universalAddressSize_,
50  groupLinkChild.second.getNode("UniversalInterfaceAddress").getValue <std::string>(),
51  groupLinkChild.second.getNode("UniversalDataBitOffset").getValue <unsigned int>(),
52  groupLinkChild.second.getNode("ReadAccess").getValue <bool>(),
53  groupLinkChild.second.getNode("WriteAccess").getValue <bool>(),
54  groupLinkChild.second.getNode("MonitoringEnabled").getValue <bool>(),
55  groupLinkChild.second.getNode("RecordChangesOnly").getValue <bool>(),
56  groupLinkChild.second.getNode("DelayBetweenSamplesInSeconds").getValue <time_t>(),
57  groupLinkChild.second.getNode("LocalSavingEnabled").getValue <bool>(),
58  groupLinkChild.second.getNode("LocalFilePath").getValue <std::string>(),
59  groupLinkChild.second.getNode("RadixFileName").getValue <std::string>(),
60  groupLinkChild.second.getNode("SaveBinaryFile").getValue <bool>(),
61  groupLinkChild.second.getNode("AlarmsEnabled").getValue <bool>(),
62  groupLinkChild.second.getNode("LatchAlarms").getValue <bool>(),
63  groupLinkChild.second.getNode("LowLowThreshold").getValue <std::string>(),
64  groupLinkChild.second.getNode("LowThreshold").getValue <std::string>(),
65  groupLinkChild.second.getNode("HighThreshold").getValue <std::string>(),
66  groupLinkChild.second.getNode("HighHighThreshold").getValue <std::string>()
67  )));
68  }
69 
70 }
71 
72 //========================================================================================================================
73 bool FEVInterface::slowControlsRunning(void)
74 {
75  __COUT__ << "slowControlsRunning" << std::endl;
76  std::string readVal;
77  readVal.resize(universalDataSize_); //size to data in advance
78 
79  FESlowControlsChannel *channel;
80 
81  const unsigned int txBufferSz = 1500;
82  const unsigned int txBufferFullThreshold = 750;
83  std::string txBuffer;
84  txBuffer.reserve(txBufferSz);
85 
86  ConfigurationTree FEInterfaceNode = theXDAQContextConfigTree_.getBackNode(
87  theConfigurationPath_);
88 
89  ConfigurationTree slowControlsInterfaceLink =
90  FEInterfaceNode.getNode("LinkToSlowControlsMonitorConfiguration");
91 
92  std::unique_ptr<UDPDataStreamerBase> txSocket;
93 
94  if(slowControlsInterfaceLink.isDisconnected())
95  {
96  __COUT__ << "slowControlsInterfaceLink is disconnected, so no socket made." <<
97  std::endl;
98  }
99  else
100  {
101  __COUT__ << "slowControlsInterfaceLink is valid! Create tx socket..." <<
102  std::endl;
103  txSocket.reset(new UDPDataStreamerBase(
104  FEInterfaceNode.getNode("SlowControlsTxSocketIPAddress").getValue <std::string>(),
105  FEInterfaceNode.getNode("SlowControlsTxSocketPort").getValue <int>(),
106  slowControlsInterfaceLink.getNode("IPAddress").getValue <std::string>(),
107  slowControlsInterfaceLink.getNode("Port").getValue <int>()
108  ));
109  }
110 
111 
112  //check if aggregate saving
113 
114 
115  FILE *fp = 0;
116  bool aggregateFileIsBinaryFormat = false;
117  if(FEInterfaceNode.getNode("SlowControlsLocalAggregateSavingEnabled").getValue<bool>())
118  {
119  aggregateFileIsBinaryFormat =
120  FEInterfaceNode.getNode("SlowControlsSaveBinaryFile").getValue<bool>();
121 
122  __COUT_INFO__ << "Slow Controls Aggregate Saving turned On BinaryFormat=" <<
123  aggregateFileIsBinaryFormat << std::endl;
124 
125  std::string saveFullFileName =
126  FEInterfaceNode.getNode("SlowControlsLocalFilePath").getValue<std::string>() +
127  "/" +
128  FEInterfaceNode.getNode("SlowControlsRadixFileName").getValue<std::string>() +
129  "-" +
130  FESlowControlsChannel::underscoreString(getInterfaceUID()) +
131  "-" + std::to_string(time(0)) +
132  (aggregateFileIsBinaryFormat?".dat":".txt");
133 
134 
135  fp = fopen(saveFullFileName.c_str(),
136  aggregateFileIsBinaryFormat?
137  "ab":"a");
138  if(!fp)
139  {
140  __COUT_ERR__ << "Failed to open slow controls channel file: " <<
141  saveFullFileName << std::endl;
142  //continue on, just nothing will be saved
143  }
144  else
145  __COUT_INFO__ << "Slow controls aggregate file opened: " <<
146  saveFullFileName << std::endl;
147  }
148  else
149  __COUT_INFO__ << "Slow Controls Aggregate Saving turned off." << std::endl;
150 
151 
152  time_t timeCounter = 0;
153 
154  while(slowControlsWorkLoop_.getContinueWorkLoop())
155  {
156  sleep(1); //seconds
157  ++timeCounter;
158 
159  if(txBuffer.size())
160  __COUT__ << "txBuffer sz=" << txBuffer.size() << std::endl;
161 
162  txBuffer.resize(0); //clear buffer a la txBuffer = "";
163 
164  //__COUT__ << "timeCounter=" << timeCounter << std::endl;
165  //__COUT__ << "txBuffer sz=" << txBuffer.size() << std::endl;
166 
167  for(auto &slowControlsChannelPair : mapOfSlowControlsChannels_)
168  {
169  channel = &slowControlsChannelPair.second;
170 
171  //skip if no read access
172  if(!channel->readAccess_) continue;
173 
174  //skip if not a sampling moment in time for channel
175  if(timeCounter % channel->delayBetweenSamples_) continue;
176 
177 
178  __COUT__ << "Channel:" << getInterfaceUID() <<
179  "/" << slowControlsChannelPair.first << std::endl;
180  __COUT__ << "Monitoring..." << std::endl;
181 
182  universalRead(channel->getUniversalAddress(),
183  &readVal[0]);
184 
185  // { //print
186  // __SS__ << "0x ";
187  // for(int i=(int)universalAddressSize_-1;i>=0;--i)
188  // ss << std::hex << (int)((readVal[i]>>4)&0xF) <<
189  // (int)((readVal[i])&0xF) << " " << std::dec;
190  // ss << std::endl;
191  // __COUT__ << "Sampled.\n" << ss.str();
192  // }
193 
194  //have sample
195  channel->handleSample(readVal,txBuffer, fp, aggregateFileIsBinaryFormat);
196  if(txBuffer.size())
197  __COUT__ << "txBuffer sz=" << txBuffer.size() << std::endl;
198 
199  //make sure buffer hasn't exploded somehow
200  if(txBuffer.size() > txBufferSz)
201  {
202  __SS__ << "This should never happen hopefully!" << std::endl;
203  __COUT_ERR__ << "\n" << ss.str();
204  throw std::runtime_error(ss.str());
205  }
206 
207  //send early if threshold reached
208  if(txSocket &&
209  txBuffer.size() > txBufferFullThreshold)
210  {
211  __COUT__ << "Sending now! txBufferFullThreshold=" << txBufferFullThreshold << std::endl;
212  txSocket->send(txBuffer);
213  txBuffer.resize(0); //clear buffer a la txBuffer = "";
214  }
215 
216 
217  }
218 
219  if(txBuffer.size())
220  __COUT__ << "txBuffer sz=" << txBuffer.size() << std::endl;
221 
222  //send anything left
223  if(txSocket &&
224  txBuffer.size())
225  {
226  __COUT__ << "Sending now!" << std::endl;
227  txSocket->send(txBuffer);
228  }
229 
230  if(fp) fflush(fp); //flush anything in aggregate file for reading ease
231  }
232  if(fp) fclose(fp);
233  return false;
234 }
235 
236 //========================================================================================================================
237 //registerFEMacroFunction
238 // used by user-defined front-end interface implementations of this
239 // virtual interface class to register their macro functions.
240 //
241 // Front-end Macro Functions are then made accessible through the ots Control System
242 // web interfaces. The menu consisting of all enabled FEs macros is assembled
243 // by the FE Supervisor (and its FE Interface Manager).
244 void FEVInterface::registerFEMacroFunction(
245  const std::string &feMacroName, frontEndMacroFunction_t feMacroFunction,
246  const std::vector<std::string> &namesOfInputArgs,
247  const std::vector<std::string> &namesOfOutputArgs,
248  uint8_t requiredUserPermissions)
249 {
250  if(mapOfFEMacroFunctions_.find(feMacroName) !=
251  mapOfFEMacroFunctions_.end())
252  {
253  __SS__ << "feMacroName '" << feMacroName << "' already exists! Not allowed." << std::endl;
254  __COUT_ERR__ << "\n" << ss.str();
255  throw std::runtime_error(ss.str());
256  }
257 
258  mapOfFEMacroFunctions_.insert(
259  std::pair<std::string, frontEndMacroStruct_t> (
260  feMacroName,
261  frontEndMacroStruct_t(
262  feMacroFunction,
263  namesOfInputArgs,
264  namesOfOutputArgs,
265  requiredUserPermissions
266  )));
267 }
268 
269 
270 //========================================================================================================================
271 //getFEMacroInputArgument
272 // helper function for getting the value of an argument
273 const std::string& FEVInterface::getFEMacroInputArgument(frontEndMacroInArgs_t& argsIn,
274  const std::string& argName)
275 {
276  for(const std::pair<const std::string /* input arg name */ , const std::string /* arg input value */ >&
277  pair : argsIn)
278  {
279  if(pair.first == argName)
280  {
281 
282  __COUT__ << "argName : " << pair.second << __E__;
283  return pair.second;
284  }
285  }
286  __SS__ << "Requested input argument not found with name '" << argName << "'" << std::endl;
287  __COUT_ERR__ << "\n" << ss.str();
288  throw std::runtime_error(ss.str());
289 }
290 //========================================================================================================================
291 //getFEMacroInputArgumentValue
292 // helper function for getting the copy of the value of an argument
293 template<>
294 std::string getFEMacroInputArgumentValue<std::string>(FEVInterface::frontEndMacroInArgs_t &argsIn,
295  const std::string &argName)
296 {
297  return FEVInterface::getFEMacroInputArgument(argsIn,argName);
298 }
299 
300 //========================================================================================================================
301 //getFEMacroOutputArgument
302 // helper function for getting the value of an argument
303 std::string& FEVInterface::getFEMacroOutputArgument(frontEndMacroOutArgs_t& argsOut,
304  const std::string& argName)
305 {
306 
307  for(std::pair<const std::string /* output arg name */ , std::string /* arg output value */ >&
308  pair : argsOut)
309  {
310  if(pair.first == argName)
311  return pair.second;
312  }
313  __SS__ << "Requested output argument not found with name '" << argName << "'" << std::endl;
314  __COUT_ERR__ << "\n" << ss.str();
315  throw std::runtime_error(ss.str());
316 }
317 
318 //========================================================================================================================
319 //runSequenceOfCommands
320 // runs a sequence of write commands from a linked section of the configuration tree
321 // based on these fields:
322 // - WriteAddress, WriteValue, StartingBitPosition, BitFieldSize
323 void FEVInterface::runSequenceOfCommands(const std::string &treeLinkName)
324 {
325  std::map<uint64_t,uint64_t> writeHistory;
326  uint64_t writeAddress, writeValue, bitMask;
327  uint8_t bitPosition;
328 
329  std::string writeBuffer;
330  std::string readBuffer;
331  char msg[1000];
332  try
333  {
334  auto configSeqLink = theXDAQContextConfigTree_.getNode(theConfigurationPath_).getNode(
335  treeLinkName);
336 
337  if(configSeqLink.isDisconnected())
338  __COUT__ << "Disconnected configure sequence" << std::endl;
339  else
340  {
341  __COUT__ << "Handling configure sequence." << std::endl;
342  auto childrenMap = configSeqLink.getChildrenMap();
343  for(const auto &child:childrenMap)
344  {
345  //WriteAddress and WriteValue fields
346 
347  writeAddress = child.second.getNode("WriteAddress").getValue<uint64_t>();
348  writeValue = child.second.getNode("WriteValue").getValue<uint64_t>();
349  bitPosition = child.second.getNode("StartingBitPosition").getValue<uint8_t>();
350  bitMask = (1 << child.second.getNode("BitFieldSize").getValue<uint8_t>())-1;
351 
352  writeValue &= bitMask;
353  writeValue <<= bitPosition;
354  bitMask = ~(bitMask<<bitPosition);
355 
356  //place into write history
357  if(writeHistory.find(writeAddress) == writeHistory.end())
358  writeHistory[writeAddress] = 0;//init to 0
359 
360  writeHistory[writeAddress] &= bitMask; //clear incoming bits
361  writeHistory[writeAddress] |= writeValue; //add incoming bits
362 
363  sprintf(msg,"\t Writing %s: \t %ld(0x%lX) \t %ld(0x%lX)", child.first.c_str(),
364  writeAddress, writeAddress,
365  writeHistory[writeAddress], writeHistory[writeAddress]);
366 
367  __COUT__ << msg << std::endl;
368 
369  universalWrite((char *)&writeAddress,(char *)&(writeHistory[writeAddress]));
370  }
371  }
372  }
373  catch(const std::runtime_error &e)
374  {
375  __COUT__ << "Error accessing sequence, so giving up:\n" << e.what() << std::endl;
376  }
377  catch(...)
378  {
379  __COUT__ << "Unknown Error accessing sequence, so giving up." << std::endl;
380  }
381 }
382 
383 //==============================================================================
384 //isNumber ~~
385 // returns true if hex ("0x.."), binary("b..."), or base10 number
386 bool FEVInterface::isNumber(const std::string& s)
387 {
388  //__COUT__ << "string " << s << std::endl;
389  if(s.find("0x") == 0) //indicates hex
390  {
391  //__COUT__ << "0x found" << std::endl;
392  for(unsigned int i=2;i<s.size();++i)
393  {
394  if(!((s[i] >= '0' && s[i] <= '9') ||
395  (s[i] >= 'A' && s[i] <= 'F') ||
396  (s[i] >= 'a' && s[i] <= 'f')
397  ))
398  {
399  //__COUT__ << "prob " << s[i] << std::endl;
400  return false;
401  }
402  }
403  //return std::regex_match(s.substr(2), std::regex("^[0-90-9a-fA-F]+"));
404  }
405  else if(s[0] == 'b') //indicates binary
406  {
407  //__COUT__ << "b found" << std::endl;
408 
409  for(unsigned int i=1;i<s.size();++i)
410  {
411  if(!((s[i] >= '0' && s[i] <= '1')
412  ))
413  {
414  //__COUT__ << "prob " << s[i] << std::endl;
415  return false;
416  }
417  }
418  }
419  else
420  {
421  //__COUT__ << "base 10 " << std::endl;
422  for(unsigned int i=0;i<s.size();++i)
423  if(!((s[i] >= '0' && s[i] <= '9') ||
424  s[i] == '.' ||
425  s[i] == '+' ||
426  s[i] == '-'))
427  return false;
428  //Note: std::regex crashes in unresolvable ways (says Ryan.. also, stop using libraries)
429  //return std::regex_match(s, std::regex("^(\\-|\\+)?[0-9]*(\\.[0-9]+)?"));
430  }
431 
432  return true;
433 }
434 
435 
436 
437 
438 
439 
440 
441 
442 
443 
444 
445 
446 
447 
448 
449 
450 
451 
452 
453 
454 
455 
456