otsdaq_components  v2_03_00
OtsUDPHardware.cc
1 #include "otsdaq-components/DAQHardware/OtsUDPHardware.h"
2 #include <iomanip>
3 #include <iostream>
4 #include "otsdaq-core/Macros/CoutMacros.h"
5 #include "otsdaq-core/MessageFacility/MessageFacility.h"
6 
7 using namespace ots;
8 
9 //========================================================================================================================
10 // This one is often (e.g. FENIMPlusInterface) called by FEs inheriting OtsUDPHardware
11 OtsUDPHardware::OtsUDPHardware(std::string boardIPAddress,
12  unsigned int boardPort,
13  unsigned int version,
14  bool verbose)
15  : // Socket () default constructor
16  FrontEndHardwareBase(version)
17  , OtsUDPBoard_(boardIPAddress, boardPort)
18  , verbose_(verbose)
19 {
20  Socket::initialize();
21 
22  // char msg[100];
23  // sprintf(msg,"_%d",getPort());
24  // std::string fn = "/tmp/new_udp_chk" + std::string(msg) + ".dat";
25  // FILE *fp = fopen(fn.c_str(),"w");
26  // if(fp) fclose(fp);
27  // __COUT__ << fn << std::endl;
28 }
29 
30 //========================================================================================================================
31 OtsUDPHardware::OtsUDPHardware(std::string hostIPAddress,
32  unsigned int hostPort,
33  std::string OtsUDPHardwareIPAddress,
34  unsigned int OtsUDPHardwarePort,
35  unsigned int version,
36  bool verbose)
37  : Socket(hostIPAddress, hostPort)
38  , FrontEndHardwareBase(version)
39  , OtsUDPBoard_(OtsUDPHardwareIPAddress, OtsUDPHardwarePort)
40  , verbose_(verbose)
41 {
42  Socket::initialize();
43 
44  __COUT__ << "Socket for hardware is initialized at IP:Port "
45  << OtsUDPBoard_.getIPAddress() << ":" << OtsUDPBoard_.getPort() << __E__;
46 
47  // char msg[100];
48  // sprintf(msg,"_%d",getPort());
49  // std::string fn = "/tmp/new_udp_chk" + std::string(msg) + ".dat";
50  // FILE *fp = fopen(fn.c_str(),"w");
51  // if(fp) fclose(fp);
52  // __COUT__ << fn << std::endl;
53 }
54 
55 //========================================================================================================================
56 OtsUDPHardware::~OtsUDPHardware(void) {}
57 
58 //========================================================================================================================
59 void OtsUDPHardware::write(const std::string& sendBuffer) throw(std::runtime_error) try
60 {
61  // char msg[100];
62  // sprintf(msg,"_%d",getPort());
63  // std::string fn = "/tmp/new_udp_chk" + std::string(msg) + ".dat";
64  // FILE *fp = fopen(fn.c_str(),"a");
65  // __COUT__ << fn << std::endl;
66 
67  //
68  // if(fp) //debug
69  // {
70  // std::stringstream ss;
71  // ss << "\t";
72  // uint32_t begin = 0;
73  // for(uint32_t i=begin; i<sendBuffer.size(); i++)
74  // {
75  // if(i==begin+2) ss << ":::";
76  // else if(i==begin+10) ss << ":::";
77  // ss << std::setfill('0') << std::setw(2) << std::hex << (((int16_t)
78  // sendBuffer[i]) &0xFF) << "-" << std::dec;
79  // }
80  // ss << std::endl;
81  // fprintf(fp,"%s",ss.str().c_str());
82  // }
83  // if(fp) fclose(fp);
84 
85  if(TransceiverSocket::send(OtsUDPBoard_, sendBuffer, verbose_) < 0)
86  {
87  __SS__ << "Write failed to hardware at IP:Port " << OtsUDPBoard_.getIPAddress()
88  << ":" << OtsUDPBoard_.getPort() << __E__;
89  __SS_THROW__;
90  }
91 }
92 catch(std::runtime_error& e)
93 {
94  throw;
95 }
96 catch(...)
97 {
98  __SS__ << "Unrecognized exception caught!" << std::endl;
99  __SS_THROW__;
100 }
101 
102 //========================================================================================================================
103 void OtsUDPHardware::write(const std::vector<std::string>& sendBuffer) throw(
104  std::runtime_error)
105 {
106  for(const auto& it : sendBuffer)
107  {
108  // char msg[100];
109  // sprintf(msg,"_%d",getPort());
110  // std::string fn = "/tmp/new_udp_chk" + std::string(msg) + ".dat";
111  // FILE *fp = fopen(fn.c_str(),"a");
112  // __COUT__ << fn << std::endl;
113 
114  // if(fp) //debug
115  // {
116  // std::stringstream ss;
117  // ss << "\t";
118  // uint32_t begin = 0;
119  // for(uint32_t i=begin; i<it.size(); i++)
120  // {
121  // if(i==begin+2) ss << ":::";
122  // else if(i==begin+10) ss << ":::";
123  // ss << std::setfill('0') << std::setw(2) << std::hex << (((const
124  // int16_t) it[i]) &0xFF) << "-" << std::dec;
125  // }
126  // ss << std::endl;
127  // fprintf(fp,"%s",ss.str().c_str());
128  // }
129  // if(fp) fclose(fp);
130 
131  write(it);
132  }
133 }
134 
135 //========================================================================================================================
136 void OtsUDPHardware::writeAndAcknowledge(const std::string& buffer,
137  int timeoutSeconds) throw(std::runtime_error) try
138 {
139  // char msg[100];
140  // sprintf(msg,"_%d",getPort());
141  // std::string fn = "/tmp/new_udp_chk" + std::string(msg) + ".dat";
142  // FILE *fp = fopen(fn.c_str(),"a");
143  // __COUT__ << fn << std::endl;
144 
145  // if(fp) //debug
146  // {
147  // std::stringstream ss;
148  // ss << "\tack ";
149  // uint32_t begin = 0;
150  // for(uint32_t i=begin; i<buffer.size(); i++)
151  // {
152  // if(i==begin+2) ss << ":::";
153  // else if(i==begin+10) ss << ":::";
154  // ss << std::setfill('0') << std::setw(2) << std::hex << (((int16_t)
155  // buffer[i]) &0xFF) << "-" << std::dec;
156  // }
157  // ss << std::endl;
158  // fprintf(fp,"%s",ss.str().c_str());
159  // }
160  // if(fp) fclose(fp);
161 
162  // __COUT__ << std::endl;
163  // for(auto& b: buffer)
164  // {
165  // __COUT__ << std::hex << (uint16_t)b << std::dec << std::endl;
166  // }
167  TransceiverSocket::send(OtsUDPBoard_, buffer, verbose_);
168  // acknowledgment_.clear();
169 
170  if(timeoutSeconds < 0) // use default timeout
171  timeoutSeconds = 5;
172 
173  if(TransceiverSocket::receive(acknowledgment_, timeoutSeconds) < 0)
174  {
175  __SS__ << "writeAndAcknowledge failed from hardware at IP:Port "
176  << OtsUDPBoard_.getIPAddress() << ":" << OtsUDPBoard_.getPort()
177  << ". Timeout period of " << timeoutSeconds
178  << " seconds reached without response." << std::endl;
179  __COUT_ERR__ << "\n" << ss.str() << std::endl;
180  __SS_THROW__;
181  }
182 
183  // __COUT__ << "Acknowledgment size: " << acknowledgment_.size() << std::endl;
184  // for(unsigned int i=0; i< acknowledgment_.size(); i++)
185  // {
186  // if(i%24 == 0)
187  // __COUT__ << i << "("<< (unsigned int)acknowledgment_[i] << ")-" << std::endl;
188  // }
189  //
190 
191  // Check First Byte:
192  // (https://docs.google.com/document/d/1i3Z07n8Jq78NwgUFdjAv2sLGhH4rWjHeYEScAWBzSyw/edit?usp=sharing)
193  // bits 2:0 = Packet Type (0: Read, 1: First in Burst, 2: Burst Middle, 3: Last in
194  // Burst, 4: Read Ack, 5: Write Ack, 6: Burst Start Ack, 7: Burst Stop Ack) bit 3
195  // = ack of no address increment op bit 4 = err detected in protocol since reset
196  // bit 5 = rx overflow since reset
197  // bit 6 = crc err flag
198  // bit 7 = crc err detected
199 
200  if((acknowledgment_[0] >> 4))
201  {
202  __SS__ << "Error in OTS protocol encountered! " << std::setfill('0')
203  << std::setw(2) << std::hex << (((int16_t)acknowledgment_[0]) & 0xff)
204  << "-" << std::dec << __E__;
205  __SS_THROW__;
206  }
207 }
208 catch(std::runtime_error& e)
209 {
210  throw;
211 }
212 catch(...)
213 {
214  __SS__ << "Unrecognized exception caught!" << std::endl;
215  __COUT_ERR__ << "\n" << ss.str() << std::endl;
216  __SS_THROW__;
217 }
218 
219 //========================================================================================================================
220 void OtsUDPHardware::writeAndAcknowledge(const std::vector<std::string>& buffer,
221  int timeoutSeconds) throw(std::runtime_error)
222 {
223  for(const auto& it : buffer)
224  {
225  // char msg[100];
226  // sprintf(msg,"_%d",getPort());
227  // std::string fn = "/tmp/new_udp_chk" + std::string(msg) + ".dat";
228  // FILE *fp = fopen(fn.c_str(),"a");
229  // __COUT__ << fn << std::endl;
230 
231  // if(fp) //debug
232  // {
233  // std::stringstream ss;
234  // ss << "\tack ";
235  // uint32_t begin = 0;
236  // for(uint32_t i=begin; i<it.size(); i++)
237  // {
238  // if(i==begin+2) ss << ":::";
239  // else if(i==begin+10) ss << ":::";
240  // ss << std::setfill('0') << std::setw(2) << std::hex << (((const
241  // int16_t) it[i]) &0xFF) << "-" << std::dec;
242  // }
243  // ss << std::endl;
244  // fprintf(fp,"%s",ss.str().c_str());
245  // }
246  // if(fp) fclose(fp);
247 
248  writeAndAcknowledge(it);
249  }
250 }
251 
252 //========================================================================================================================
253 // return -1 on failure
254 void OtsUDPHardware::read(const std::string& sendBuffer,
255  std::string& receiveBuffer,
256  int timeoutSeconds) throw(std::runtime_error) try
257 {
258  { // clear packets so that read matches!
259  int clearedPackets = OtsUDPHardware::clearReadSocket();
260  if(clearedPackets)
261  __COUT__ << "Cleared receive socket buffer: " << clearedPackets
262  << " packets cleared." << std::endl;
263  }
264 
265  __COUT__ << "Sending" << std::endl;
266  TransceiverSocket::send(OtsUDPBoard_, sendBuffer, verbose_);
267 
268  if(timeoutSeconds < 0) // use default timeout
269  timeoutSeconds = 5;
270 
271  __COUT__ << "Receiving" << std::endl;
272  if(TransceiverSocket::receive(
273  receiveBuffer, timeoutSeconds, 0 /*timeoutUSeconds*/, verbose_) < 0)
274  {
275  __SS__ << "Read failed from hardware at IP : Port " << OtsUDPBoard_.getIPAddress()
276  << " : " << OtsUDPBoard_.getPort() << ". Timeout period of "
277  << timeoutSeconds << " seconds reached without response." << __E__;
278  __SS_THROW__;
279  }
280 
281  //__COUT__ << "Received Message: ";
282  // for(uint32_t i=0; i<receiveBuffer.size(); i++)
283  // std::cout << std::setfill('0') << std::setw(2) << std::hex << (((int16_t)
284  // receiveBuffer[i]) &0xff) << "-" << std::dec; std::cout << std::endl;
285 
286  // Check First Byte:
287  // (https://docs.google.com/document/d/1i3Z07n8Jq78NwgUFdjAv2sLGhH4rWjHeYEScAWBzSyw/edit?usp=sharing)
288  // bits 2:0 = Packet Type (0: Read, 1: First in Burst, 2: Burst Middle, 3: Last in
289  // Burst, 4: Read Ack, 5: Write Ack, 6: Burst Start Ack, 7: Burst Stop Ack) bit 3
290  // = ack of no address increment op bit 4 = err detected in protocol since reset
291  // bit 5 = rx overflow since reset
292  // bit 6 = crc err flag
293  // bit 7 = crc err detected
294 
295  if((receiveBuffer[0] >> 5)) // FIXME?? also consider bit 4?
296  {
297  __SS__ << "Error in OTS protocol encountered! " << std::setfill('0')
298  << std::setw(2) << std::hex << (((int16_t)receiveBuffer[0]) & 0xff) << "-"
299  << std::dec << __E__;
300  //__SS_THROW__;
301  }
302 }
303 catch(std::runtime_error& e)
304 {
305  throw;
306 }
307 catch(...)
308 {
309  __SS__ << "Unrecognized exception caught!" << std::endl;
310  __SS_THROW__;
311 }
312 
313 //========================================================================================================================
314 void OtsUDPHardware::read(const std::vector<std::string>& sendBuffers,
315  std::vector<std::string>& receiveBuffers,
316  int timeoutSeconds) throw(std::runtime_error)
317 {
318  receiveBuffers.resize(sendBuffers.size());
319  auto receiveBufferIterator = receiveBuffers.begin();
320  for(const auto& sendBuffer : sendBuffers)
321  read(sendBuffer, *(receiveBufferIterator++));
322 }
323 
324 //========================================================================================================================
325 void OtsUDPHardware::read(const std::string& sendBuffer,
326  uint64_t& receiveQuadWord,
327  int timeoutSeconds) throw(std::runtime_error)
328 {
329  std::string receiveBuffer;
330  read(sendBuffer, receiveBuffer);
331 
332  // force response to be only one quad word
333  if(receiveBuffer.length() != 10)
334  {
335  __SS__ << "Read uint64_t quad-word failed. Invalid size of received buffer: "
336  << receiveBuffer.length() << " != " << 10 << std::endl;
337  __SS_THROW__;
338  }
339  // copy_n does not work!! alert?! it only copies the first byte?
340  // std::copy_n((char *)&receiveBuffer[2],sizeof(uint64_t),&receiveQuadWord);
341  //
342  // __COUT__ << "receiveQuadWord all = 0x" << std::hex <<
343  // receiveQuadWord << std::dec << std::endl;
344 
345  receiveQuadWord = *((uint64_t*)&receiveBuffer[2]);
346  // //memcpy((char *)&receiveBuffer[2],sizeof(uint64_t),&receiveQuadWord);
347  // __COUT__ << "receiveQuadWord all = 0x" << std::hex <<
348  // receiveQuadWord << std::dec << std::endl;
349 }
350 
351 //========================================================================================================================
352 void OtsUDPHardware::read(const std::string& sendBuffer,
353  std::vector<uint64_t>& receiveQuadWords,
354  int timeoutSeconds) throw(std::runtime_error)
355 {
356  receiveQuadWords.resize(0); // clear
357 
358  std::string receiveBuffer;
359  read(sendBuffer, receiveBuffer);
360 
361  // force response to be only integer quad words
362  if((receiveBuffer.length() - 2) % 8 != 0)
363  {
364  __SS__ << "Read vector of uint64_t quad-word failed. Invalid size of received "
365  "buffer: ("
366  << receiveBuffer.length() << " - 2) % 8 != 0" << std::endl;
367  __SS_THROW__;
368  }
369 
370  for(unsigned int i = 2; i < receiveBuffer.length(); i += 8)
371  {
372  receiveQuadWords.push_back(uint64_t());
373 
374  // copy_n does not work!! alert?! it only copies the first byte?
375  // std::copy_n((char
376  // *)&receiveBuffer[i],sizeof(uint64_t),&receiveQuadWords[receiveQuadWords.size()-1]);
377  receiveQuadWords[receiveQuadWords.size() - 1] = *((uint64_t*)&receiveBuffer[i]);
378  }
379 }
380 
381 //========================================================================================================================
382 void OtsUDPHardware::read(const std::vector<std::string>& sendBuffers,
383  std::vector<std::vector<uint64_t> >& receiveQuadWordsVector,
384  int timeoutSeconds) throw(std::runtime_error)
385 {
386  receiveQuadWordsVector.resize(
387  sendBuffers.size()); // create a return vector for each send buffer
388 
389  std::string receiveBuffer;
390 
391  // for each send buffere
392  for(unsigned int b = 0; b < sendBuffers.size(); ++b)
393  {
394  receiveQuadWordsVector[b].resize(0); // clear
395 
396  read(sendBuffers[b], receiveBuffer);
397 
398  // force response to be only integer quad words
399  if((receiveBuffer.length() - 2) % 8 != 0)
400  {
401  __SS__ << "Read vector of uint64_t quad-word failed. Invalid size of "
402  "received buffer: ("
403  << receiveBuffer.length() << " - 2) % 8 != 0" << std::endl;
404  __SS_THROW__;
405  }
406 
407  // copy to uint64_t's
408  for(unsigned int i = 2; i < receiveBuffer.length(); i += 8)
409  {
410  receiveQuadWordsVector[b].push_back(uint64_t());
411  std::copy_n((char*)&receiveBuffer[i],
412  sizeof(uint64_t),
413  &receiveQuadWordsVector[b][receiveQuadWordsVector[b].size() - 1]);
414  }
415  }
416 }
417 
418 //========================================================================================================================
419 // clearReadSocket
420 //
421 // flushes read socket.
422 //
423 // reads from read socket until timeout is reached (remove stale packets)
424 // returns count of packets that were cleared
425 int OtsUDPHardware::clearReadSocket()
426 {
427  std::string dummerReceiveBuffer;
428  int cnt = 0;
429 
430  // receive with no timeout
431  try
432  {
433  while(TransceiverSocket::receive(dummerReceiveBuffer,
434  0 /*timeoutSeconds*/,
435  0 /*timeoutUSeconds*/,
436  false /*verbose*/) >= 0)
437  ++cnt;
438  }
439  catch(...)
440  {
441  // ignore exceptions... assume due to there be nothing to read
442  __COUT__ << "I am crashing while trying to read the socket...strange!"
443  << std::endl;
444  }
445  return cnt;
446 }