Line data Source code
1 : #ifndef ARTDAQ_ARTDAQ_APPLICATION_BOARDREADERCORE_HH_
2 : #define ARTDAQ_ARTDAQ_APPLICATION_BOARDREADERCORE_HH_
3 :
4 : #include "artdaq/Application/Commandable.hh"
5 : #include "artdaq/DAQrate/DataSenderManager.hh"
6 : #include "artdaq/DAQrate/StatisticsHelper.hh"
7 : #include "artdaq/DAQrate/detail/RequestReceiver.hh"
8 : #include "artdaq/Generators/CommandableFragmentGenerator.hh"
9 :
10 : #include "canvas/Persistency/Provenance/RunID.h"
11 : #include "fhiclcpp/ParameterSet.h"
12 :
13 : #include <atomic>
14 : #include <string>
15 :
16 : namespace artdaq {
17 : class BoardReaderCore;
18 : }
19 :
20 : /**
21 : * \brief BoardReaderCore implements the state machine for the BoardReader artdaq application.
22 : * It contains a CommandableFragmentGenerator, which generates Fragments which are then sent to a DataSenderManager by BoardReaderCore.
23 : */
24 : class artdaq::BoardReaderCore
25 : {
26 : public:
27 : static const std::string FRAGMENTS_PROCESSED_STAT_KEY; ///< Key for the Fragments Processed MonitoredQuantity
28 : static const std::string INPUT_WAIT_STAT_KEY; ///< Key for the Input Wait MonitoredQuantity
29 : static const std::string BUFFER_WAIT_STAT_KEY; ///< Key for the Fragment Buffer Wait MonitoredQuantity
30 : static const std::string REQUEST_WAIT_STAT_KEY; ///< Key for the Request Buffer Wait MonitoredQuantity
31 : static const std::string BRSYNC_WAIT_STAT_KEY; ///< Key for the Sync Wait MonitoredQuantity
32 : static const std::string OUTPUT_WAIT_STAT_KEY; ///< Key for the Output Wait MonitoredQuantity
33 : static const std::string FRAGMENTS_PER_READ_STAT_KEY; ///< Key for the Fragments Per Read MonitoredQuantity
34 :
35 : /**
36 : * \brief BoardReaderCore Constructor
37 : * \param parent_application Reference to parent Commandable object, for in_run_failure notification
38 : */
39 : BoardReaderCore(Commandable& parent_application);
40 :
41 : /**
42 : * \brief Copy Constructor is Deleted
43 : */
44 : BoardReaderCore(BoardReaderCore const&) = delete;
45 :
46 : /**
47 : * \brief BoardReaderCore Destructor
48 : */
49 : virtual ~BoardReaderCore();
50 :
51 : /**
52 : * \brief Copy Assignment Operator is deleted
53 : * \return BoardReaderCore copy
54 : */
55 : BoardReaderCore& operator=(BoardReaderCore const&) = delete;
56 : BoardReaderCore(BoardReaderCore&&) = delete; ///< Move Constructor is deleted
57 : BoardReaderCore& operator=(BoardReaderCore&&) = delete; ///< Move Assignment Operator is deleted
58 :
59 : /**
60 : * \brief Initialize the BoardReaderCore
61 : * \param pset ParameterSet used to configure the BoardReaderCore
62 : * \param timeout Timeout for transition
63 : * \param timestamp Timestamp of transition
64 : * \return True if the initialize attempt succeeded
65 : *
66 : * \verbatim
67 : * BoardReaderCore accepts the following Parameters:
68 : * "daq" (REQUIRED): FHiCL table containing DAQ configuration.
69 : * "fragment_receiver" (REQUIRED): FHiCL table containing Fragment Receiver configruation.
70 : * See CommandableFragmentGenerator for configuration options.
71 : * "generator" (Default: ""): The plugin name of the generator to load
72 : * "rt_priority" (Default: 0): The unix priority to attempt to assign to the process
73 : * "verbose" (Default: true): Whether to print transition messages
74 : * "metrics": FHiCL table containing MetricManager configuration.
75 : * See MetricManager for configuration options.
76 : * \endverbatim
77 : *
78 : */
79 : bool initialize(fhicl::ParameterSet const& pset, uint64_t timeout, uint64_t timestamp);
80 :
81 : /**
82 : * \brief Start the BoardReader, and the CommandableFragmentGenerator
83 : * \param id Run ID of new run
84 : * \param timeout Timeout for transition
85 : * \param timestamp Timestamp of transition
86 : * \return True unless exception occurred
87 : */
88 : bool start(art::RunID id, uint64_t timeout, uint64_t timestamp);
89 :
90 : /**
91 : * \brief Stop the BoardReader, and the CommandableFragmentGenerator
92 : * \param timeout Timeout for transition
93 : * \param timestamp Timestamp of transition
94 : * \return True unless exception occurred
95 : */
96 : bool stop(uint64_t timeout, uint64_t timestamp);
97 :
98 : /**
99 : * \brief Pause the BoardReader, and the CommandableFragmentGenerator
100 : * \param timeout Timeout for transition
101 : * \param timestamp Timestamp of transition
102 : * \return True unless exception occurred
103 : */
104 : bool pause(uint64_t timeout, uint64_t timestamp);
105 :
106 : /**
107 : * \brief Resume the BoardReader, and the CommandableFragmentGenerator
108 : * \param timeout Timeout for transition
109 : * \param timestamp Timestamp of transition
110 : * \return True unless exception occurred
111 : */
112 : bool resume(uint64_t timeout, uint64_t timestamp);
113 :
114 : /**
115 : * \brief Shutdown the BoardReader, and the CommandableFragmentGenerator
116 : * \param timeout Timeout for transition
117 : * \return True unless exception occurred
118 : */
119 : bool shutdown(uint64_t timeout);
120 :
121 : /**
122 : * \brief Soft-Initialize the BoardReader. No-Op
123 : * \param pset ParameterSet used to configure the BoardReaderCore
124 : * \param timeout Timeout for transition
125 : * \param timestamp Timestamp of transition
126 : * \return True unless exception occurred
127 : */
128 : bool soft_initialize(fhicl::ParameterSet const& pset, uint64_t timeout, uint64_t timestamp);
129 :
130 : /**
131 : * \brief Reinitialize the BoardReader. No-Op
132 : * \param pset ParameterSet used to configure the BoardReaderCore
133 : * \param timeout Timeout for transition
134 : * \param timestamp Timestamp of transition
135 : * \return True unless exception occurred
136 : */
137 : bool reinitialize(fhicl::ParameterSet const& pset, uint64_t timeout, uint64_t timestamp);
138 :
139 : /**
140 : * \brief Main working loop of the BoardReaderCore
141 : *
142 : * This loop calls the CommandableFragmentGenerator::getNext method and gives the result to the FragmentBuffer
143 : */
144 : void receive_fragments();
145 :
146 : /**
147 : * @brief Main working loop of the BoardReaderCore, pt. 2
148 : *
149 : * This loop calls the FragmentBuffer::applyRequests method and sends the result using DataSenderManager
150 : */
151 : void send_fragments();
152 :
153 : /**
154 : * \brief Send a report on a given run-time quantity
155 : * \param which Which quantity to report
156 : * \return A string containing the requested quantity.
157 : *
158 : * If the CommandableFragmentGenerator has been initialized, CommandableFragmentGenerator::report(std::string const& which) will be called.
159 : * Otherwise, the BoardReaderCore will return the current run number and an error message.
160 : */
161 : std::string report(std::string const& which) const;
162 :
163 : /**
164 : * \brief Run a user-defined command on the CommandableFragmentGenerator
165 : * \param command Command name to run
166 : * \param arg Argument(s) for command
167 : * \return Whether command completed successfully. (By convention, unsupported commands should return true)
168 : */
169 : bool metaCommand(std::string const& command, std::string const& arg);
170 :
171 : /**
172 : * \brief Gets a handle to the DataSenderManager
173 : * \return Pointer to the DataSenderManager
174 : */
175 : static DataSenderManager* GetDataSenderManagerPtr() { return sender_ptr_.get(); }
176 :
177 : /// <summary>
178 : /// Get the number of Fragments processed this run
179 : /// </summary>
180 : /// <returns>The number of Fragments processed this run</returns>
181 0 : size_t GetFragmentsProcessed() { return fragment_count_; }
182 :
183 : CommandableFragmentGenerator const* GetGeneratorPointer()
184 : {
185 : if (generator_ptr_)
186 : return generator_ptr_.get();
187 : else
188 : return nullptr;
189 : }
190 :
191 : /**
192 : * @brief Get whether the sender thread is still running
193 : * @return Whether the sender thread (applying requests to FragmentBuffer and sending to DataSenderManager) is still running
194 : */
195 0 : bool GetSenderThreadActive() { return sender_thread_active_.load(); }
196 : /**
197 : * @brief Get whether the receiver thread is still running
198 : * @return Whether the receiver thread (calling CFG::getNext and putting Fragments into the FragmentBuffer) is still running
199 : */
200 0 : bool GetReceiverThreadActive() { return receiver_thread_active_.load(); }
201 : /**
202 : * @brief Set the timeout for starting the sender and receiver threads
203 : * @param timeout Timeout, in seconds, for starting the sender and receiver threads
204 : *
205 : * This function is used to communicate the start transition timeout from BoardReaderApp to the BoardReaderCore threads
206 : */
207 0 : void SetStartTransitionTimeout(double timeout) { start_transition_timeout_ = timeout; }
208 :
209 : private:
210 : Commandable& parent_application_;
211 : std::unique_ptr<CommandableFragmentGenerator> generator_ptr_;
212 : std::unique_ptr<RequestReceiver> request_receiver_ptr_;
213 : std::shared_ptr<FragmentBuffer> fragment_buffer_ptr_;
214 : art::RunID run_id_;
215 :
216 : fhicl::ParameterSet data_pset_;
217 : int rt_priority_;
218 : bool skip_seqId_test_;
219 :
220 : static std::unique_ptr<artdaq::DataSenderManager> sender_ptr_;
221 :
222 : std::atomic<size_t> fragment_count_;
223 : artdaq::Fragment::sequence_id_t prev_seq_id_;
224 : std::atomic<bool> stop_requested_;
225 : std::atomic<bool> pause_requested_;
226 :
227 : // State orchestration
228 : std::atomic<bool> running_{false};
229 : std::atomic<bool> sender_thread_active_{false};
230 : std::atomic<bool> receiver_thread_active_{false};
231 : double start_transition_timeout_{10.0};
232 :
233 : // attributes and methods for statistics gathering & reporting
234 : artdaq::StatisticsHelper statsHelper_;
235 :
236 : std::string buildStatisticsString_();
237 :
238 : void sendMetrics_();
239 :
240 : bool verbose_; ///< Whether to log transition messages
241 : };
242 :
243 : #endif // ARTDAQ_ARTDAQ_APPLICATION_BOARDREADERCORE_HH_
|