tdaq-develop-2025-02-12
FESlowControlsChannel.cc
1 #include "otsdaq/FECore/FESlowControlsChannel.h"
2 #include "otsdaq/FECore/FEVInterface.h"
3 #include "otsdaq/Macros/BinaryStringMacros.h"
4 #include "otsdaq/Macros/CoutMacros.h"
5 
6 #include <iostream>
7 #include <sstream>
8 #include <stdexcept> /*runtime_error*/
9 
10 using namespace ots;
11 
12 #undef __MF_SUBJECT__
13 #define __MF_SUBJECT__ "SlowControls"
14 #define mfSubject_ (interface_->getInterfaceUID() + "-" + channelName)
15 
31 //==============================================================================
33  const std::string& channelNameIn,
34  const std::string& dataTypeIn,
35  const std::string& universalAddress,
36  const std::string& transformationIn,
37  unsigned int universalDataBitOffset,
38  bool readAccess,
39  bool writeAccess,
40  bool monitoringEnabledIn,
41  bool recordChangesOnly,
42  time_t delayBetweenSamples,
43  bool saveEnabled,
44  const std::string& savePath,
45  const std::string& saveFileRadix,
46  bool saveBinaryFormat,
47  bool alarmsEnabled,
48  bool latchAlarms,
49  const std::string& lolo,
50  const std::string& lo,
51  const std::string& hi,
52  const std::string& hihi)
53  : interface_(interface)
54  , channelName(channelNameIn)
55  , fullChannelName(interface->getInterfaceUID() + ":" + channelName)
56  , dataType(dataTypeIn)
57  , transformation(transformationIn)
58  , universalDataBitOffset_(universalDataBitOffset)
59  , txPacketSequenceNumber_(0)
60  , readAccess_(readAccess)
61  , writeAccess_(writeAccess)
62  , monitoringEnabled(monitoringEnabledIn)
63  , recordChangesOnly_(recordChangesOnly)
64  , delayBetweenSamples_(delayBetweenSamples < 1
65  ? 1
66  : delayBetweenSamples) // units of seconds, with 1 minimum
67  , saveEnabled_(saveEnabled)
68  , savePath_(savePath)
69  , saveFileRadix_(saveFileRadix)
70  , saveBinaryFormat_(saveBinaryFormat)
71  , alarmsEnabled_(alarmsEnabled)
72  , latchAlarms_(latchAlarms)
73  , lastSampleTime_(0)
74  , loloAlarmed_(false)
75  , loAlarmed_(false)
76  , hiAlarmed_(false)
77  , hihiAlarmed_(false)
78  , saveFullFileName_(savePath_ + "/" + saveFileRadix_ + "-" +
79  underscoreString(fullChannelName) + "-" +
80  std::to_string(time(0)) + (saveBinaryFormat_ ? ".dat" : ".txt"))
81 {
82  __GEN_COUTV__(dataType);
83  __GEN_COUTV__(interface->getUniversalAddressSize());
84  __GEN_COUTV__(universalAddress);
85  __GEN_COUTV__(transformation);
86 
87  if(interface->getUniversalAddressSize() == 0 ||
88  interface->getUniversalDataSize() == 0)
89  {
90  __GEN_SS__ << "The front-end interface must have a non-zero universal address "
91  "and data size. Current address size = "
92  << interface->getUniversalAddressSize()
93  << ", data size = " << interface->getUniversalDataSize() << __E__;
94  __GEN_SS_THROW__;
95  }
96 
97  sizeOfReadBytes_ = 0;
98 
99  // check for valid types:
100  // if(dataType != "char" &&
101  // dataType != "short" &&
102  // dataType != "int" &&
103  // dataType != "unsigned int" &&
104  // dataType != "long long " &&
105  // dataType != "unsigned long long" &&
106  // dataType != "float" &&
107  // dataType != "double")
108  // {
109  if(dataType.size() > 1 &&
110  dataType[dataType.size() - 1] == 'b') // if ends in 'b' then take that many bits
111  {
112  //if dataType leads with xB then yb, the use x as the number of read bytes (e.g. for a block read)
113 
114  //search for 'B'
115  for(unsigned int i = 0; i < dataType.size() - 1; ++i)
116  if(dataType[i] == 'B') //then treat as number of read bytes
117  {
118  sscanf(&dataType[0], "%uB", &sizeOfReadBytes_);
119  ++i; //to get past 'B'
120  sscanf(&dataType[i], "%u", &sizeOfDataTypeBits_);
121  break;
122  }
123  else if(i == dataType.size() - 2) //else no 'B'
124  sscanf(&dataType[0], "%u", &sizeOfDataTypeBits_);
125  }
126  else if(dataType == "char" || dataType == "unsigned char")
127  sizeOfDataTypeBits_ = sizeof(char) * 8;
128  else if(dataType == "short" || dataType == "unsigned short")
129  sizeOfDataTypeBits_ = sizeof(short) * 8;
130  else if(dataType == "int" || dataType == "unsigned int")
131  sizeOfDataTypeBits_ = sizeof(int) * 8;
132  else if(dataType == "long long" || dataType == "unsigned long long")
133  sizeOfDataTypeBits_ = sizeof(long long) * 8;
134  else if(dataType == "float")
135  sizeOfDataTypeBits_ = sizeof(float) * 8;
136  else if(dataType == "double")
137  sizeOfDataTypeBits_ = sizeof(double) * 8;
138  else
139  {
140  __GEN_SS__ << "ChannelDataType '" << dataType << "' is invalid. "
141  << "Valid data types (w/size in bytes) are as follows: "
142  << "#b (# bits)"
143  << ", char (" << sizeof(char) << "B), unsigned char ("
144  << sizeof(unsigned char) << "B), short (" << sizeof(short)
145  << "B), unsigned short (" << sizeof(unsigned short) << "B), int ("
146  << sizeof(int) << "B), unsigned int (" << sizeof(unsigned int)
147  << "B), long long (" << sizeof(long long) << "B), unsigned long long ("
148  << sizeof(unsigned long long) << "B), float (" << sizeof(float)
149  << "B), double (" << sizeof(double) << "B)." << __E__;
150  __GEN_COUT_ERR__ << "\n" << ss.str();
151  __GEN_SS_THROW__;
152  }
153 
154  //calculate number of bytes to read
155  if(!sizeOfReadBytes_)
156  sizeOfReadBytes_ =
157  ((universalDataBitOffset_ + sizeOfDataTypeBits_) / 8 +
158  (((universalDataBitOffset_ + sizeOfDataTypeBits_) % 8) ? 1 : 0));
159  sizeOfDataTypeBytes_ =
160  ((sizeOfDataTypeBits_) / 8 + (((sizeOfDataTypeBits_) % 8) ? 1 : 0));
161 
162  universalAddress_.resize(interface->getUniversalAddressSize());
163  try
164  {
165  convertStringToBuffer(universalAddress, universalAddress_);
166  __GEN_COUTV__(
167  BinaryStringMacros::binaryNumberToHexString(universalAddress_, "0x", " "));
168  }
169  catch(const std::runtime_error& e)
170  {
171  __GEN_SS__ << "Failed to extract universalAddress '" << universalAddress << "'..."
172  << __E__;
173  ss << e.what();
174  __GEN_SS_THROW__;
175  }
176 
177  __GEN_COUTV__(sizeOfReadBytes_);
178  __GEN_COUTV__(interface->getUniversalDataSize());
179  if(sizeOfReadBytes_ > interface->getUniversalDataSize() &&
181  {
182  //check if FE supports Block Reads by using a test read (because the compiler does not allow this preferrable code attempt below...)
183  // if(interface->*(&FEVInterface::universalBlockRead) != (&FEVInterface::universalBlockRead))
184  // {
185  // __GEN_COUT__ << "This FE interface does implement block reads." << __E__;
186  // }
187  try //check if FE supports Block Reads by using a test read
188  {
189  std::string readValue;
190  readValue.resize(sizeOfReadBytes_);
191  interface->universalBlockRead(
192  &universalAddress_[0], &readValue[0], sizeOfReadBytes_);
193  }
194  catch(const std::runtime_error& e)
195  {
196  __GEN_COUTV__(StringMacros::demangleTypeName(typeid(*interface).name()));
197  if(strcmp(e.what(), "UNDEFINED BLOCK READ") == 0)
198  {
199  __GEN_SS__ << "Invalid Data Type '" << dataType
200  << "' (offset:" << universalDataBitOffset_ << " + "
201  << sizeOfDataTypeBits_ << "-bits) = " << sizeOfReadBytes_
202  << "-bytes. Data Type size must be less than or equal to "
203  "Universal Data Size = "
204  << interface->getUniversalDataSize()
205  << "-bytes. (Or the FEInterface must implement the virtual "
206  "function universalBlockRead() for larger read sizes)"
207  << __E__;
208  __GEN_COUT_ERR__ << "\n" << ss.str();
209  __GEN_SS_THROW__;
210  }
211  else // else ignore error for test read (assume things are not setup yet)
212  __GEN_COUT_WARN__ << "Ignoring test block read error - assuming FE not "
213  "setup yet - here is the caught exception:\n"
214  << e.what() << __E__;
215  }
216  __GEN_COUT__ << "Block read was found to be implemented!" << __E__;
218  true; //set to avoid more tests of block read functionality
219  }
220 
221  lolo_.resize(sizeOfDataTypeBytes_);
222  lo_.resize(sizeOfDataTypeBytes_);
223  hi_.resize(sizeOfDataTypeBytes_);
224  hihi_.resize(sizeOfDataTypeBytes_);
225 
226  if(alarmsEnabled_)
227  {
228  try
229  {
230  convertStringToBuffer(lolo, lolo_, true);
231  }
232  catch(const std::runtime_error& e)
233  {
234  __GEN_SS__ << "Failed to extract lolo '" << lolo << "'..." << __E__;
235  ss << e.what();
236  __GEN_SS_THROW__;
237  }
238  try
239  {
240  convertStringToBuffer(lo, lo_, true);
241  }
242  catch(const std::runtime_error& e)
243  {
244  __GEN_SS__ << "Failed to extract lo '" << lo << "'..." << __E__;
245  ss << e.what();
246  __GEN_SS_THROW__;
247  }
248  try
249  {
250  convertStringToBuffer(hi, hi_, true);
251  }
252  catch(const std::runtime_error& e)
253  {
254  __GEN_SS__ << "Failed to extract hi '" << hi << "'..." << __E__;
255  ss << e.what();
256  __GEN_SS_THROW__;
257  }
258  try
259  {
260  convertStringToBuffer(hihi, hihi_, true);
261  }
262  catch(const std::runtime_error& e)
263  {
264  __GEN_SS__ << "Failed to extract hihi '" << hihi << "'..." << __E__;
265  ss << e.what();
266  __GEN_SS_THROW__;
267  }
268  }
269 
270  // prepare for data to come
271  sample_.resize(sizeOfDataTypeBytes_);
272  lastSample_.resize(sizeOfDataTypeBytes_);
273 
274  __GEN_COUT__;
275  print();
276  __GEN_COUT__ << "Constructed." << __E__;
277 } // end constructor
278 
279 //==============================================================================
280 FESlowControlsChannel::~FESlowControlsChannel(void) {}
281 
282 const std::string& FESlowControlsChannel::getInterfaceUID(void) const
283 {
284  return interface_->getInterfaceUID();
285 }
286 const std::string& FESlowControlsChannel::getInterfaceType(void) const
287 {
288  return interface_->getInterfaceType();
289 }
290 
291 //==============================================================================
292 void FESlowControlsChannel::doRead(std::string& readValue)
293 {
294  if(getReadSizeBytes() > interface_->getUniversalDataSize())
295  {
296  //block read!
297  readValue.resize(getReadSizeBytes());
298  interface_->universalBlockRead(
299  &universalAddress_[0], &readValue[0], getReadSizeBytes());
300  }
301  else //normal read
302  {
303  readValue.resize(interface_->getUniversalDataSize());
304  interface_->universalRead(&universalAddress_[0], &readValue[0]);
305  }
306 } // end doRead()
307 
308 //==============================================================================
309 void FESlowControlsChannel::print(std::ostream& out) const
310 {
311  out << "Slow Controls Channel '" << mfSubject_ << "'" << __E__;
312 
313  out << "\t"
314  << "dataType: " << dataType << __E__;
315  out << "\t"
316  << "sizeOfDataTypeBits_: " << sizeOfDataTypeBits_ << __E__;
317  out << "\t"
318  << "sizeOfDataTypeBytes_: " << sizeOfDataTypeBytes_ << __E__;
319  out << "\t"
320  << "universalDataBitOffset_: " << universalDataBitOffset_ << __E__;
321  out << "\t"
322  << "sizeOfReadBytes_: " << sizeOfReadBytes_ << __E__;
323  out << "\t"
324  << "universalAddress_: "
325  << BinaryStringMacros::binaryNumberToHexString(universalAddress_, "0x", " ")
326  << __E__;
327  out << "\t"
328  << "transformation: " << transformation << __E__;
329  out << "\t"
330  << "readAccess_: " << readAccess_ << __E__;
331  out << "\t"
332  << "writeAccess_: " << writeAccess_ << __E__;
333  out << "\t"
334  << "monitoringEnabled: " << monitoringEnabled << __E__;
335  out << "\t"
336  << "recordChangesOnly_: " << recordChangesOnly_ << __E__;
337  out << "\t"
338  << "delayBetweenSamples_: " << delayBetweenSamples_ << __E__;
339  out << "\t"
340  << "saveEnabled_: " << saveEnabled_ << __E__;
341  out << "\t"
342  << "savePath_: " << savePath_ << __E__;
343  out << "\t"
344  << "saveFileRadix_: " << saveFileRadix_ << __E__;
345  out << "\t"
346  << "saveBinaryFormat_: " << saveBinaryFormat_ << __E__;
347  out << "\t"
348  << "alarmsEnabled_: " << alarmsEnabled_ << __E__;
349  out << "\t"
350  << "latchAlarms_: " << latchAlarms_ << __E__;
351  out << "\t"
352  << "savePath_: " << savePath_ << __E__;
353  out << "\t"
354  << "saveFullFileName_: " << saveFullFileName_ << __E__;
355 
356 } // end print()
357 
358 //==============================================================================
361 std::string FESlowControlsChannel::underscoreString(const std::string& str)
362 {
363  std::string retStr;
364  retStr.reserve(str.size());
365  for(unsigned int i = 0; i < str.size(); ++i)
366  if((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') ||
367  (str[i] >= '0' && str[i] <= '9'))
368  retStr.push_back(str[i]);
369  else
370  retStr.push_back('_');
371  return retStr;
372 } // end underscoreString()
373 
374 //==============================================================================
379 void FESlowControlsChannel::convertStringToBuffer(const std::string& inString,
380  std::string& buffer,
381  bool useDataType /* = false */)
382 {
383  if(useDataType && (dataType == "float" || dataType == "double"))
384  {
385  __GEN_COUT__ << "Floating point spec'd" << __E__;
386  if(dataType == "float" && buffer.size() == sizeof(float))
387  {
388  sscanf(&inString[0], "%f", (float*)&buffer[0]);
389  __GEN_COUT__ << "float: " << *((float*)&buffer[0]) << __E__;
390  }
391  else if(dataType == "double" && buffer.size() == sizeof(double))
392  {
393  sscanf(&inString[0], "%lf", (double*)&buffer[0]);
394  __GEN_COUT__ << "double: " << *((double*)&buffer[0]) << __E__;
395  }
396  else
397  {
398  __GEN_SS__ << "Invalid floating point spec! "
399  << "dataType=" << dataType << " buffer.size()=" << buffer.size()
400  << __E__;
401  __GEN_COUT_ERR__ << "\n" << ss.str();
402  __GEN_SS_THROW__;
403  }
404 
405  { // print
406  __GEN_SS__ << "0x ";
407  for(int i = (int)buffer.size() - 1; i >= 0; --i)
408  ss << std::hex << (int)((buffer[i] >> 4) & 0xF)
409  << (int)((buffer[i]) & 0xF) << " " << std::dec;
410  ss << __E__;
411  __GEN_COUT__ << "\n" << ss.str();
412  }
413  return;
414  }
415 
416  // at this point assume unsigned number that will be matched to buffer size
417  unsigned long long val;
418  if(!StringMacros::getNumber(inString, val))
419  {
420  __GEN_SS__ << "Invalid unsigned number format in string " << inString << __E__;
421  ss << __E__;
422  print(ss);
423  __GEN_SS_THROW__;
424  }
425  // transfer the long long to the buffer
426  unsigned int i = 0;
427  for(; i < sizeof(long long) && i < buffer.size(); ++i)
428  buffer[i] = ((char*)&val)[i];
429 
430  // clear remaining buffer
431  for(; i < buffer.size(); ++i)
432  buffer[i] = 0;
433 
434  __COUTT__ << "Resulting Number Buffer: "
435  << BinaryStringMacros::binaryNumberToHexString(buffer, "0x", " ") << __E__;
436 } // end convertStringToBuffer()
437 
438 //==============================================================================
441 void FESlowControlsChannel::handleSample(const std::string& universalReadValue,
442  std::string& txBuffer,
443  FILE* fpAggregate,
444  bool aggregateIsBinaryFormat,
445  bool txBufferUsed)
446 {
447  // __GEN_COUT__ << "txBuffer size=" << txBuffer.size() << __E__;
448 
449  // first copy the read value to the channel, then extract sample from universalReadValue_
450  universalReadValue_ = universalReadValue;
451  // considering bit size and offset
452  extractSample(); // sample_ = universalReadValue_
453 
454  // behavior:
455  // if recordChangesOnly
456  // if no change and not first value
457  // return
458  //
459  // for interesting value
460  // if monitoringEnabled
461  // add packet to buffer
462  // if alarmsEnabled
463  // for each alarm add packet to buffer
464  // if localSavingEnabled
465  // append to file
466 
468 
469  lastSampleTime_ = time(0);
470 
471  if(recordChangesOnly_)
472  {
473  if(lastSampleTime_ && lastSample_ == sample_)
474  {
475  __GEN_COUT__ << "no change." << __E__;
476  return; // no change
477  }
478  }
479 
480  __GEN_COUT__ << "new value!" << __E__;
481 
482  // else we have an interesting value!
483  lastSample_ = sample_;
484 
485  char alarmMask = 0;
486 
490  if(monitoringEnabled && txBufferUsed)
491  {
492  // create value packet:
493  // 1B type (0: value, 1: loloalarm, 2: loalarm, 3: hioalarm, 4: hihialarm)
494  // 1B sequence count from channel
495  // 8B time
496  // 4B sz of name
497  // name
498  // 1B sz of value in bytes
499  // 1B sz of value in bits
500  // value
501 
502  __GEN_COUT__ << "before txBuffer sz=" << txBuffer.size() << __E__;
503  txBuffer.push_back(0); // value type
504  txBuffer.push_back(txPacketSequenceNumber_++); // sequence counter and increment
505 
506  txBuffer.resize(txBuffer.size() + sizeof(lastSampleTime_));
507  memcpy(&txBuffer[txBuffer.size() - sizeof(lastSampleTime_)] /*dest*/,
508  &lastSampleTime_ /*src*/,
509  sizeof(lastSampleTime_));
510 
511  unsigned int tmpSz = fullChannelName.size();
512 
513  txBuffer.resize(txBuffer.size() + sizeof(tmpSz));
514  memcpy(&txBuffer[txBuffer.size() - sizeof(tmpSz)] /*dest*/,
515  &tmpSz /*src*/,
516  sizeof(tmpSz));
517 
518  txBuffer += fullChannelName;
519 
520  txBuffer.push_back((unsigned char)sample_.size()); // size in bytes
521  txBuffer.push_back((unsigned char)sizeOfDataTypeBits_); // size in bits
522 
523  txBuffer += sample_;
524  __GEN_COUT__ << "after txBuffer sz=" << txBuffer.size() << __E__;
525 
526  { // print
527  __GEN_SS__ << "txBuffer: \n";
528  for(unsigned int i = 0; i < txBuffer.size(); ++i)
529  {
530  ss << std::hex << (int)((txBuffer[i] >> 4) & 0xF)
531  << (int)((txBuffer[i]) & 0xF) << " " << std::dec;
532  if(i % 8 == 7)
533  ss << __E__;
534  }
535  ss << __E__;
536  __GEN_COUT__ << "\n" << ss.str();
537  }
538  }
539 
540  // check alarms
541  if(alarmsEnabled_ && txBufferUsed)
542  alarmMask = checkAlarms(txBuffer);
543 
544  // create array helper for saving
545  std::string* alarmValueArray[] = {&lolo_, &lo_, &hi_, &hihi_};
546 
550  if(fpAggregate) // aggregate file means saving enabled at FE level
551  {
552  // append to file
553  if(aggregateIsBinaryFormat)
554  {
555  // save binary format:
556  // 8B time (save any alarms by marking with time = 1, 2, 3, 4)
557  // 4B sz of name
558  // name
559  // 1B sz of value in bytes
560  // 1B sz of value in bits
561  // value or alarm threshold
562 
563  __GEN_COUT__ << "Aggregate Binary File Format: " << sizeof(lastSampleTime_)
564  << " " << sample_.size() << __E__;
565 
566  {
567  fwrite(&lastSampleTime_,
568  sizeof(lastSampleTime_),
569  1,
570  fpAggregate); // 8B time
571 
572  unsigned int tmpSz = fullChannelName.size();
573  fwrite(&tmpSz, sizeof(tmpSz), 1, fpAggregate); // 4B sz of name
574  fwrite(&fullChannelName[0],
575  fullChannelName.size(),
576  1,
577  fpAggregate); // name
578 
579  unsigned char tmpChar = (unsigned char)sample_.size();
580  fwrite(&tmpChar, 1, 1, fpAggregate); // size in bytes
581 
582  tmpChar = (unsigned char)sizeOfDataTypeBits_;
583  fwrite(&tmpChar, 1, 1, fpAggregate); // size in bits
584  fwrite(&sample_[0], sample_.size(), 1, fpAggregate); // value
585  }
586 
587  // save any alarms by marking with time 1, 2, 3, 4
588  if(alarmMask) // if any alarms
589  for(time_t i = 1; i < 5; ++i, alarmMask >>= 1)
590  if(alarmMask & 1)
591  {
592  {
593  fwrite(&i,
594  sizeof(lastSampleTime_),
595  1,
596  fpAggregate); // 8B save any alarms by marking with
597  // time = 1, 2, 3, 4
598 
599  unsigned int tmpSz = fullChannelName.size();
600  fwrite(
601  &tmpSz, sizeof(tmpSz), 1, fpAggregate); // 4B sz of name
602  fwrite(&fullChannelName[0],
603  fullChannelName.size(),
604  1,
605  fpAggregate); // name
606 
607  unsigned char tmpChar = (unsigned char)sample_.size();
608  fwrite(&tmpChar, 1, 1, fpAggregate); // size in bytes
609 
610  tmpChar = (unsigned char)sizeOfDataTypeBits_;
611  fwrite(&tmpChar, 1, 1, fpAggregate); // size in bits
612  fwrite(&(*alarmValueArray[i - 1])[0],
613  (*alarmValueArray[i - 1]).size(),
614  1,
615  fpAggregate); // alarm threshold
616  }
617  }
618  }
619  else
620  {
621  // save text format:
622  // timestamp (save any alarms by marking with time 1, 2, 3, 4)
623  // name
624  // value
625 
626  __GEN_COUT__ << "Aggregate Text File Format: " << dataType << __E__;
627 
628  fprintf(fpAggregate, "%lu\n", lastSampleTime_);
629  fprintf(fpAggregate, "%s\n", fullChannelName.c_str());
630 
631  if(dataType[dataType.size() - 1] ==
632  'b') // if ends in 'b' then take that many bits
633  {
634  std::stringstream ss;
635  ss << "0x";
636  for(unsigned int i = 0; i < sample_.size(); ++i)
637  ss << std::hex << (int)((sample_[i] >> 4) & 0xF)
638  << (int)((sample_[i]) & 0xF) << std::dec;
639  fprintf(fpAggregate, "%s\n", ss.str().c_str());
640  }
641  else if(dataType == "char")
642  fprintf(fpAggregate, "%d\n", *((char*)(&sample_[0])));
643  else if(dataType == "unsigned char")
644  fprintf(fpAggregate, "%u\n", *((unsigned char*)(&sample_[0])));
645  else if(dataType == "short")
646  fprintf(fpAggregate, "%d\n", *((short*)(&sample_[0])));
647  else if(dataType == "unsigned short")
648  fprintf(fpAggregate, "%u\n", *((unsigned short*)(&sample_[0])));
649  else if(dataType == "int")
650  fprintf(fpAggregate, "%d\n", *((int*)(&sample_[0])));
651  else if(dataType == "unsigned int")
652  fprintf(fpAggregate, "%u\n", *((unsigned int*)(&sample_[0])));
653  else if(dataType == "long long")
654  fprintf(fpAggregate, "%lld\n", *((long long*)(&sample_[0])));
655  else if(dataType == "unsigned long long")
656  fprintf(fpAggregate, "%llu\n", *((unsigned long long*)(&sample_[0])));
657  else if(dataType == "float")
658  fprintf(fpAggregate, "%f\n", *((float*)(&sample_[0])));
659  else if(dataType == "double")
660  fprintf(fpAggregate, "%f\n", *((double*)(&sample_[0])));
661 
662  // save any alarms by marking with time 1, 2, 3, 4
663  if(alarmMask) // if any alarms
664  {
665  char checkMask = 1; // use mask to maintain alarm mask
666  for(time_t i = 1; i < 5; ++i, checkMask <<= 1)
667  if(alarmMask & checkMask)
668  {
669  fprintf(fpAggregate, "%lu\n", i);
670  fprintf(fpAggregate, "%s\n", fullChannelName.c_str());
671 
672  if(dataType[dataType.size() - 1] ==
673  'b') // if ends in 'b' then take that many bits
674  {
675  std::stringstream ss;
676  ss << "0x";
677  for(unsigned int j = 0; j < (*alarmValueArray[i - 1]).size();
678  ++i)
679  ss << std::hex
680  << (int)(((*alarmValueArray[i - 1])[j] >> 4) & 0xF)
681  << (int)(((*alarmValueArray[i - 1])[j]) & 0xF)
682  << std::dec;
683  fprintf(fpAggregate, "%s\n", ss.str().c_str());
684  }
685  else if(dataType == "char")
686  fprintf(fpAggregate,
687  "%d\n",
688  *((char*)(&(*alarmValueArray[i - 1])[0])));
689  else if(dataType == "unsigned char")
690  fprintf(fpAggregate,
691  "%u\n",
692  *((unsigned char*)(&(*alarmValueArray[i - 1])[0])));
693  else if(dataType == "short")
694  fprintf(fpAggregate,
695  "%d\n",
696  *((short*)(&(*alarmValueArray[i - 1])[0])));
697  else if(dataType == "unsigned short")
698  fprintf(fpAggregate,
699  "%u\n",
700  *((unsigned short*)(&(*alarmValueArray[i - 1])[0])));
701  else if(dataType == "int")
702  fprintf(fpAggregate,
703  "%d\n",
704  *((int*)(&(*alarmValueArray[i - 1])[0])));
705  else if(dataType == "unsigned int")
706  fprintf(fpAggregate,
707  "%u\n",
708  *((unsigned int*)(&(*alarmValueArray[i - 1])[0])));
709  else if(dataType == "long long")
710  fprintf(fpAggregate,
711  "%lld\n",
712  *((long long*)(&(*alarmValueArray[i - 1])[0])));
713  else if(dataType == "unsigned long long")
714  fprintf(
715  fpAggregate,
716  "%llu\n",
717  *((unsigned long long*)(&(*alarmValueArray[i - 1])[0])));
718  else if(dataType == "float")
719  fprintf(fpAggregate,
720  "%f\n",
721  *((float*)(&(*alarmValueArray[i - 1])[0])));
722  else if(dataType == "double")
723  fprintf(fpAggregate,
724  "%f\n",
725  *((double*)(&(*alarmValueArray[i - 1])[0])));
726  }
727  }
728  }
729  }
730 
734  if(saveEnabled_)
735  {
736  FILE* fp = fopen(saveFullFileName_.c_str(), saveBinaryFormat_ ? "ab" : "a");
737  if(!fp)
738  {
739  __GEN_COUT_ERR__ << "Failed to open slow controls channel file: "
740  << saveFullFileName_ << __E__;
741  return;
742  }
743 
744  // append to file
745  if(saveBinaryFormat_)
746  {
747  __GEN_COUT__ << "Binary File Format: " << sizeof(lastSampleTime_) << " "
748  << sample_.size() << __E__;
749  fwrite(&lastSampleTime_, sizeof(lastSampleTime_), 1, fp);
750  fwrite(&sample_[0], sample_.size(), 1, fp);
751 
752  // save any alarms by marking with time 1, 2, 3, 4
753  if(alarmMask) // if any alarms
754  for(time_t i = 1; i < 5; ++i, alarmMask >>= 1)
755  if(alarmMask & 1)
756  {
757  fwrite(&i, sizeof(lastSampleTime_), 1, fp);
758  fwrite(&(*alarmValueArray[i - 1])[0],
759  (*alarmValueArray[i - 1]).size(),
760  1,
761  fp);
762  }
763  }
764  else
765  {
766  __GEN_COUT__ << "Text File Format: " << dataType << __E__;
767 
768  fprintf(fp, "%lu\n", lastSampleTime_);
769 
770  if(dataType[dataType.size() - 1] ==
771  'b') // if ends in 'b' then take that many bits
772  {
773  std::stringstream ss;
774  ss << "0x";
775  for(unsigned int i = 0; i < sample_.size(); ++i)
776  ss << std::hex << (int)((sample_[i] >> 4) & 0xF)
777  << (int)((sample_[i]) & 0xF) << std::dec;
778  fprintf(fp, "%s\n", ss.str().c_str());
779  }
780  else if(dataType == "char")
781  fprintf(fp, "%d\n", *((char*)(&sample_[0])));
782  else if(dataType == "unsigned char")
783  fprintf(fp, "%u\n", *((unsigned char*)(&sample_[0])));
784  else if(dataType == "short")
785  fprintf(fp, "%d\n", *((short*)(&sample_[0])));
786  else if(dataType == "unsigned short")
787  fprintf(fp, "%u\n", *((unsigned short*)(&sample_[0])));
788  else if(dataType == "int")
789  fprintf(fp, "%d\n", *((int*)(&sample_[0])));
790  else if(dataType == "unsigned int")
791  fprintf(fp, "%u\n", *((unsigned int*)(&sample_[0])));
792  else if(dataType == "long long")
793  fprintf(fp, "%lld\n", *((long long*)(&sample_[0])));
794  else if(dataType == "unsigned long long")
795  fprintf(fp, "%llu\n", *((unsigned long long*)(&sample_[0])));
796  else if(dataType == "float")
797  fprintf(fp, "%f\n", *((float*)(&sample_[0])));
798  else if(dataType == "double")
799  fprintf(fp, "%f\n", *((double*)(&sample_[0])));
800 
801  // save any alarms by marking with time 1, 2, 3, 4
802  if(alarmMask) // if any alarms
803  {
804  char checkMask = 1; // use mask to maintain alarm mask
805  for(time_t i = 1; i < 5; ++i, checkMask <<= 1)
806  if(alarmMask & checkMask)
807  {
808  fprintf(fp, "%lu\n", i);
809 
810  if(dataType[dataType.size() - 1] ==
811  'b') // if ends in 'b' then take that many bits
812  {
813  std::stringstream ss;
814  ss << "0x";
815  for(unsigned int j = 0; j < (*alarmValueArray[i - 1]).size();
816  ++i)
817  ss << std::hex
818  << (int)(((*alarmValueArray[i - 1])[j] >> 4) & 0xF)
819  << (int)(((*alarmValueArray[i - 1])[j]) & 0xF)
820  << std::dec;
821  fprintf(fp, "%s\n", ss.str().c_str());
822  }
823  else if(dataType == "char")
824  fprintf(
825  fp, "%d\n", *((char*)(&(*alarmValueArray[i - 1])[0])));
826  else if(dataType == "unsigned char")
827  fprintf(fp,
828  "%u\n",
829  *((unsigned char*)(&(*alarmValueArray[i - 1])[0])));
830  else if(dataType == "short")
831  fprintf(
832  fp, "%d\n", *((short*)(&(*alarmValueArray[i - 1])[0])));
833  else if(dataType == "unsigned short")
834  fprintf(fp,
835  "%u\n",
836  *((unsigned short*)(&(*alarmValueArray[i - 1])[0])));
837  else if(dataType == "int")
838  fprintf(fp, "%d\n", *((int*)(&(*alarmValueArray[i - 1])[0])));
839  else if(dataType == "unsigned int")
840  fprintf(fp,
841  "%u\n",
842  *((unsigned int*)(&(*alarmValueArray[i - 1])[0])));
843  else if(dataType == "long long")
844  fprintf(fp,
845  "%lld\n",
846  *((long long*)(&(*alarmValueArray[i - 1])[0])));
847  else if(dataType == "unsigned long long")
848  fprintf(
849  fp,
850  "%llu\n",
851  *((unsigned long long*)(&(*alarmValueArray[i - 1])[0])));
852  else if(dataType == "float")
853  fprintf(
854  fp, "%f\n", *((float*)(&(*alarmValueArray[i - 1])[0])));
855  else if(dataType == "double")
856  fprintf(
857  fp, "%f\n", *((double*)(&(*alarmValueArray[i - 1])[0])));
858  }
859  }
860  }
861 
862  fclose(fp);
863  }
864 }
865 
866 //==============================================================================
870 void FESlowControlsChannel::extractSample()
871 {
872  const std::string& universalReadValue = universalReadValue_; //do not modify
873 
874  { // print
875  __GEN_SS__ << "Universal Read: ";
876  for(unsigned int i = 0; i < universalReadValue.size(); ++i)
877  ss << std::hex << (int)((universalReadValue[i] >> 4) & 0xF)
878  << (int)((universalReadValue[i]) & 0xF) << " " << std::dec;
879  ss << __E__;
880  __GEN_COUT__ << "\n" << ss.str();
881  __GEN_COUT__ << "Universal Read: "
882  << BinaryStringMacros::binaryNumberToHexString(
883  universalReadValue, "0x", " ")
884  << " at t=" << time(0) << __E__;
885  }
886 
887  sample_.resize(0); // clear a la sample_ = "";
889  universalReadValue, sample_, sizeOfDataTypeBits_, universalDataBitOffset_);
890 
891  __GEN_COUT__ << "Sample: "
892  << BinaryStringMacros::binaryNumberToHexString(sample_, "0x", " ")
893  << ", from address: "
894  << BinaryStringMacros::binaryNumberToHexString(
895  universalAddress_, "0x", " ")
896  << ", sample size in bytes: " << sample_.size()
897  << ", in bits: " << sizeOfDataTypeBits_
898  << ", at bit-offset: " << universalDataBitOffset_ << __E__;
899 
900 } // end extractSample()
901 
902 //==============================================================================
907 {
908  if(targetAlarm == -1 || targetAlarm == 0)
909  loloAlarmed_ = false;
910  if(targetAlarm == -1 || targetAlarm == 1)
911  loAlarmed_ = false;
912  if(targetAlarm == -1 || targetAlarm == 2)
913  hiAlarmed_ = false;
914  if(targetAlarm == -1 || targetAlarm == 3)
915  hihiAlarmed_ = false;
916 } // end clearAlarms()
917 
918 //==============================================================================
923 char FESlowControlsChannel::checkAlarms(std::string& txBuffer)
924 {
925  // procedure:
926  // for each alarm type
927  // determine type and get value as proper type
928  // i.e.:
929  // 0 -- unsigned long long
930  // 1 -- long long
931  // 2 -- float
932  // 3 -- double
933  // do comparison with the type
934  // alarm alarms
935 
936  int useType = -1;
937  char createPacketMask = 0;
938 
939  if(dataType[dataType.size() - 1] == 'b') // if ends in 'b' then take that many bits
940  useType = 0;
941  else if(dataType == "char")
942  useType = 1;
943  else if(dataType == "unsigned char")
944  useType = 0;
945  else if(dataType == "short")
946  useType = 1;
947  else if(dataType == "unsigned short")
948  useType = 0;
949  else if(dataType == "int")
950  useType = 1;
951  else if(dataType == "unsigned int")
952  useType = 0;
953  else if(dataType == "long long")
954  useType = 1;
955  else if(dataType == "unsigned long long")
956  useType = 0;
957  else if(dataType == "float")
958  useType = 2;
959  else if(dataType == "double")
960  useType = 3;
961 
962  if(useType == 0) // unsigned long long
963  {
964  __GEN_COUT__ << "Using unsigned long long for alarms." << __E__;
965  // lolo
966  if((!loloAlarmed_ || !latchAlarms_) &&
967  *((unsigned long long*)&sample_[0]) <= *((unsigned long long*)&lolo_[0]))
968  {
969  loloAlarmed_ = true;
970  createPacketMask |= 1 << 0;
971  }
972  // lo
973  if((!loAlarmed_ || !latchAlarms_) &&
974  *((unsigned long long*)&sample_[0]) <= *((unsigned long long*)&lo_[0]))
975  {
976  loAlarmed_ = true;
977  createPacketMask |= 1 << 1;
978  }
979  // hi
980  if((!hiAlarmed_ || !latchAlarms_) &&
981  *((unsigned long long*)&sample_[0]) >= *((unsigned long long*)&hi_[0]))
982  {
983  hiAlarmed_ = true;
984  createPacketMask |= 1 << 2;
985  }
986  // hihi
987  if((!hihiAlarmed_ || !latchAlarms_) &&
988  *((unsigned long long*)&sample_[0]) >= *((unsigned long long*)&hihi_[0]))
989  {
990  hihiAlarmed_ = true;
991  createPacketMask |= 1 << 3;
992  }
993  }
994  else if(useType == 1) // long long
995  {
996  __GEN_COUT__ << "Using long long for alarms." << __E__;
997  // lolo
998  if((!loloAlarmed_ || !latchAlarms_) &&
999  *((long long*)&sample_[0]) <= *((long long*)&lolo_[0]))
1000  {
1001  loloAlarmed_ = true;
1002  createPacketMask |= 1 << 0;
1003  }
1004  // lo
1005  if((!loAlarmed_ || !latchAlarms_) &&
1006  *((long long*)&sample_[0]) <= *((long long*)&lo_[0]))
1007  {
1008  loAlarmed_ = true;
1009  createPacketMask |= 1 << 1;
1010  }
1011  // hi
1012  if((!hiAlarmed_ || !latchAlarms_) &&
1013  *((long long*)&sample_[0]) >= *((long long*)&hi_[0]))
1014  {
1015  hiAlarmed_ = true;
1016  createPacketMask |= 1 << 2;
1017  }
1018  // hihi
1019  if((!hihiAlarmed_ || !latchAlarms_) &&
1020  *((long long*)&sample_[0]) >= *((long long*)&hihi_[0]))
1021  {
1022  hihiAlarmed_ = true;
1023  createPacketMask |= 1 << 3;
1024  }
1025  }
1026  else if(useType == 2) // float
1027  {
1028  __GEN_COUT__ << "Using float for alarms." << __E__;
1029  // lolo
1030  if((!loloAlarmed_ || !latchAlarms_) &&
1031  *((float*)&sample_[0]) <= *((float*)&lolo_[0]))
1032  {
1033  loloAlarmed_ = true;
1034  createPacketMask |= 1 << 0;
1035  }
1036  // lo
1037  if((!loAlarmed_ || !latchAlarms_) && *((float*)&sample_[0]) <= *((float*)&lo_[0]))
1038  {
1039  loAlarmed_ = true;
1040  createPacketMask |= 1 << 1;
1041  }
1042  // hi
1043  if((!hiAlarmed_ || !latchAlarms_) && *((float*)&sample_[0]) >= *((float*)&hi_[0]))
1044  {
1045  hiAlarmed_ = true;
1046  createPacketMask |= 1 << 2;
1047  }
1048  // hihi
1049  if((!hihiAlarmed_ || !latchAlarms_) &&
1050  *((float*)&sample_[0]) >= *((float*)&hihi_[0]))
1051  {
1052  hihiAlarmed_ = true;
1053  createPacketMask |= 1 << 3;
1054  }
1055  }
1056  else if(useType == 3) // double
1057  {
1058  __GEN_COUT__ << "Using double for alarms." << __E__;
1059  // lolo
1060  if((!loloAlarmed_ || !latchAlarms_) &&
1061  *((double*)&sample_[0]) <= *((double*)&lolo_[0]))
1062  {
1063  loloAlarmed_ = true;
1064  createPacketMask |= 1 << 0;
1065  }
1066  // lo
1067  if((!loAlarmed_ || !latchAlarms_) &&
1068  *((double*)&sample_[0]) <= *((double*)&lo_[0]))
1069  {
1070  loAlarmed_ = true;
1071  createPacketMask |= 1 << 1;
1072  }
1073  // hi
1074  if((!hiAlarmed_ || !latchAlarms_) &&
1075  *((double*)&sample_[0]) >= *((double*)&hi_[0]))
1076  {
1077  hiAlarmed_ = true;
1078  createPacketMask |= 1 << 2;
1079  }
1080  // hihi
1081  if((!hihiAlarmed_ || !latchAlarms_) &&
1082  *((double*)&sample_[0]) >= *((double*)&hihi_[0]))
1083  {
1084  hihiAlarmed_ = true;
1085  createPacketMask |= 1 << 3;
1086  }
1087  }
1088 
1089  // create array helper for packet gen
1090  std::string* alarmValueArray[] = {&lolo_, &lo_, &hi_, &hihi_};
1091 
1092  if(monitoringEnabled) // only create packet if monitoring
1093  {
1094  // create a packet for each bit in mask
1095  char checkMask = 1; // use mask to maintain return mask
1096  for(int i = 0; i < 4; ++i, checkMask <<= 1)
1097  if(createPacketMask & checkMask)
1098  {
1099  // create alarm packet:
1100  // 1B type (0: value, 1: loloalarm, 2: loalarm, 3: hioalarm, 4:
1101  // hihialarm)
1102  // 1B sequence count from channel
1103  // 8B time
1104  // 4B sz of name
1105  // name
1106  // 1B sz of alarm value in bytes
1107  // 1B sz of alarm value in bits
1108  // alarm value
1109 
1110  __GEN_COUT__ << "Create packet type " << i + 1
1111  << " alarm value = " << *alarmValueArray[i] << __E__;
1112 
1113  __GEN_COUT__ << "before txBuffer sz=" << txBuffer.size() << __E__;
1114  txBuffer.push_back(i + 1); // alarm packet type
1115  txBuffer.push_back(
1116  txPacketSequenceNumber_++); // sequence counter and increment
1117 
1118  txBuffer.resize(txBuffer.size() + sizeof(lastSampleTime_));
1119  memcpy(&txBuffer[txBuffer.size() - sizeof(lastSampleTime_)] /*dest*/,
1120  &lastSampleTime_ /*src*/,
1121  sizeof(lastSampleTime_));
1122 
1123  unsigned int tmpSz = fullChannelName.size();
1124 
1125  txBuffer.resize(txBuffer.size() + sizeof(tmpSz));
1126  memcpy(&txBuffer[txBuffer.size() - sizeof(tmpSz)] /*dest*/,
1127  &tmpSz /*src*/,
1128  sizeof(tmpSz));
1129 
1130  txBuffer += fullChannelName;
1131 
1132  txBuffer.push_back(
1133  (unsigned char)(*alarmValueArray[i]).size()); // size in bytes
1134  txBuffer.push_back((unsigned char)sizeOfDataTypeBits_); // size in bits
1135 
1136  txBuffer += (*alarmValueArray[i]);
1137  __GEN_COUT__ << "after txBuffer sz=" << txBuffer.size() << __E__;
1138 
1139  { // print
1140  __GEN_SS__ << "txBuffer: \n";
1141  for(unsigned int i = 0; i < txBuffer.size(); ++i)
1142  {
1143  ss << std::hex << (int)((txBuffer[i] >> 4) & 0xF)
1144  << (int)((txBuffer[i]) & 0xF) << " " << std::dec;
1145  if(i % 8 == 7)
1146  ss << __E__;
1147  }
1148  ss << __E__;
1149  __GEN_COUT__ << "\n" << ss.str();
1150  }
1151  }
1152  }
1153 
1154  return createPacketMask;
1155 } // end checkAlarms()
void handleSample(const std::string &universalReadValue, std::string &txBuffer, FILE *fpAggregate=0, bool aggregateIsBinaryFormat=false, bool txBufferUsed=true)
FESlowControlsChannel(FEVInterface *interface, const std::string &channelName, const std::string &dataType, const std::string &universalAddress, const std::string &transformation, unsigned int universalDataBitOffset, bool readAccess, bool writeAccess, bool monitoringEnabled, bool recordChangesOnly, time_t delayBetweenSamples, bool saveEnabled, const std::string &savePath, const std::string &saveFileRadix, bool saveBinaryFormat, bool alarmsEnabled, bool latchAlarms, const std::string &lolo, const std::string &lo, const std::string &hi, const std::string &hihi)
static std::string underscoreString(const std::string &str)
void clearAlarms(int targetAlarm=-1)
default to all
bool universalBlockReadImplementationConfirmed
is confirmed by slow controls handling (for example) that universalBlockRead is implemented by the FE...
Definition: FEVInterface.h:79
virtual void universalRead(char *address, char *returnValue)=0
throw std::runtime_error exception on error/timeout
static void extractValueFromBinaryString(const std::string &binaryBuffer, T &value, unsigned int bitIndex=0)
static std::string demangleTypeName(const char *name)
static bool getNumber(const std::string &s, T &retValue)