1 #define TRACE_NAME "UDPReceiver"
2 #include "artdaq/DAQdata/Globals.hh"
4 #include "artdaq-demo/Generators/UDPReceiver.hh"
6 #include "canvas/Utilities/Exception.h"
8 #include "artdaq-core-demo/Overlays/UDPFragmentWriter.hh"
9 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
10 #include "artdaq/Generators/GeneratorMacros.hh"
11 #include "cetlib_except/exception.h"
12 #include "fhiclcpp/ParameterSet.h"
13 #include "messagefacility/MessageLogger/MessageLogger.h"
22 : CommandableFragmentGenerator(ps)
23 , dataport_(ps.get<int>(
"port", 6343))
24 , ip_(ps.get<std::string>(
"ip",
"127.0.0.1"))
25 , expectedPacketNumber_(0)
26 , sendCommands_(ps.get<bool>(
"send_CAPTAN_commands", false))
27 , rawOutput_(ps.get<bool>(
"raw_output_enabled", false))
28 , rawPath_(ps.get<std::string>(
"raw_output_path",
"/tmp"))
30 datasocket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
33 throw art::Exception(art::errors::Configuration) <<
"UDPReceiver: Error creating socket!" << std::endl;
37 struct sockaddr_in si_me_data;
38 si_me_data.sin_family = AF_INET;
39 si_me_data.sin_port = htons(dataport_);
40 si_me_data.sin_addr.s_addr = htonl(INADDR_ANY);
41 if (bind(datasocket_, reinterpret_cast<struct sockaddr *>(&si_me_data),
sizeof(si_me_data)) == -1)
43 throw art::Exception(art::errors::Configuration)
44 <<
"UDPReceiver: Cannot bind data socket to port " << dataport_ << std::endl;
48 si_data_.sin_family = AF_INET;
49 si_data_.sin_port = htons(dataport_);
50 if (inet_aton(ip_.c_str(), &si_data_.sin_addr) == 0)
52 throw art::Exception(art::errors::Configuration)
53 <<
"UDPReceiver: Could not translate provided IP Address: " << ip_ <<
"\n";
58 bool demo::UDPReceiver::getNext_(artdaq::FragmentPtrs &frags)
65 demo::UDPFragment::Metadata metadata;
66 metadata.port = dataport_;
67 metadata.address = si_data_.sin_addr.s_addr;
87 std::size_t initial_payload_size = 0;
89 frags.emplace_back(artdaq::Fragment::FragmentBytes(initial_payload_size, ev_counter(), fragment_id(),
90 artdaq::Fragment::FirstUserFragmentType, metadata));
92 demo::UDPFragmentWriter thisFrag(*frags.back());
94 bool haveData =
false;
95 int16_t burst_end = -1;
96 uint8_t droppedPackets = 0;
103 struct pollfd ufds[1];
104 ufds[0].fd = datasocket_;
105 ufds[0].events = POLLIN | POLLPRI;
107 int rv = poll(ufds, 1, 1000);
111 if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
113 uint8_t peekBuffer[2];
114 socklen_t addr_len =
sizeof(si_data_);
115 recvfrom(datasocket_, peekBuffer,
sizeof(peekBuffer), MSG_PEEK, reinterpret_cast<struct sockaddr *>(&si_data_),
118 TLOG(TLVL_INFO) <<
"Recieved UDP Packet with sequence number " << std::hex << static_cast<int>(peekBuffer[1])
123 uint8_t seqNum = peekBuffer[1];
124 ReturnCode dataCode = getReturnCode(peekBuffer[0]);
125 if (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200) ||
126 droppedPackets > 0 || expectedPacketNumber_ - seqNum > 20)
128 if (seqNum != expectedPacketNumber_ &&
129 (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200)))
131 int deltaHi = seqNum - expectedPacketNumber_;
132 int deltaLo = 255 + seqNum - expectedPacketNumber_;
133 droppedPackets += deltaLo < 255 ? deltaLo : deltaHi;
134 TLOG(TLVL_WARNING) <<
"Dropped/Delayed packets detected: " << droppedPackets << std::endl;
135 expectedPacketNumber_ = seqNum;
137 else if (seqNum != expectedPacketNumber_)
139 int delta = expectedPacketNumber_ - seqNum;
141 <<
"Sequence Number significantly different than expected! (delta: " << delta <<
")";
144 if (dataCode == ReturnCode::Read || dataCode == ReturnCode::First)
146 packetBuffers_.clear();
149 socklen_t addr_len =
sizeof(si_data_);
150 recvfrom(datasocket_, &buffer[0],
sizeof(
packetBuffer_t), 0, reinterpret_cast<struct sockaddr *>(&si_data_),
152 packetBuffers_.push_back(buffer);
153 TLOG(TLVL_DEBUG) <<
"Now placing UDP packet with sequence number " << std::hex << seqNum
155 if (dataCode == ReturnCode::Read)
165 else if ((dataCode == ReturnCode::Middle || dataCode == ReturnCode::Last) &&
166 !packetBuffers_.empty())
170 socklen_t addr_len =
sizeof(si_data_);
171 recvfrom(datasocket_, &buffer[0],
sizeof(
packetBuffer_t), 0, reinterpret_cast<struct sockaddr *>(&si_data_),
173 if (droppedPackets == 0)
175 packetBuffers_.push_back(buffer);
177 else if (burst_end == -1 || seqNum < burst_end)
180 for (
auto it = packetBuffers_.begin(); it != packetBuffers_.end();
183 if (seqNum < (*it)[1])
185 packetBuffers_.insert(it, buffer);
187 expectedPacketNumber_--;
192 packetBuffers_.push_back(buffer);
195 TLOG(TLVL_DEBUG) <<
"Now placing UDP packet with sequence number " << std::hex << seqNum
197 if (dataCode == ReturnCode::Last && droppedPackets == 0)
199 while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last)
201 packetBuffers_.pop_back();
205 else if (dataCode == ReturnCode::Last)
209 else if (burst_end >= 0 && droppedPackets == 0)
211 while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last)
213 packetBuffers_.pop_back();
219 ++expectedPacketNumber_;
224 socklen_t addr_len =
sizeof(si_data_);
225 recvfrom(datasocket_, &discardBuffer[0],
sizeof(discardBuffer), 0,
226 reinterpret_cast<struct sockaddr *>(&si_data_), &addr_len);
227 TLOG(TLVL_WARNING) <<
"Out-of-sequence packet detected and discarded!";
234 TLOG(TLVL_DEBUG) <<
"Recieved data, now placing data with UDP sequence number " <<
static_cast<int>(firstPacket[1])
235 <<
" into UDPFragment";
236 thisFrag.resize(1500 * packetBuffers_.size() + 1);
237 std::ofstream output;
240 std::string outputPath = rawPath_ +
"/UDPReceiver-" + ip_ +
":" + std::to_string(dataport_) +
".bin";
241 output.open(outputPath, std::ios::out | std::ios::app | std::ios::binary);
244 DataType dataType = getDataType(firstPacket[0]);
245 thisFrag.set_hdr_type(static_cast<demo::UDPFragment::Header::data_type_t>(dataType));
247 for (
auto jj : packetBuffers_)
249 for (
int ii = 2; ii < 1500; ++ii)
252 if (jj.at(ii) == 0 && (dataType == DataType::JSON || dataType == DataType::String))
259 output.write(reinterpret_cast<const char *>(&(jj.at(ii))),
sizeof(uint8_t));
261 *(thisFrag.dataBegin() + pos) = jj.at(ii);
265 if (dataType == DataType::JSON || dataType == DataType::String)
267 *(thisFrag.dataBegin() + pos) = 0;
271 output.write(&zero,
sizeof(
char));
282 void demo::UDPReceiver::start() { send(CommandType::Start_Burst); }
284 void demo::UDPReceiver::stop() { send(CommandType::Stop_Burst); }
286 void demo::UDPReceiver::pause() { send(CommandType::Stop_Burst); }
288 void demo::UDPReceiver::resume() { send(CommandType::Start_Burst); }
294 CommandPacket packet;
295 packet.type = command;
297 sendto(datasocket_, &packet,
sizeof(packet), 0, reinterpret_cast<struct sockaddr *>(&si_data_),
sizeof(si_data_));
ReturnCode
Enumeration describing status codes that indicate current sender position in the stream.
An artdaq::CommandableFragmentGenerator which receives data in the form of UDP datagrams.
CommandType
Enumeration describing valid command types.
DataType
Enumeration describing potential data types.
std::array< uint8_t, 1500 > packetBuffer_t
An array of 1500 bytes (MTU length)
UDPReceiver(fhicl::ParameterSet const &ps)
UDPReceiver Constructor.