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