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 );
31 if ( datasocket_ < 0 )
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_, (
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 )
60 if ( should_stop() ) {
return false; }
62 demo::UDPFragment::Metadata metadata;
63 metadata.port = dataport_;
64 metadata.address = si_data_.sin_addr.s_addr;
84 std::size_t initial_payload_size = 0;
86 frags.emplace_back( artdaq::Fragment::FragmentBytes( initial_payload_size, ev_counter(), fragment_id(),
87 artdaq::Fragment::FirstUserFragmentType, metadata ) );
89 demo::UDPFragmentWriter thisFrag( *frags.back() );
91 bool haveData =
false;
92 int16_t burst_end = -1;
93 uint8_t droppedPackets = 0;
96 if ( should_stop() ) {
return false; }
97 struct pollfd ufds[ 1 ];
98 ufds[ 0 ].fd = datasocket_;
99 ufds[ 0 ].events = POLLIN | POLLPRI;
101 int rv = poll( ufds, 1, 1000 );
105 if ( ufds[ 0 ].revents == POLLIN || ufds[ 0 ].revents == POLLPRI )
107 uint8_t peekBuffer[ 2 ];
108 recvfrom( datasocket_, peekBuffer,
sizeof( peekBuffer ), MSG_PEEK, (
struct sockaddr *)&si_data_,
109 (socklen_t *)
sizeof( si_data_ ) );
111 TLOG( TLVL_INFO ) <<
"Recieved UDP Packet with sequence number " << std::hex << (int)peekBuffer[ 1 ]
116 uint8_t seqNum = peekBuffer[ 1 ];
117 ReturnCode dataCode = getReturnCode( peekBuffer[ 0 ] );
118 if ( seqNum >= expectedPacketNumber_ || ( seqNum < 10 && expectedPacketNumber_ > 200 ) ||
119 droppedPackets > 0 || expectedPacketNumber_ - seqNum > 20 )
121 if ( seqNum != expectedPacketNumber_ &&
122 ( seqNum >= expectedPacketNumber_ || ( seqNum < 10 && expectedPacketNumber_ > 200 ) ) )
124 int deltaHi = seqNum - expectedPacketNumber_;
125 int deltaLo = 255 + seqNum - expectedPacketNumber_;
126 droppedPackets += deltaLo < 255 ? deltaLo : deltaHi;
127 TLOG( TLVL_WARNING ) <<
"Dropped/Delayed packets detected: " << droppedPackets << std::endl;
128 expectedPacketNumber_ = seqNum;
130 else if ( seqNum != expectedPacketNumber_ )
132 int delta = expectedPacketNumber_ - seqNum;
134 <<
"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_,
143 (socklen_t *)
sizeof( si_data_ ) );
144 packetBuffers_.push_back( buffer );
145 TLOG( TLVL_DEBUG ) <<
"Now placing UDP packet with sequence number " << std::hex << (int)seqNum
147 if ( dataCode == ReturnCode::Read ) { haveData =
true; }
154 else if ( ( dataCode == ReturnCode::Middle || dataCode == ReturnCode::Last ) &&
155 packetBuffers_.size() > 0 )
159 recvfrom( datasocket_, &buffer[ 0 ],
sizeof(
packetBuffer_t ), 0, (
struct sockaddr *)&si_data_,
160 (socklen_t *)
sizeof( si_data_ ) );
161 if ( droppedPackets == 0 ) { packetBuffers_.push_back( buffer ); }
162 else if ( burst_end == -1 || seqNum < burst_end )
165 for ( packetBuffer_list_t::iterator it = packetBuffers_.begin(); it != packetBuffers_.end();
168 if ( seqNum < ( *it )[ 1 ] )
170 packetBuffers_.insert( it, buffer );
172 expectedPacketNumber_--;
175 if ( !found ) { packetBuffers_.push_back( buffer ); }
177 TLOG( TLVL_DEBUG ) <<
"Now placing UDP packet with sequence number " << std::hex << (int)seqNum
179 if ( dataCode == ReturnCode::Last && droppedPackets == 0 )
181 while ( getReturnCode( packetBuffers_.back()[ 0 ] ) != ReturnCode::Last )
182 { packetBuffers_.pop_back(); }
185 else if ( dataCode == ReturnCode::Last )
189 else if ( burst_end >= 0 && droppedPackets == 0 )
191 while ( getReturnCode( packetBuffers_.back()[ 0 ] ) != ReturnCode::Last )
192 { packetBuffers_.pop_back(); }
197 ++expectedPacketNumber_;
202 recvfrom( datasocket_, &discardBuffer[ 0 ],
sizeof( discardBuffer ), 0,
203 (
struct sockaddr *)&si_data_, (socklen_t *)
sizeof( si_data_ ) );
204 TLOG( TLVL_WARNING ) <<
"Out-of-sequence packet detected and discarded!";
211 TLOG( TLVL_DEBUG ) <<
"Recieved data, now placing data with UDP sequence number " << (int)firstPacket[ 1 ]
212 <<
" into UDPFragment";
213 thisFrag.resize( 1500 * packetBuffers_.size() + 1 );
214 std::ofstream output;
217 std::string outputPath = rawPath_ +
"/UDPReceiver-" + ip_ +
":" + std::to_string( dataport_ ) +
".bin";
218 output.open( outputPath, std::ios::out | std::ios::app | std::ios::binary );
221 DataType dataType = getDataType( firstPacket[ 0 ] );
222 thisFrag.set_hdr_type( (
int)dataType );
224 for (
auto jj : packetBuffers_ )
226 for (
int ii = 2; ii < 1500; ++ii )
229 if ( jj[ ii ] == 0 && ( dataType == DataType::JSON || dataType == DataType::String ) ) {
break; }
231 if ( rawOutput_ ) output.write( (
char *)&( jj[ ii ] ),
sizeof( uint8_t ) );
232 *( thisFrag.dataBegin() + pos ) = jj[ ii ];
236 if ( dataType == DataType::JSON || dataType == DataType::String )
238 *( thisFrag.dataBegin() + pos ) = 0;
240 if ( rawOutput_ ) output.write( &zero,
sizeof(
char ) );
242 if ( rawOutput_ ) output.close();
247 void demo::UDPReceiver::start() { send( CommandType::Start_Burst ); }
249 void demo::UDPReceiver::stop() { send( CommandType::Stop_Burst ); }
251 void demo::UDPReceiver::pause() { send( CommandType::Stop_Burst ); }
253 void demo::UDPReceiver::resume() { send( CommandType::Start_Burst ); }
255 void demo::UDPReceiver::send(
CommandType command )
259 CommandPacket packet;
260 packet.type = command;
262 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.