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