Line data Source code
1 : /**
2 : * @file TimingMasterControllerBase.cpp TimingMasterControllerBase class
3 : * implementation
4 : *
5 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
6 : * Licensing/copyright details are in the COPYING file that you should have
7 : * received with this code.
8 : */
9 :
10 : #include "TimingMasterControllerBase.hpp"
11 : #include "timinglibs/dal/EndpointLocation.hpp"
12 : #include "timinglibs/timingcmd/Nljs.hpp"
13 : #include "timinglibs/timingcmd/Structs.hpp"
14 :
15 : #include "appfwk/cmd/Nljs.hpp"
16 : #include "ers/Issue.hpp"
17 : #include "appfwk/ConfigurationManager.hpp"
18 : #include "appfwk/DAQModule.hpp"
19 :
20 : #include <chrono>
21 : #include <cstdlib>
22 : #include <string>
23 : #include <thread>
24 : #include <vector>
25 :
26 : namespace dunedaq {
27 : namespace timinglibs {
28 :
29 0 : TimingMasterControllerBase::TimingMasterControllerBase(const std::string& name)
30 : : dunedaq::timinglibs::TimingController(name, 7) // 2nd arg: how many hw commands can this module send?
31 0 : , m_endpoint_scan_period(0)
32 0 : , endpoint_scan_thread(std::bind(&TimingMasterControllerBase::endpoint_scan, this, std::placeholders::_1))
33 : {
34 0 : register_command("conf", &TimingMasterControllerBase::do_configure);
35 0 : register_command("scrap", &TimingMasterControllerBase::do_scrap);
36 :
37 0 : register_command("start_scanning_endpoints", &TimingMasterControllerBase::do_start);
38 0 : register_command("stop_scanning_endpoints", &TimingMasterControllerBase::do_stop);
39 :
40 : // timing master hardware commands
41 0 : register_command("master_set_timestamp", &TimingMasterControllerBase::do_master_set_timestamp);
42 0 : register_command("master_set_endpoint_delay", &TimingMasterControllerBase::do_master_set_endpoint_delay);
43 0 : register_command("master_send_fl_command", &TimingMasterControllerBase::do_master_send_fl_command);
44 0 : register_command("master_measure_endpoint_rtt", &TimingMasterControllerBase::do_master_measure_endpoint_rtt);
45 0 : register_command("master_endpoint_scan", &TimingMasterControllerBase::do_master_endpoint_scan);
46 0 : }
47 :
48 : void
49 0 : TimingMasterControllerBase::do_configure(const CommandData_t& data)
50 : {
51 0 : auto mdal = m_params->cast<dal::TimingMasterControllerConf>();
52 :
53 0 : auto monitored_endpoints = mdal->get_monitored_endpoints();
54 :
55 0 : for (auto endpoint : monitored_endpoints) {
56 0 : timingcmd::EndpointLocation endpoint_location;
57 0 : endpoint_location.address = endpoint->get_address();
58 0 : endpoint_location.fanout_slot = endpoint->get_fanout_slot();
59 0 : endpoint_location.sfp_slot = endpoint->get_sfp_slot();
60 0 : m_monitored_endpoint_locations.push_back(endpoint_location);
61 : }
62 :
63 0 : TimingController::do_configure(data); // configure hw command connection
64 :
65 0 : configure_hardware_or_recover_state<TimingMasterNotReady>(data, "Timing master");
66 :
67 0 : TLOG() << get_name() << " conf done on master, device: " << m_timing_device;
68 :
69 0 : m_endpoint_scan_period = mdal->get_endpoint_scan_period();
70 0 : if (m_endpoint_scan_period)
71 : {
72 0 : TLOG() << get_name() << " conf: master, will send delays with period [ms] " << m_endpoint_scan_period;
73 : }
74 : else
75 : {
76 0 : TLOG() << get_name() << " conf: master, will not send delays";
77 : }
78 0 : }
79 :
80 : void
81 0 : TimingMasterControllerBase::do_start(const CommandData_t& data)
82 : {
83 0 : TimingController::do_start(data); // set sent cmd counters to 0
84 0 : if (m_endpoint_scan_period) endpoint_scan_thread.start_working_thread();
85 0 : TLOG() << "Endpoint monitoring started";
86 0 : }
87 :
88 : void
89 0 : TimingMasterControllerBase::do_stop(const CommandData_t& /*data*/)
90 : {
91 0 : if (endpoint_scan_thread.thread_running()) endpoint_scan_thread.stop_working_thread();
92 0 : TLOG() << "Endpoint monitoring stopped";
93 0 : }
94 :
95 : void
96 0 : TimingMasterControllerBase::send_configure_hardware_commands(const CommandData_t& data)
97 : {
98 0 : do_io_reset(data);
99 0 : do_master_set_timestamp(data);
100 0 : }
101 :
102 : void
103 0 : TimingMasterControllerBase::do_master_set_timestamp(const CommandData_t&)
104 : {
105 0 : timingcmd::TimingHwCmd hw_cmd =
106 0 : construct_hw_cmd( "set_timestamp");
107 :
108 0 : auto mdal = m_params->cast<dal::TimingMasterControllerConf>();
109 0 : hw_cmd.payload["timestamp_source"] = mdal->get_timestamp_source();
110 :
111 0 : send_hw_cmd(std::move(hw_cmd));
112 0 : ++(m_sent_hw_command_counters.at(1).atomic);
113 0 : }
114 :
115 : void
116 0 : TimingMasterControllerBase::do_master_set_endpoint_delay(const CommandData_t& data)
117 : {
118 0 : timingcmd::TimingHwCmd hw_cmd =
119 0 : construct_hw_cmd( "set_endpoint_delay", data);
120 :
121 0 : TLOG_DEBUG(2) << "set ept delay data: " << data.dump();
122 :
123 0 : send_hw_cmd(std::move(hw_cmd));
124 0 : ++(m_sent_hw_command_counters.at(3).atomic);
125 0 : }
126 :
127 : void
128 0 : TimingMasterControllerBase::do_master_send_fl_command(const CommandData_t& data)
129 : {
130 0 : timingcmd::TimingHwCmd hw_cmd =
131 0 : construct_hw_cmd( "send_fl_command", data);
132 :
133 0 : TLOG_DEBUG(2) << "send fl cmd data: " << data.dump();
134 :
135 0 : send_hw_cmd(std::move(hw_cmd));
136 0 : ++(m_sent_hw_command_counters.at(4).atomic);
137 0 : }
138 :
139 : void
140 0 : TimingMasterControllerBase::do_master_measure_endpoint_rtt(const CommandData_t& data)
141 : {
142 0 : timingcmd::TimingHwCmd hw_cmd =
143 0 : construct_hw_cmd( "master_measure_endpoint_rtt");
144 :
145 0 : TLOG_DEBUG(2) << "measure endpoint rtt data: " << data.dump();
146 :
147 0 : send_hw_cmd(std::move(hw_cmd));
148 0 : ++(m_sent_hw_command_counters.at(5).atomic);
149 0 : }
150 :
151 : void
152 0 : TimingMasterControllerBase::do_master_endpoint_scan(const CommandData_t& data)
153 : {
154 0 : timingcmd::TimingHwCmd hw_cmd =
155 0 : construct_hw_cmd( "master_endpoint_scan");
156 :
157 0 : TLOG_DEBUG(2) << "endpoint scan data: " << data.dump();
158 :
159 0 : send_hw_cmd(std::move(hw_cmd));
160 0 : ++(m_sent_hw_command_counters.at(6).atomic);
161 0 : }
162 :
163 : //void
164 : //TimingMasterControllerBase::get_info(opmonlib::InfoCollector& ci, int /*level*/)
165 : //{
166 : // send counters internal to the module
167 : // timingmastercontrollerinfo::Info module_info;
168 : // module_info.sent_master_io_reset_cmds = m_sent_hw_command_counters.at(0).atomic.load();
169 : // module_info.sent_master_print_status_cmds = m_sent_hw_command_counters.at(1).atomic.load();
170 : // module_info.sent_master_set_timestamp_cmds = m_sent_hw_command_counters.at(2).atomic.load();
171 : // module_info.sent_master_set_endpoint_delay_cmds = m_sent_hw_command_counters.at(3).atomic.load();
172 : // module_info.sent_master_send_fl_command_cmds = m_sent_hw_command_counters.at(4).atomic.load();
173 :
174 : // // for (uint i = 0; i < m_number_hw_commands; ++i) {
175 : // // module_info.sent_hw_command_counters.push_back(m_sent_hw_command_counters.at(i).atomic.load());
176 : // //}
177 : // ci.add(module_info);
178 : // }
179 :
180 : // cmd stuff
181 : void
182 0 : TimingMasterControllerBase::endpoint_scan(std::atomic<bool>& running_flag)
183 : {
184 :
185 0 : std::ostringstream starting_stream;
186 0 : starting_stream << ": Starting endpoint_scan() method.";
187 0 : TLOG_DEBUG(0) << get_name() << starting_stream.str();
188 :
189 0 : while (running_flag.load() && m_endpoint_scan_period) {
190 :
191 0 : timingcmd::TimingHwCmd hw_cmd =
192 0 : construct_hw_cmd( "master_endpoint_scan");
193 :
194 0 : timingcmd::TimingMasterEndpointScanPayload cmd_payload;
195 0 : cmd_payload.endpoints = m_monitored_endpoint_locations;
196 :
197 : // dal::TimingMasterController::TimingMasterEndpointScanPayload cmd_payload;
198 : // cmd_payload.endpoints = m_monitored_endpoint_locations;
199 :
200 0 : hw_cmd.payload = cmd_payload;
201 0 : send_hw_cmd(std::move(hw_cmd));
202 :
203 0 : ++(m_sent_hw_command_counters.at(3).atomic);
204 0 : if (m_endpoint_scan_period)
205 : {
206 0 : auto prev_gather_time = std::chrono::steady_clock::now();
207 0 : auto next_gather_time = prev_gather_time + std::chrono::milliseconds(m_endpoint_scan_period);
208 :
209 : // check running_flag periodically
210 0 : auto slice_period = std::chrono::microseconds(10000);
211 0 : auto next_slice_gather_time = prev_gather_time + slice_period;
212 :
213 0 : bool break_flag = false;
214 0 : while (next_gather_time > next_slice_gather_time + slice_period) {
215 0 : if (!running_flag.load()) {
216 0 : TLOG_DEBUG(0) << "while waiting to send delays, negative run gatherer flag detected.";
217 0 : break_flag = true;
218 0 : break;
219 : }
220 0 : std::this_thread::sleep_until(next_slice_gather_time);
221 0 : next_slice_gather_time = next_slice_gather_time + slice_period;
222 : }
223 0 : if (break_flag == false) {
224 0 : std::this_thread::sleep_until(next_gather_time);
225 : }
226 : }
227 : else
228 : {
229 0 : TLOG() << "m_endpoint_scan_period is 0 and send delays thread is running! breaking loop!";
230 0 : break;
231 : }
232 0 : }
233 :
234 0 : std::ostringstream exiting_stream;
235 0 : exiting_stream << ": Exiting endpoint_scan() method. Received " << m_sent_hw_command_counters.at(3).atomic.load()
236 0 : << " commands";
237 0 : TLOG_DEBUG(0) << get_name() << exiting_stream.str();
238 0 : }
239 :
240 : } // namespace timinglibs
241 : } // namespace dunedaq
242 :
243 : // Local Variables:
244 : // c-basic-offset: 2
245 : // End:
|