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