$treeview $search $mathjax $extrastylesheet
artdaq_demo
v3_04_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #define TRACE_NAME "UDPReceiver" 00002 #include "artdaq/DAQdata/Globals.hh" 00003 00004 #include "artdaq-demo/Generators/UDPReceiver.hh" 00005 00006 #include "canvas/Utilities/Exception.h" 00007 00008 #include "artdaq/Application/GeneratorMacros.hh" 00009 #include "cetlib_except/exception.h" 00010 #include "fhiclcpp/ParameterSet.h" 00011 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh" 00012 #include "messagefacility/MessageLogger/MessageLogger.h" 00013 #include "artdaq-core-demo/Overlays/UDPFragmentWriter.hh" 00014 00015 #include <fstream> 00016 #include <iomanip> 00017 #include <iterator> 00018 #include <iostream> 00019 #include <sys/poll.h> 00020 00021 demo::UDPReceiver::UDPReceiver(fhicl::ParameterSet const& ps) 00022 : CommandableFragmentGenerator(ps) 00023 , dataport_(ps.get<int>("port", 6343)) 00024 , ip_(ps.get<std::string>("ip", "127.0.0.1")) 00025 , expectedPacketNumber_(0) 00026 , sendCommands_(ps.get<bool>("send_CAPTAN_commands", false)) 00027 , rawOutput_(ps.get<bool>("raw_output_enabled", false)) 00028 , rawPath_(ps.get<std::string>("raw_output_path", "/tmp")) 00029 { 00030 datasocket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 00031 if (datasocket_ < 0) 00032 { 00033 throw art::Exception(art::errors::Configuration) << "UDPReceiver: Error creating socket!" << std::endl; 00034 exit(1); 00035 } 00036 00037 struct sockaddr_in si_me_data; 00038 si_me_data.sin_family = AF_INET; 00039 si_me_data.sin_port = htons(dataport_); 00040 si_me_data.sin_addr.s_addr = htonl(INADDR_ANY); 00041 if (bind(datasocket_, (struct sockaddr *)&si_me_data, sizeof(si_me_data)) == -1) 00042 { 00043 throw art::Exception(art::errors::Configuration) << 00044 "UDPReceiver: Cannot bind data socket to port " << dataport_ << std::endl; 00045 exit(1); 00046 } 00047 00048 si_data_.sin_family = AF_INET; 00049 si_data_.sin_port = htons(dataport_); 00050 if (inet_aton(ip_.c_str(), &si_data_.sin_addr) == 0) 00051 { 00052 throw art::Exception(art::errors::Configuration) << 00053 "UDPReceiver: Could not translate provided IP Address: " << ip_ << "\n"; 00054 exit(1); 00055 } 00056 } 00057 00058 00059 bool demo::UDPReceiver::getNext_(artdaq::FragmentPtrs& frags) 00060 { 00061 if (should_stop()) 00062 { 00063 return false; 00064 } 00065 00066 demo::UDPFragment::Metadata metadata; 00067 metadata.port = dataport_; 00068 metadata.address = si_data_.sin_addr.s_addr; 00069 00070 // And use it, along with the artdaq::Fragment header information 00071 // (fragment id, sequence id, and user type) to create a fragment 00072 00073 // We'll use the static factory function 00074 00075 // artdaq::Fragment::FragmentBytes(std::size_t payload_size_in_bytes, sequence_id_t sequence_id, 00076 // fragment_id_t fragment_id, type_t type, const T & metadata) 00077 00078 // which will then return a unique_ptr to an artdaq::Fragment 00079 // object. The advantage of this approach over using the 00080 // artdaq::Fragment constructor is that, if we were to want to 00081 // initialize the artdaq::Fragment with a nonzero-size payload (data 00082 // after the artdaq::Fragment header and metadata), we could provide 00083 // the size of the payload in bytes, rather than in units of the 00084 // artdaq::Fragment's RawDataType (8 bytes, as of 3/26/14). The 00085 // artdaq::Fragment constructor itself was not altered so as to 00086 // maintain backward compatibility. 00087 00088 std::size_t initial_payload_size = 0; 00089 00090 frags.emplace_back(artdaq::Fragment::FragmentBytes(initial_payload_size, 00091 ev_counter(), fragment_id(), 00092 artdaq::Fragment::FirstUserFragmentType, metadata)); 00093 // We now have a fragment to contain this event: 00094 demo::UDPFragmentWriter thisFrag(*frags.back()); 00095 00096 bool haveData = false; 00097 int16_t burst_end = -1; 00098 uint8_t droppedPackets = 0; 00099 while (!haveData) 00100 { 00101 if (should_stop()) 00102 { 00103 return false; 00104 } 00105 struct pollfd ufds[1]; 00106 ufds[0].fd = datasocket_; 00107 ufds[0].events = POLLIN | POLLPRI; 00108 00109 int rv = poll(ufds, 1, 1000); 00110 if (rv > 0) 00111 { 00112 //std::cout << "revents: " << ufds[0].revents << ", " << ufds[1].revents << std::endl; 00113 if (ufds[0].revents == POLLIN || ufds[0].revents == POLLPRI) 00114 { 00115 uint8_t peekBuffer[2]; 00116 recvfrom(datasocket_, peekBuffer, sizeof(peekBuffer), MSG_PEEK, 00117 (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_)); 00118 00119 TLOG(TLVL_INFO) << "Recieved UDP Packet with sequence number " << std::hex << (int)peekBuffer[1] << "!"; 00120 //std::cout << "peekBuffer[1] == expectedPacketNumber_: " << std::hex << (int)peekBuffer[1] << " =?= " << (int)expectedPacketNumber_ << std::endl; 00121 00122 uint8_t seqNum = peekBuffer[1]; 00123 ReturnCode dataCode = getReturnCode(peekBuffer[0]); 00124 if (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200) || droppedPackets > 0 || expectedPacketNumber_ - seqNum > 20) 00125 { 00126 if (seqNum != expectedPacketNumber_ && (seqNum >= expectedPacketNumber_ || (seqNum < 10 && expectedPacketNumber_ > 200))) 00127 { 00128 int deltaHi = seqNum - expectedPacketNumber_; 00129 int deltaLo = 255 + seqNum - expectedPacketNumber_; 00130 droppedPackets += deltaLo < 255 ? deltaLo : deltaHi; 00131 TLOG(TLVL_WARNING) << "Dropped/Delayed packets detected: " << droppedPackets << std::endl; 00132 expectedPacketNumber_ = seqNum; 00133 } 00134 else if (seqNum != expectedPacketNumber_) 00135 { 00136 int delta = expectedPacketNumber_ - seqNum; 00137 TLOG(TLVL_WARNING) << "Sequence Number significantly different than expected! (delta: " << delta << ")"; 00138 } 00139 00140 if (dataCode == ReturnCode::Read || dataCode == ReturnCode::First) 00141 { 00142 packetBuffers_.clear(); 00143 packetBuffer_t buffer; 00144 memset(&buffer[0], 0, sizeof(packetBuffer_t)); 00145 recvfrom(datasocket_, &buffer[0], sizeof(packetBuffer_t), 0, (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_)); 00146 packetBuffers_.push_back(buffer); 00147 TLOG(TLVL_DEBUG) << "Now placing UDP packet with sequence number " << std::hex << (int)seqNum << " into buffer."; 00148 if (dataCode == ReturnCode::Read) { haveData = true; } 00149 else 00150 { 00151 droppedPackets = 0; 00152 burst_end = -1; 00153 } 00154 } 00155 else if ((dataCode == ReturnCode::Middle || dataCode == ReturnCode::Last) && packetBuffers_.size() > 0) 00156 { 00157 packetBuffer_t buffer; 00158 memset(&buffer[0], 0, sizeof(packetBuffer_t)); 00159 recvfrom(datasocket_, &buffer[0], sizeof(packetBuffer_t), 0, (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_)); 00160 if (droppedPackets == 0) 00161 { 00162 packetBuffers_.push_back(buffer); 00163 } 00164 else if (burst_end == -1 || seqNum < burst_end) 00165 { 00166 bool found = false; 00167 for (packetBuffer_list_t::iterator it = packetBuffers_.begin(); it != packetBuffers_.end(); ++it) 00168 { 00169 if (seqNum < (*it)[1]) 00170 { 00171 packetBuffers_.insert(it, buffer); 00172 droppedPackets--; 00173 expectedPacketNumber_--; 00174 } 00175 } 00176 if (!found) 00177 { 00178 packetBuffers_.push_back(buffer); 00179 } 00180 } 00181 TLOG(TLVL_DEBUG) << "Now placing UDP packet with sequence number " << std::hex << (int)seqNum << " into buffer."; 00182 if (dataCode == ReturnCode::Last && droppedPackets == 0) 00183 { 00184 while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last) { packetBuffers_.pop_back(); } 00185 haveData = true; 00186 } 00187 else if (dataCode == ReturnCode::Last) { burst_end = seqNum; } 00188 else if (burst_end >= 0 && droppedPackets == 0) 00189 { 00190 while (getReturnCode(packetBuffers_.back()[0]) != ReturnCode::Last) { packetBuffers_.pop_back(); } 00191 haveData = true; 00192 } 00193 } 00194 00195 ++expectedPacketNumber_; 00196 } 00197 else 00198 { 00199 packetBuffer_t discardBuffer; 00200 recvfrom(datasocket_, &discardBuffer[0], sizeof(discardBuffer), 0, (struct sockaddr *) &si_data_, (socklen_t*)sizeof(si_data_)); 00201 TLOG(TLVL_WARNING) << "Out-of-sequence packet detected and discarded!"; 00202 } 00203 } 00204 } 00205 } 00206 00207 packetBuffer_t& firstPacket = packetBuffers_.front(); 00208 TLOG(TLVL_DEBUG) << "Recieved data, now placing data with UDP sequence number " << (int)firstPacket[1] << " into UDPFragment"; 00209 thisFrag.resize(1500 * packetBuffers_.size() + 1); 00210 std::ofstream output; 00211 if (rawOutput_) 00212 { 00213 std::string outputPath = rawPath_ + "/UDPReceiver-" + ip_ + ":" + std::to_string(dataport_) + ".bin"; 00214 output.open(outputPath, std::ios::out | std::ios::app | std::ios::binary); 00215 } 00216 00217 DataType dataType = getDataType(firstPacket[0]); 00218 thisFrag.set_hdr_type((int)dataType); 00219 int pos = 0; 00220 for (auto jj : packetBuffers_) 00221 { 00222 for (int ii = 2; ii < 1500; ++ii) 00223 { 00224 // Null-terminate string types 00225 if (jj[ii] == 0 && (dataType == DataType::JSON || dataType == DataType::String)) { break; } 00226 00227 if (rawOutput_) output.write((char*)&(jj[ii]), sizeof(uint8_t)); 00228 *(thisFrag.dataBegin() + pos) = jj[ii]; 00229 ++pos; 00230 } 00231 } 00232 if (dataType == DataType::JSON || dataType == DataType::String) 00233 { 00234 *(thisFrag.dataBegin() + pos) = 0; 00235 char zero = 0; 00236 if (rawOutput_) output.write(&zero, sizeof(char)); 00237 } 00238 if (rawOutput_) output.close(); 00239 00240 return true; 00241 } 00242 00243 void demo::UDPReceiver::start() 00244 { 00245 send(CommandType::Start_Burst); 00246 } 00247 00248 void demo::UDPReceiver::stop() 00249 { 00250 send(CommandType::Stop_Burst); 00251 } 00252 00253 void demo::UDPReceiver::pause() 00254 { 00255 send(CommandType::Stop_Burst); 00256 } 00257 00258 void demo::UDPReceiver::resume() 00259 { 00260 send(CommandType::Start_Burst); 00261 } 00262 00263 void demo::UDPReceiver::send(CommandType command) 00264 { 00265 if (sendCommands_) 00266 { 00267 CommandPacket packet; 00268 packet.type = command; 00269 packet.dataSize = 0; 00270 sendto(datasocket_, &packet, sizeof(packet), 0, (struct sockaddr *) &si_data_, sizeof(si_data_)); 00271 } 00272 } 00273 00274 // The following macro is defined in artdaq's GeneratorMacros.hh header 00275 DEFINE_ARTDAQ_COMMANDABLE_GENERATOR(demo::UDPReceiver)