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