artdaq_demo  v3_02_00
UDPReceiver_generator.cc
1 #include "artdaq-demo/Generators/UDPReceiver.hh"
2 
3 #include "canvas/Utilities/Exception.h"
4 
5 #include "artdaq/Application/GeneratorMacros.hh"
6 #include "cetlib_except/exception.h"
7 #include "fhiclcpp/ParameterSet.h"
8 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
9 #include "messagefacility/MessageLogger/MessageLogger.h"
10 #include "artdaq-core-demo/Overlays/UDPFragmentWriter.hh"
11 
12 #include <fstream>
13 #include <iomanip>
14 #include <iterator>
15 #include <iostream>
16 #include <sys/poll.h>
17 
18 demo::UDPReceiver::UDPReceiver(fhicl::ParameterSet const& ps)
19  : CommandableFragmentGenerator(ps)
20  , dataport_(ps.get<int>("port", 6343))
21  , ip_(ps.get<std::string>("ip", "127.0.0.1"))
22  , expectedPacketNumber_(0)
23  , sendCommands_(ps.get<bool>("send_CAPTAN_commands", false))
24  , rawOutput_(ps.get<bool>("raw_output_enabled", false))
25  , rawPath_(ps.get<std::string>("raw_output_path", "/tmp"))
26 {
27  datasocket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
28  if (datasocket_ < 0)
29  {
30  throw art::Exception(art::errors::Configuration) << "UDPReceiver: Error creating socket!" << std::endl;
31  exit(1);
32  }
33 
34  struct sockaddr_in si_me_data;
35  si_me_data.sin_family = AF_INET;
36  si_me_data.sin_port = htons(dataport_);
37  si_me_data.sin_addr.s_addr = htonl(INADDR_ANY);
38  if (bind(datasocket_, (struct sockaddr *)&si_me_data, sizeof(si_me_data)) == -1)
39  {
40  throw art::Exception(art::errors::Configuration) <<
41  "UDPReceiver: Cannot bind data socket to port " << dataport_ << std::endl;
42  exit(1);
43  }
44 
45  si_data_.sin_family = AF_INET;
46  si_data_.sin_port = htons(dataport_);
47  if (inet_aton(ip_.c_str(), &si_data_.sin_addr) == 0)
48  {
49  throw art::Exception(art::errors::Configuration) <<
50  "UDPReceiver: Could not translate provided IP Address: " << ip_ << "\n";
51  exit(1);
52  }
53 }
54 
55 
56 bool demo::UDPReceiver::getNext_(artdaq::FragmentPtrs& frags)
57 {
58  if (should_stop())
59  {
60  return false;
61  }
62 
63  demo::UDPFragment::Metadata metadata;
64  metadata.port = dataport_;
65  metadata.address = si_data_.sin_addr.s_addr;
66 
67  // And use it, along with the artdaq::Fragment header information
68  // (fragment id, sequence id, and user type) to create a fragment
69 
70  // We'll use the static factory function
71 
72  // artdaq::Fragment::FragmentBytes(std::size_t payload_size_in_bytes, sequence_id_t sequence_id,
73  // fragment_id_t fragment_id, type_t type, const T & metadata)
74 
75  // which will then return a unique_ptr to an artdaq::Fragment
76  // object. The advantage of this approach over using the
77  // artdaq::Fragment constructor is that, if we were to want to
78  // initialize the artdaq::Fragment with a nonzero-size payload (data
79  // after the artdaq::Fragment header and metadata), we could provide
80  // the size of the payload in bytes, rather than in units of the
81  // artdaq::Fragment's RawDataType (8 bytes, as of 3/26/14). The
82  // artdaq::Fragment constructor itself was not altered so as to
83  // maintain backward compatibility.
84 
85  std::size_t initial_payload_size = 0;
86 
87  frags.emplace_back(artdaq::Fragment::FragmentBytes(initial_payload_size,
88  ev_counter(), fragment_id(),
89  artdaq::Fragment::FirstUserFragmentType, metadata));
90  // We now have a fragment to contain this event:
91  demo::UDPFragmentWriter thisFrag(*frags.back());
92 
93  bool haveData = false;
94  int16_t burst_end = -1;
95  uint8_t droppedPackets = 0;
96  while (!haveData)
97  {
98  if (should_stop())
99  {
100  return false;
101  }
102  struct pollfd ufds[1];
103  ufds[0].fd = datasocket_;
104  ufds[0].events = POLLIN | POLLPRI;
105 
106  int rv = poll(ufds, 1, 1000);
107  if (rv > 0)
108  {
109  //std::cout << "revents: " << ufds[0].revents << ", " << ufds[1].revents << std::endl;
110  if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
111  {
112  uint8_t peekBuffer[2];
113  recvfrom(datasocket_, peekBuffer, sizeof(peekBuffer), MSG_PEEK,
114  (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_));
115 
116  mf::LogInfo("UDPReceiver") << "Recieved UDP Packet with sequence number " << std::hex << (int)peekBuffer[1] << "!";
117  //std::cout << "peekBuffer[1] == expectedPacketNumber_: " << std::hex << (int)peekBuffer[1] << " =?= " << (int)expectedPacketNumber_ << std::endl;
118 
119  uint8_t seqNum = peekBuffer[1];
120  ReturnCode dataCode = getReturnCode(peekBuffer[0]);
121  if (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200) || droppedPackets > 0 || expectedPacketNumber_ - seqNum > 20)
122  {
123  if (seqNum != expectedPacketNumber_ && (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200)))
124  {
125  int deltaHi = seqNum - expectedPacketNumber_;
126  int deltaLo = 255 + seqNum - expectedPacketNumber_;
127  droppedPackets += deltaLo < 255 ? deltaLo : deltaHi;
128  mf::LogWarning("UDPReceiver") << "Dropped/Delayed packets detected: " << std::to_string(droppedPackets) << std::endl;
129  expectedPacketNumber_ = seqNum;
130  }
131  else if (seqNum != expectedPacketNumber_)
132  {
133  int delta = expectedPacketNumber_ - seqNum;
134  mf::LogWarning("UDPReceiver") << "Sequence Number significantly different than expected! (delta: " << delta << ")";
135  }
136 
137  if (dataCode == ReturnCode::Read || dataCode == ReturnCode::First)
138  {
139  packetBuffers_.clear();
140  packetBuffer_t buffer;
141  memset(&buffer[0], 0, sizeof(packetBuffer_t));
142  recvfrom(datasocket_, &buffer[0], sizeof(packetBuffer_t), 0, (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_));
143  packetBuffers_.push_back(buffer);
144  mf::LogDebug("UDPReceiver") << "Now placing UDP packet with sequence number " << std::hex << (int)seqNum << " into buffer.";
145  if (dataCode == ReturnCode::Read) { haveData = true; }
146  else
147  {
148  droppedPackets = 0;
149  burst_end = -1;
150  }
151  }
152  else if ((dataCode == ReturnCode::Middle || dataCode == ReturnCode::Last) && packetBuffers_.size() > 0)
153  {
154  packetBuffer_t buffer;
155  memset(&buffer[0], 0, sizeof(packetBuffer_t));
156  recvfrom(datasocket_, &buffer[0], sizeof(packetBuffer_t), 0, (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_));
157  if (droppedPackets == 0)
158  {
159  packetBuffers_.push_back(buffer);
160  }
161  else if (burst_end == -1 || seqNum < burst_end)
162  {
163  bool found = false;
164  for (packetBuffer_list_t::iterator it = packetBuffers_.begin(); it != packetBuffers_.end(); ++it)
165  {
166  if (seqNum < (*it)[1])
167  {
168  packetBuffers_.insert(it, buffer);
169  droppedPackets--;
170  expectedPacketNumber_--;
171  }
172  }
173  if (!found)
174  {
175  packetBuffers_.push_back(buffer);
176  }
177  }
178  mf::LogDebug("UDPReceiver") << "Now placing UDP packet with sequence number " << std::hex << (int)seqNum << " into buffer.";
179  if (dataCode == ReturnCode::Last && droppedPackets == 0)
180  {
181  while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last) { packetBuffers_.pop_back(); }
182  haveData = true;
183  }
184  else if (dataCode == ReturnCode::Last) { burst_end = seqNum; }
185  else if (burst_end >= 0 && droppedPackets == 0)
186  {
187  while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last) { packetBuffers_.pop_back(); }
188  haveData = true;
189  }
190  }
191 
192  ++expectedPacketNumber_;
193  }
194  else
195  {
196  packetBuffer_t discardBuffer;
197  recvfrom(datasocket_, &discardBuffer[0], sizeof(discardBuffer), 0, (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_));
198  mf::LogWarning("UDPReceiver") << "Out-of-sequence packet detected and discarded!";
199  }
200  }
201  }
202  }
203 
204  packetBuffer_t& firstPacket = packetBuffers_.front();
205  mf::LogDebug("UDPReceiver") << "Recieved data, now placing data with UDP sequence number " << (int)firstPacket[1] << " into UDPFragment";
206  thisFrag.resize(1500 * packetBuffers_.size() + 1);
207  std::ofstream output;
208  if (rawOutput_)
209  {
210  std::string outputPath = rawPath_ + "/UDPReceiver-" + ip_ + ":" + std::to_string(dataport_) + ".bin";
211  output.open(outputPath, std::ios::out | std::ios::app | std::ios::binary);
212  }
213 
214  DataType dataType = getDataType(firstPacket[0]);
215  thisFrag.set_hdr_type((int)dataType);
216  int pos = 0;
217  for (auto jj : packetBuffers_)
218  {
219  for (int ii = 2; ii < 1500; ++ii)
220  {
221  // Null-terminate string types
222  if (jj[ii] == 0 && (dataType == DataType::JSON || dataType == DataType::String)) { break; }
223 
224  if (rawOutput_) output.write((char*)&(jj[ii]), sizeof(uint8_t));
225  *(thisFrag.dataBegin() + pos) = jj[ii];
226  ++pos;
227  }
228  }
229  if (dataType == DataType::JSON || dataType == DataType::String)
230  {
231  *(thisFrag.dataBegin() + pos) = 0;
232  char zero = 0;
233  if (rawOutput_) output.write(&zero, sizeof(char));
234  }
235  if (rawOutput_) output.close();
236 
237  return true;
238 }
239 
240 void demo::UDPReceiver::start()
241 {
242  send(CommandType::Start_Burst);
243 }
244 
245 void demo::UDPReceiver::stop()
246 {
247  send(CommandType::Stop_Burst);
248 }
249 
250 void demo::UDPReceiver::pause()
251 {
252  send(CommandType::Stop_Burst);
253 }
254 
255 void demo::UDPReceiver::resume()
256 {
257  send(CommandType::Start_Burst);
258 }
259 
260 void demo::UDPReceiver::send(CommandType command)
261 {
262  if (sendCommands_)
263  {
264  CommandPacket packet;
265  packet.type = command;
266  packet.dataSize = 0;
267  sendto(datasocket_, &packet, sizeof(packet), 0, (struct sockaddr *) &si_data_, sizeof(si_data_));
268  }
269 }
270 
271 // The following macro is defined in artdaq's GeneratorMacros.hh header
272 DEFINE_ARTDAQ_COMMANDABLE_GENERATOR(demo::UDPReceiver)
ReturnCode
Enumeration describing status codes that indicate current sender position in the stream.
Definition: UDPReceiver.hh:47
An artdaq::CommandableFragmentGenerator which receives data in the form of UDP datagrams.
Definition: UDPReceiver.hh:82
CommandType
Enumeration describing valid command types.
Definition: UDPReceiver.hh:36
DataType
Enumeration describing potential data types.
Definition: UDPReceiver.hh:58
std::array< uint8_t, 1500 > packetBuffer_t
An array of 1500 bytes (MTU length)
Definition: UDPReceiver.hh:76
UDPReceiver(fhicl::ParameterSet const &ps)
UDPReceiver Constructor.