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