1 #include "artdaq-demo/Generators/UDPReceiver.hh"
3 #include "canvas/Utilities/Exception.h"
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"
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"))
27 datasocket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
30 throw art::Exception(art::errors::Configuration) <<
"UDPReceiver: Error creating socket!" << std::endl;
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)
40 throw art::Exception(art::errors::Configuration) <<
41 "UDPReceiver: Cannot bind data socket to port " << dataport_ << std::endl;
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)
49 throw art::Exception(art::errors::Configuration) <<
50 "UDPReceiver: Could not translate provided IP Address: " << ip_ <<
"\n";
56 bool demo::UDPReceiver::getNext_(artdaq::FragmentPtrs& frags)
63 demo::UDPFragment::Metadata metadata;
64 metadata.port = dataport_;
65 metadata.address = si_data_.sin_addr.s_addr;
85 std::size_t initial_payload_size = 0;
87 frags.emplace_back(artdaq::Fragment::FragmentBytes(initial_payload_size,
88 ev_counter(), fragment_id(),
89 artdaq::Fragment::FirstUserFragmentType, metadata));
91 demo::UDPFragmentWriter thisFrag(*frags.back());
93 bool haveData =
false;
94 int16_t burst_end = -1;
95 uint8_t droppedPackets = 0;
102 struct pollfd ufds[1];
103 ufds[0].fd = datasocket_;
104 ufds[0].events = POLLIN | POLLPRI;
106 int rv = poll(ufds, 1, 1000);
110 if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI)
112 uint8_t peekBuffer[2];
113 recvfrom(datasocket_, peekBuffer,
sizeof(peekBuffer), MSG_PEEK,
114 (
struct sockaddr *) &si_data_, (socklen_t*)
sizeof(si_data_));
116 mf::LogInfo(
"UDPReceiver") <<
"Recieved UDP Packet with sequence number " << std::hex << (int)peekBuffer[1] <<
"!";
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)
123 if (seqNum != expectedPacketNumber_ && (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200)))
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;
131 else if (seqNum != expectedPacketNumber_)
133 int delta = expectedPacketNumber_ - seqNum;
134 mf::LogWarning(
"UDPReceiver") <<
"Sequence Number significantly different than expected! (delta: " << delta <<
")";
137 if (dataCode == ReturnCode::Read || dataCode == ReturnCode::First)
139 packetBuffers_.clear();
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; }
152 else if ((dataCode == ReturnCode::Middle || dataCode == ReturnCode::Last) && packetBuffers_.size() > 0)
156 recvfrom(datasocket_, &buffer[0],
sizeof(
packetBuffer_t), 0, (
struct sockaddr *) &si_data_, (socklen_t*)
sizeof(si_data_));
157 if (droppedPackets == 0)
159 packetBuffers_.push_back(buffer);
161 else if (burst_end == -1 || seqNum < burst_end)
164 for (packetBuffer_list_t::iterator it = packetBuffers_.begin(); it != packetBuffers_.end(); ++it)
166 if (seqNum < (*it)[1])
168 packetBuffers_.insert(it, buffer);
170 expectedPacketNumber_--;
175 packetBuffers_.push_back(buffer);
178 mf::LogDebug(
"UDPReceiver") <<
"Now placing UDP packet with sequence number " << std::hex << (int)seqNum <<
" into buffer.";
179 if (dataCode == ReturnCode::Last && droppedPackets == 0)
181 while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last) { packetBuffers_.pop_back(); }
184 else if (dataCode == ReturnCode::Last) { burst_end = seqNum; }
185 else if (burst_end >= 0 && droppedPackets == 0)
187 while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last) { packetBuffers_.pop_back(); }
192 ++expectedPacketNumber_;
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!";
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;
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);
214 DataType dataType = getDataType(firstPacket[0]);
215 thisFrag.set_hdr_type((
int)dataType);
217 for (
auto jj : packetBuffers_)
219 for (
int ii = 2; ii < 1500; ++ii)
222 if (jj[ii] == 0 && (dataType == DataType::JSON || dataType == DataType::String)) {
break; }
224 if (rawOutput_) output.write((
char*)&(jj[ii]),
sizeof(uint8_t));
225 *(thisFrag.dataBegin() + pos) = jj[ii];
229 if (dataType == DataType::JSON || dataType == DataType::String)
231 *(thisFrag.dataBegin() + pos) = 0;
233 if (rawOutput_) output.write(&zero,
sizeof(
char));
235 if (rawOutput_) output.close();
240 void demo::UDPReceiver::start()
242 send(CommandType::Start_Burst);
245 void demo::UDPReceiver::stop()
247 send(CommandType::Stop_Burst);
250 void demo::UDPReceiver::pause()
252 send(CommandType::Stop_Burst);
255 void demo::UDPReceiver::resume()
257 send(CommandType::Start_Burst);
264 CommandPacket packet;
265 packet.type = command;
267 sendto(datasocket_, &packet,
sizeof(packet), 0, (
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.