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