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 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
00009 #include "fhiclcpp/types/ConfigurationTable.h"
00010 #endif
00011
00012 #include <mutex>
00013 #include <condition_variable>
00014
00015 namespace artdaq
00016 {
00020 class RequestReceiver
00021 {
00022 public:
00023
00027 struct Config
00028 {
00030 fhicl::Atom<int> request_port{ fhicl::Name{"request_port"}, fhicl::Comment{"Port to listen for request messages on"}, 3001 };
00032 fhicl::Atom<std::string> request_addr{ fhicl::Name{"request_address"}, fhicl::Comment{"Multicast address to listen for request messages on"}, "227.128.12.26" };
00034 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" };
00036 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 };
00038 fhicl::Atom<artdaq::Fragment::sequence_id_t> request_increment{ fhicl::Name{"request_increment"}, fhicl::Comment{"Expected increment of sequence ID between each request"}, 1 };
00039 };
00040 #if MESSAGEFACILITY_HEX_VERSION >= 0x20103
00041 using Parameters = fhicl::WrappedTable<Config>;
00042 #endif
00043
00047 RequestReceiver();
00048
00053 RequestReceiver(const fhicl::ParameterSet& ps);
00054 virtual ~RequestReceiver();
00055
00059 void setupRequestListener();
00060
00065 void stopRequestReceiverThread(bool force = false);
00066
00070 void startRequestReceiverThread();
00071
00075 void receiveRequestsLoop();
00076
00081 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetRequests() const
00082 {
00083 std::unique_lock<std::mutex> lk(request_mutex_);
00084 std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
00085 for (auto& in : requests_)
00086 {
00087 out[in.first] = in.second;
00088 }
00089 return out;
00090 }
00091
00096 void RemoveRequest(artdaq::Fragment::sequence_id_t reqID);
00097
00102 bool isRunning() { return running_; }
00103
00107 void ClearRequests()
00108 {
00109 std::unique_lock<std::mutex> lk(request_mutex_);
00110 requests_.clear();
00111 }
00112
00117 size_t size() { return requests_.size(); }
00118
00124 bool WaitForRequests(int timeout_ms)
00125 {
00126 std::unique_lock<std::mutex> lk(request_mutex_);
00127 return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
00128 }
00129
00135 std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
00136 {
00137 std::unique_lock<std::mutex> lk(request_mutex_);
00138 return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
00139 }
00140 private:
00141
00142
00143 int request_port_;
00144 std::string request_addr_;
00145 std::string multicast_out_addr_;
00146 bool running_;
00147
00148
00149 int request_socket_;
00150 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> requests_;
00151 std::map<artdaq::Fragment::sequence_id_t, std::chrono::steady_clock::time_point> request_timing_;
00152 std::atomic<bool> request_stop_requested_;
00153 std::chrono::steady_clock::time_point request_stop_timeout_;
00154 std::atomic<bool> request_received_;
00155 size_t end_of_run_timeout_ms_;
00156 std::atomic<bool> should_stop_;
00157 mutable std::mutex request_mutex_;
00158 mutable std::mutex state_mutex_;
00159 std::condition_variable request_cv_;
00160 boost::thread requestThread_;
00161
00162 std::atomic<artdaq::Fragment::sequence_id_t> highest_seen_request_;
00163 std::set<artdaq::Fragment::sequence_id_t> out_of_order_requests_;
00164 artdaq::Fragment::sequence_id_t request_increment_;
00165 };
00166 }
00167
00168
00169 #endif //ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH