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