00001 #ifndef ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
00002 #define ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
00003
00004 #include <boost/thread.hpp>
00005 #include "artdaq-core/Data/Fragment.hh"
00006 #include "fhiclcpp/ParameterSet.h"
00007 #include "fhiclcpp/types/Atom.h"
00008 #include "fhiclcpp/types/ConfigurationTable.h"
00009
00010 #include <mutex>
00011 #include <condition_variable>
00012
00013 namespace artdaq
00014 {
00018 class RequestReceiver
00019 {
00020 public:
00021
00025 struct Config
00026 {
00028 fhicl::Atom<int> request_port{ fhicl::Name{"request_port"}, fhicl::Comment{"Port to listen for request messages on"}, 3001 };
00030 fhicl::Atom<std::string> request_addr{ fhicl::Name{"request_address"}, fhicl::Comment{"Multicast address to listen for request messages on"}, "227.128.12.26" };
00032 fhicl::Atom<std::string> output_address{ fhicl::Name{ "multicast_interface_ip" }, fhicl::Comment{ "Use this hostname for multicast (to assign to the proper NIC)" }, "0.0.0.0" };
00034 fhicl::Atom<size_t> end_of_run_timeout_ms{ fhicl::Name{"end_of_run_quiet_timeout_ms"}, fhicl::Comment{"Amount of time (in ms) to wait for no new requests when a Stop transition is pending"}, 1000 };
00036 fhicl::Atom<artdaq::Fragment::sequence_id_t> request_increment{ fhicl::Name{"request_increment"}, fhicl::Comment{"Expected increment of sequence ID between each request"}, 1 };
00037 };
00038 using Parameters = fhicl::WrappedTable<Config>;
00039
00043 RequestReceiver();
00044
00049 RequestReceiver(const fhicl::ParameterSet& ps);
00050 virtual ~RequestReceiver();
00051
00055 void setupRequestListener();
00056
00061 void stopRequestReceiverThread(bool force = false);
00062
00066 void startRequestReceiverThread();
00067
00071 void receiveRequestsLoop();
00072
00077 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetRequests() const
00078 {
00079 std::unique_lock<std::mutex> lk(request_mutex_);
00080 std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
00081 for (auto& in : requests_)
00082 {
00083 out[in.first] = in.second;
00084 }
00085 return out;
00086 }
00087
00092 void RemoveRequest(artdaq::Fragment::sequence_id_t reqID);
00093
00098 bool isRunning() { return running_; }
00099
00103 void ClearRequests()
00104 {
00105 std::unique_lock<std::mutex> lk(request_mutex_);
00106 requests_.clear();
00107 }
00108
00113 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetAndClearRequests()
00114 {
00115 std::unique_lock<std::mutex> lk(request_mutex_);
00116 std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
00117 for (auto& in : requests_)
00118 {
00119 out[in.first] = in.second;
00120 }
00121 if(requests_.size())
00122 highest_seen_request_ = requests_.rbegin()->first;
00123 out_of_order_requests_.clear();
00124 requests_.clear();
00125 request_timing_.clear();
00126 return out;
00127 }
00128
00133 size_t size() {
00134 std::unique_lock<std::mutex> tlk(request_mutex_);
00135 return requests_.size();
00136 }
00137
00143 bool WaitForRequests(int timeout_ms)
00144 {
00145 std::unique_lock<std::mutex> lk(request_mutex_);
00146
00147 if (requests_.size() > 0) return true;
00148
00149 return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
00150 }
00151
00157 std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
00158 {
00159 std::unique_lock<std::mutex> lk(request_mutex_);
00160 return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
00161 }
00162 private:
00163
00164
00165 int request_port_;
00166 std::string request_addr_;
00167 std::string multicast_out_addr_;
00168 bool running_;
00169
00170
00171 int request_socket_;
00172 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> requests_;
00173 std::map<artdaq::Fragment::sequence_id_t, std::chrono::steady_clock::time_point> request_timing_;
00174 std::atomic<bool> request_stop_requested_;
00175 std::chrono::steady_clock::time_point request_stop_timeout_;
00176 std::atomic<bool> request_received_;
00177 size_t end_of_run_timeout_ms_;
00178 std::atomic<bool> should_stop_;
00179 mutable std::mutex request_mutex_;
00180 mutable std::mutex state_mutex_;
00181 std::condition_variable request_cv_;
00182 boost::thread requestThread_;
00183
00184 std::atomic<artdaq::Fragment::sequence_id_t> highest_seen_request_;
00185 std::set<artdaq::Fragment::sequence_id_t> out_of_order_requests_;
00186 artdaq::Fragment::sequence_id_t request_increment_;
00187 };
00188 }
00189
00190
00191 #endif //ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH