Line data Source code
1 : /**
2 : * @file TimingHardwareManagerBase.cpp
3 : *
4 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : #include "TimingHardwareManagerBase.hpp"
10 :
11 : #include "timinglibs/dal/TimingFanoutDevice.hpp"
12 : #include "timinglibs/dal/TimingHardwareManagerBase.hpp"
13 :
14 : #include "iomanager/IOManager.hpp"
15 : #include "logging/Logging.hpp"
16 : #include "timing/definitions.hpp"
17 :
18 : #include "timing/FanoutDesign.hpp"
19 : #include "timing/MuxDesignInterface.hpp"
20 :
21 : #include "appfwk/ConfigurationManager.hpp"
22 : #include "timing/timingfirmware/Nljs.hpp"
23 : #include "timing/timingfirmware/Structs.hpp"
24 :
25 : #include <memory>
26 : #include <string>
27 : #include <utility>
28 : #include <vector>
29 :
30 : #define TRACE_NAME "TimingHardwareManagerBase" // NOLINT
31 :
32 : namespace dunedaq {
33 :
34 0 : DUNE_DAQ_SERIALIZABLE(timinglibs::timingcmd::TimingHwCmd, "TimingHwCmd");
35 0 : DUNE_DAQ_SERIALIZABLE(nlohmann::json, "JSON");
36 :
37 : namespace timinglibs {
38 :
39 0 : TimingHardwareManagerBase::TimingHardwareManagerBase(const std::string& name)
40 : : dunedaq::appfwk::DAQModule(name)
41 0 : , m_hw_cmd_connection("timing_cmds")
42 0 : , m_hw_command_receiver(nullptr)
43 0 : , m_gather_interval(1e6)
44 0 : , m_gather_interval_debug(10e6)
45 0 : , m_monitored_device_name_master("")
46 0 : , m_monitored_device_name_endpoint("")
47 0 : , m_monitored_device_name_hsi("")
48 0 : , m_received_hw_commands_counter{ 0 }
49 0 : , m_accepted_hw_commands_counter{ 0 }
50 0 : , m_rejected_hw_commands_counter{ 0 }
51 0 : , m_failed_hw_commands_counter{ 0 }
52 0 : , m_endpoint_scan_threads_clean_up_thread(nullptr)
53 : {
54 : // register_command("start", &TimingHardwareManagerBase::do_start);
55 : // register_command("stop", &TimingHardwareManagerBase::do_stop);
56 0 : register_command("scrap", &TimingHardwareManagerBase::do_scrap);
57 0 : }
58 :
59 : void
60 0 : TimingHardwareManagerBase::init(std::shared_ptr<appfwk::ConfigurationManager> mcfg)
61 : {
62 0 : auto mod_config = mcfg->get_dal<timinglibs::dal::TimingHardwareManagerBase>(get_name());
63 0 : m_params = mod_config->get_configuration();
64 :
65 : // set up queues
66 0 : for (auto con : mod_config->get_inputs()) {
67 0 : if (con->get_data_type() == datatype_to_string<timingcmd::TimingHwCmd>()) {
68 0 : m_hw_cmd_connection = con->UID();
69 0 : TLOG() << "m_hw_cmd_connection: " << m_hw_cmd_connection;
70 : }
71 : }
72 :
73 0 : try {
74 0 : m_hw_command_receiver = iomanager::IOManager::get()->get_receiver<timingcmd::TimingHwCmd>(m_hw_cmd_connection);
75 0 : } catch (const ers::Issue& excpt) {
76 0 : throw InvalidQueueFatalError(ERS_HERE, get_name(), "input", excpt);
77 0 : }
78 :
79 0 : m_endpoint_scan_threads_clean_up_thread = std::make_unique<dunedaq::utilities::ReusableThread>(0);
80 0 : }
81 :
82 : void
83 0 : TimingHardwareManagerBase::conf(const CommandData_t& /*data*/)
84 : {
85 0 : m_received_hw_commands_counter = 0;
86 0 : m_accepted_hw_commands_counter = 0;
87 0 : m_rejected_hw_commands_counter = 0;
88 0 : m_failed_hw_commands_counter = 0;
89 :
90 0 : m_gather_interval = m_params->get_gather_interval();
91 0 : m_gather_interval_debug = m_params->get_gather_interval_debug();
92 :
93 0 : m_monitored_device_name_master = m_params->get_monitored_device_name_master();
94 0 : for (auto fanout : m_params->get_monitored_device_names_fanout()) {
95 0 : TLOG_DEBUG(3) << fanout->get_device() << ": device, slot: " << fanout->get_fanout_slot() << std::endl;
96 0 : m_monitored_device_names_fanout.emplace(fanout->get_fanout_slot(), fanout->get_device());
97 : }
98 :
99 0 : m_monitored_device_name_endpoint = m_params->get_monitored_device_name_endpoint();
100 0 : m_monitored_device_name_hsi = m_params->get_monitored_device_name_hsi();
101 :
102 0 : configure_uhal(m_params); // configure hw ipbus connection
103 :
104 0 : m_hw_command_receiver->add_callback(
105 0 : std::bind(&TimingHardwareManagerBase::process_hardware_command, this, std::placeholders::_1));
106 :
107 0 : m_run_endpoint_scan_cleanup_thread.store(true);
108 0 : m_endpoint_scan_threads_clean_up_thread->set_work(&TimingHardwareManagerBase::clean_endpoint_scan_threads, this);
109 0 : }
110 :
111 : void
112 0 : TimingHardwareManagerBase::do_scrap(const CommandData_t& /*data*/)
113 : {
114 0 : m_hw_command_receiver->remove_callback();
115 :
116 0 : auto time_of_scrap = std::chrono::high_resolution_clock::now();
117 0 : while (m_command_threads.size()) {
118 0 : auto now = std::chrono::high_resolution_clock::now();
119 0 : auto ms_since_scrap = std::chrono::duration_cast<std::chrono::milliseconds>(now - time_of_scrap);
120 0 : TLOG_DEBUG(0) << "Have been waiting for " << ms_since_scrap.count() << " ms for " << m_command_threads.size()
121 0 : << " command threads to finish...";
122 0 : std::this_thread::sleep_for(std::chrono::microseconds(250000));
123 : }
124 0 : m_run_endpoint_scan_cleanup_thread.store(false);
125 :
126 0 : stop_hw_mon_gathering();
127 :
128 0 : scrap_uhal();
129 :
130 0 : m_command_threads.clear();
131 0 : m_info_gatherers.clear();
132 0 : m_timing_hw_cmd_map_.clear();
133 0 : m_hw_device_map.clear();
134 0 : m_connection_manager.reset();
135 0 : }
136 :
137 : const timing::TimingNode*
138 0 : TimingHardwareManagerBase::get_timing_device_plain(const std::string& device_name)
139 : {
140 :
141 0 : if (!device_name.compare("")) {
142 0 : std::stringstream message;
143 0 : message << "UHAL device name is an empty string";
144 0 : throw UHALDeviceNameIssue(ERS_HERE, message.str());
145 0 : }
146 :
147 0 : if (auto hw_device_entry = m_hw_device_map.find(device_name); hw_device_entry != m_hw_device_map.end()) {
148 0 : return dynamic_cast<const timing::TimingNode*>(&hw_device_entry->second->getNode(""));
149 : } else {
150 0 : TLOG_DEBUG(0) << get_name() << ": hw device interface for: " << device_name
151 0 : << " does not exist. I will try to create it.";
152 :
153 0 : try {
154 0 : std::lock_guard<std::mutex> hw_device_map_guard(m_hw_device_map_mutex);
155 0 : m_hw_device_map.emplace(device_name,
156 0 : std::make_unique<uhal::HwInterface>(m_connection_manager->getDevice(device_name)));
157 0 : } catch (const uhal::exception::ConnectionUIDDoesNotExist& exception) {
158 0 : std::stringstream message;
159 0 : message << "UHAL device name not " << device_name << " in connections file";
160 0 : throw UHALDeviceNameIssue(ERS_HERE, message.str(), exception);
161 0 : }
162 :
163 0 : TLOG_DEBUG(0) << get_name() << ": hw device interface for: " << device_name << " successfully created.";
164 :
165 0 : return dynamic_cast<const timing::TimingNode*>(&m_hw_device_map.find(device_name)->second->getNode(""));
166 : }
167 : }
168 :
169 : void
170 0 : TimingHardwareManagerBase::gather_monitor_data(InfoGatherer& gatherer)
171 : {
172 0 : auto device_name = gatherer.get_device_name();
173 :
174 0 : while (gatherer.run_gathering()) {
175 :
176 : // collect the data from the hardware
177 0 : try {
178 0 : auto design = get_timing_device<const timing::TopDesignInterface*>(device_name);
179 :
180 0 : gatherer.collect_info_from_device(*design);
181 0 : } catch (const std::exception& excpt) {
182 0 : ers::warning(FailedToCollectOpMonInfo(ERS_HERE, device_name, excpt));
183 0 : }
184 :
185 0 : auto prev_gather_time = std::chrono::steady_clock::now();
186 0 : auto next_gather_time = prev_gather_time + std::chrono::microseconds(gatherer.get_gather_interval());
187 :
188 : // check running_flag periodically
189 0 : auto slice_period = std::chrono::microseconds(10000);
190 0 : auto next_slice_gather_time = prev_gather_time + slice_period;
191 :
192 0 : bool break_flag = false;
193 0 : while (next_gather_time > next_slice_gather_time + slice_period) {
194 0 : if (!gatherer.run_gathering()) {
195 0 : TLOG_DEBUG(0) << "while waiting to gather data, negative run gatherer flag detected.";
196 0 : break_flag = true;
197 0 : break;
198 : }
199 0 : std::this_thread::sleep_until(next_slice_gather_time);
200 0 : next_slice_gather_time = next_slice_gather_time + slice_period;
201 : }
202 0 : if (break_flag == false) {
203 0 : std::this_thread::sleep_until(next_gather_time);
204 : }
205 : }
206 0 : }
207 :
208 : void
209 0 : TimingHardwareManagerBase::register_info_gatherer(uint gather_interval,
210 : const std::string& device_name,
211 : int op_mon_level)
212 : {
213 0 : std::string gatherer_name = device_name + "_level_" + std::to_string(op_mon_level);
214 0 : if (m_info_gatherers.find(gatherer_name) == m_info_gatherers.end()) {
215 0 : std::unique_ptr<InfoGatherer> gatherer = std::make_unique<InfoGatherer>(
216 0 : std::bind(&TimingHardwareManagerBase::gather_monitor_data, this, std::placeholders::_1),
217 : gather_interval,
218 : device_name,
219 0 : op_mon_level);
220 :
221 0 : TLOG_DEBUG(0) << "Registering info gatherer: " << gatherer_name;
222 0 : m_info_gatherers.emplace(std::make_pair(gatherer_name, std::move(gatherer)));
223 0 : } else {
224 0 : TLOG() << "Skipping registration of " << gatherer_name << ". Already exists.";
225 : }
226 0 : }
227 :
228 : void
229 0 : TimingHardwareManagerBase::start_hw_mon_gathering(const std::string& device_name)
230 : {
231 : // start all gatherers if no device name is given
232 0 : if (!device_name.compare("")) {
233 0 : TLOG_DEBUG(0) << get_name() << " Starting all info gatherers";
234 0 : for (auto it = m_info_gatherers.begin(); it != m_info_gatherers.end(); ++it)
235 0 : it->second.get()->start_gathering_thread();
236 : } else {
237 : // find gatherer for suppled device name and start it
238 0 : bool gatherer_found = false;
239 0 : for (auto it = m_info_gatherers.lower_bound(device_name); it != m_info_gatherers.end(); ++it) {
240 0 : TLOG_DEBUG(0) << get_name() << " Starting info gatherer: " << it->first;
241 0 : it->second.get()->start_gathering_thread();
242 0 : gatherer_found = true;
243 : }
244 0 : if (!gatherer_found)
245 0 : ers::warning(AttemptedToControlNonExantInfoGatherer(ERS_HERE, "start", device_name));
246 : }
247 0 : }
248 :
249 : void
250 0 : TimingHardwareManagerBase::stop_hw_mon_gathering(const std::string& device_name)
251 : {
252 : // stop all gatherers if no device name is given
253 0 : if (!device_name.compare("")) {
254 0 : TLOG_DEBUG(0) << get_name() << " Stopping all info gatherers";
255 0 : for (auto it = m_info_gatherers.begin(); it != m_info_gatherers.end(); ++it)
256 0 : it->second.get()->stop_gathering_thread();
257 : } else {
258 : // find gatherer for suppled device name and stop it
259 0 : bool gatherer_found = false;
260 0 : for (auto it = m_info_gatherers.lower_bound(device_name); it != m_info_gatherers.end(); ++it) {
261 0 : TLOG_DEBUG(0) << get_name() << " Stopping info gatherer: " << it->first;
262 0 : it->second.get()->stop_gathering_thread();
263 0 : gatherer_found = true;
264 : }
265 0 : if (!gatherer_found)
266 0 : ers::warning(AttemptedToControlNonExantInfoGatherer(ERS_HERE, "stop", device_name));
267 : }
268 0 : }
269 :
270 : std::vector<std::string>
271 0 : TimingHardwareManagerBase::check_hw_mon_gatherer_is_running(const std::string& device_name)
272 : {
273 0 : std::vector<std::string> running_gatherers;
274 0 : for (auto it = m_info_gatherers.lower_bound(device_name); it != m_info_gatherers.end(); ++it) {
275 0 : TLOG_DEBUG(0) << get_name() << " Checking run state of info gatherer: " << it->first << ", and the state is "
276 0 : << it->second.get()->run_gathering();
277 0 : if (it->second.get()->run_gathering()) {
278 0 : running_gatherers.push_back(it->first);
279 : }
280 : }
281 0 : return running_gatherers;
282 0 : }
283 :
284 : // cmd stuff
285 :
286 : void
287 0 : TimingHardwareManagerBase::process_hardware_command(timingcmd::TimingHwCmd& timing_hw_cmd)
288 : {
289 0 : std::ostringstream starting_stream;
290 0 : starting_stream << ": Executing process_hardware_command() callback.";
291 0 : TLOG_DEBUG(0) << get_name() << starting_stream.str();
292 :
293 0 : ++m_received_hw_commands_counter;
294 :
295 0 : TLOG_DEBUG(0) << get_name() << ": Received hardware command #" << m_received_hw_commands_counter.load()
296 0 : << ", it is of type: " << timing_hw_cmd.id << ", targeting device: " << timing_hw_cmd.device
297 0 : << ", with payload: " << timing_hw_cmd.payload.dump();
298 :
299 0 : std::string hw_cmd_name = timing_hw_cmd.id;
300 0 : if (auto cmd = m_timing_hw_cmd_map_.find(hw_cmd_name); cmd != m_timing_hw_cmd_map_.end()) {
301 :
302 0 : ++m_accepted_hw_commands_counter;
303 :
304 0 : TLOG_DEBUG(0) << "Found hw cmd: " << hw_cmd_name;
305 0 : try {
306 0 : std::invoke(cmd->second, timing_hw_cmd);
307 0 : } catch (const std::exception& exception) {
308 0 : ers::error(FailedToExecuteHardwareCommand(ERS_HERE, hw_cmd_name, timing_hw_cmd.device, exception));
309 0 : ++m_failed_hw_commands_counter;
310 0 : }
311 : } else {
312 0 : ers::error(InvalidHardwareCommandID(ERS_HERE, hw_cmd_name));
313 0 : ++m_rejected_hw_commands_counter;
314 : }
315 :
316 0 : std::ostringstream exiting_stream;
317 0 : exiting_stream << ": Finished executing process_hardware_command() callback. Received "
318 0 : << m_received_hw_commands_counter.load() << " commands";
319 0 : TLOG_DEBUG(0) << get_name() << exiting_stream.str();
320 0 : }
321 :
322 : // common commands
323 : void
324 0 : TimingHardwareManagerBase::io_reset(const timingcmd::TimingHwCmd& hw_cmd)
325 : {
326 0 : timingcmd::IOResetCmdPayload cmd_payload;
327 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
328 :
329 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " io reset";
330 :
331 : // io reset disrupts hw mon gathering, so stop if running
332 0 : auto running_hw_gatherers = check_hw_mon_gatherer_is_running(hw_cmd.device);
333 0 : for (auto& gatherer : running_hw_gatherers) {
334 0 : stop_hw_mon_gathering(gatherer);
335 : }
336 :
337 0 : auto design = get_timing_device<const timing::TopDesignInterface*>(hw_cmd.device);
338 :
339 0 : if (cmd_payload.soft) {
340 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " soft io reset";
341 0 : design->soft_reset_io();
342 0 : } else if (!cmd_payload.clock_config.empty()) {
343 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device
344 0 : << " io reset, with supplied clk file: " << cmd_payload.clock_config;
345 0 : design->reset_io(cmd_payload.clock_config);
346 : } else {
347 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device
348 0 : << " io reset, with supplied clk source: " << cmd_payload.clock_source;
349 0 : design->reset_io(static_cast<timing::ClockSource>(cmd_payload.clock_source));
350 : }
351 :
352 : // if hw mon gathering was running previously, start it again
353 0 : for (auto& gatherer : running_hw_gatherers) {
354 0 : start_hw_mon_gathering(gatherer);
355 : }
356 0 : }
357 :
358 : void
359 0 : TimingHardwareManagerBase::print_status(const timingcmd::TimingHwCmd& hw_cmd)
360 : {
361 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " print status";
362 :
363 0 : auto design = get_timing_device<const timing::TopDesignInterface*>(hw_cmd.device);
364 0 : TLOG() << std::endl << design->get_status();
365 0 : }
366 :
367 : // master commands
368 : void
369 0 : TimingHardwareManagerBase::set_timestamp(const timingcmd::TimingHwCmd& hw_cmd)
370 : {
371 0 : timingcmd::SyncTimestampPayload cmd_payload;
372 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
373 :
374 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device
375 0 : << " set timestamp, with supplied ts source: " << cmd_payload.timestamp_source;
376 :
377 0 : auto design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
378 0 : design->sync_timestamp(static_cast<timing::TimestampSource>(cmd_payload.timestamp_source));
379 0 : }
380 :
381 : void
382 0 : TimingHardwareManagerBase::master_endpoint_scan(const timingcmd::TimingHwCmd& hw_cmd)
383 : {
384 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " master_endpoint_scan";
385 :
386 0 : std::stringstream command_thread_uid;
387 0 : auto t = std::time(nullptr);
388 0 : auto tm = *std::localtime(&t);
389 0 : command_thread_uid << "enpoint_scan_cmd_at_" << std::put_time(&tm, "%d-%m-%Y %H-%M-%S") << "_cmd_num_"
390 0 : << m_accepted_hw_commands_counter.load();
391 :
392 0 : if (m_command_threads.size() > 5) {
393 0 : ers::warning(TooManyEndpointScanThreadsQueued(ERS_HERE, m_command_threads.size()));
394 : } else {
395 0 : TLOG_DEBUG(1) << "Queuing: " << command_thread_uid.str();
396 :
397 0 : auto thread_key = command_thread_uid.str();
398 0 : std::unique_lock map_lock(m_command_threads_map_mutex);
399 :
400 0 : m_command_threads.emplace(
401 : thread_key,
402 0 : std::make_unique<std::thread>(std::bind(&TimingHardwareManagerBase::perform_endpoint_scan, this, hw_cmd)));
403 0 : }
404 0 : }
405 :
406 : void
407 0 : TimingHardwareManagerBase::perform_endpoint_scan(const timingcmd::TimingHwCmd& hw_cmd)
408 : {
409 0 : timingcmd::TimingMasterEndpointScanPayload cmd_payload;
410 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
411 :
412 0 : for (auto& endpoint_location : cmd_payload.endpoints) {
413 0 : auto endpoint_address = endpoint_location.address;
414 0 : auto fanout_slot = endpoint_location.fanout_slot;
415 0 : auto sfp_slot = endpoint_location.sfp_slot;
416 :
417 0 : std::unique_lock<std::mutex> master_sfp_lock(master_sfp_mutex);
418 :
419 0 : TLOG_DEBUG(1) << get_name() << ": " << hw_cmd.device
420 0 : << " master_endpoint_scan starting: ept adr: " << endpoint_address << ", ept sfp: " << sfp_slot
421 0 : << ", fanout slot: " << fanout_slot;
422 :
423 0 : auto master_design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
424 0 : try {
425 : // master_design->get_master_node_plain()->switch_endpoint_sfp(endpoint_address, true);
426 :
427 0 : if (sfp_slot >= 0) {
428 0 : if (fanout_slot >= 0) {
429 : // configure fanout/FIB
430 0 : try {
431 0 : get_timing_device<const timing::MuxDesignInterface*>(m_monitored_device_names_fanout.at(fanout_slot))
432 0 : ->switch_mux(sfp_slot);
433 0 : } catch (const UHALDeviceClassIssue& e) {
434 0 : ers::error(e);
435 0 : continue;
436 0 : }
437 :
438 : // slot 0 for board without multiple data tx paths, e.g. FMC, TLU
439 0 : if (fanout_slot != 0) {
440 : // configure GIB/MIB
441 0 : try {
442 0 : get_timing_device<const timing::MuxDesignInterface*>(hw_cmd.device)->switch_mux(fanout_slot - 1);
443 0 : } catch (const UHALDeviceClassIssue& e) {
444 0 : ers::error(e);
445 0 : continue;
446 0 : }
447 : }
448 : } else {
449 0 : dynamic_cast<const timing::MuxDesignInterface*>(master_design)->switch_mux(sfp_slot);
450 : }
451 : }
452 :
453 0 : auto scan_result = master_design->get_master_node_plain()->scan_endpoint(endpoint_address, true);
454 0 : if (scan_result.alive) {
455 0 : auto current_rtt = scan_result.round_trip_time;
456 0 : ers::info(EndpointRTTMeasurement(ERS_HERE, fanout_slot, sfp_slot, endpoint_address, current_rtt));
457 0 : if (m_monitored_endpoints_round_trip_times.count(endpoint_address)) {
458 0 : auto previous_rtt = m_monitored_endpoints_round_trip_times[endpoint_address];
459 0 : if (previous_rtt != current_rtt) {
460 : // TLOG() << "New round trip time for endpoint " << endpoint_address << " measured. Previous: "
461 : // << m_monitored_endpoints_round_trip_times[endpoint_address] << ", current: " << current_rtt;
462 0 : ers::warning(ChangedEndpointRTTMeasurement(
463 0 : ERS_HERE, fanout_slot, sfp_slot, endpoint_address, current_rtt, previous_rtt));
464 : }
465 : } else {
466 : // TLOG() << "First measured round trip time for endpoint " << endpoint_address << " is: " << current_rtt;
467 : }
468 0 : m_monitored_endpoints_round_trip_times[endpoint_address] = current_rtt;
469 : } else {
470 0 : ers::error(EndpointUnresponsive(ERS_HERE, fanout_slot, sfp_slot, endpoint_address));
471 : // TLOG() << endpoint_address << " endpoint was not alive...";
472 : }
473 : // master_design->get_master_node_plain()->switch_endpoint_sfp(endpoint_address, false);
474 0 : } catch (std::exception& e) {
475 0 : ers::error(EndpointScanFailure(ERS_HERE, e));
476 0 : master_design->get_master_node_plain()->switch_endpoint_sfp(endpoint_address, false);
477 0 : }
478 0 : }
479 0 : }
480 :
481 : void
482 0 : TimingHardwareManagerBase::clean_endpoint_scan_threads()
483 : {
484 0 : TLOG_DEBUG(0) << "Entering clean_endpoint_scan_threads()";
485 0 : bool break_flag = false;
486 0 : while (!break_flag) {
487 0 : for (auto& thread : m_command_threads) {
488 0 : if (thread.second->joinable()) {
489 0 : std::unique_lock map_lock(m_command_threads_map_mutex);
490 0 : TLOG_DEBUG(2) << thread.first << " thread ready. Cleaning up.";
491 0 : thread.second->join();
492 0 : m_command_threads.erase(thread.first);
493 0 : }
494 : }
495 :
496 0 : auto prev_clean_time = std::chrono::steady_clock::now();
497 0 : auto next_clean_time = prev_clean_time + std::chrono::milliseconds(30);
498 :
499 : // check running_flag periodically
500 0 : auto flag_check_period = std::chrono::milliseconds(1);
501 0 : auto next_flag_check_time = prev_clean_time + flag_check_period;
502 :
503 0 : while (next_clean_time > next_flag_check_time + flag_check_period) {
504 0 : if (!m_run_endpoint_scan_cleanup_thread.load()) {
505 0 : TLOG_DEBUG(2) << "while waiting to clean up endpoint scan threads, negative run gatherer flag detected.";
506 0 : break_flag = true;
507 0 : break;
508 : }
509 0 : std::this_thread::sleep_until(next_flag_check_time);
510 0 : next_flag_check_time = next_flag_check_time + flag_check_period;
511 : }
512 0 : if (break_flag == false) {
513 0 : std::this_thread::sleep_until(next_clean_time);
514 : }
515 : }
516 0 : TLOG_DEBUG(0) << "Exiting clean_endpoint_scan_threads()";
517 0 : }
518 :
519 : // master commands
520 : void
521 0 : TimingHardwareManagerBase::set_endpoint_delay(const timingcmd::TimingHwCmd& hw_cmd)
522 : {
523 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " set endpoint delay";
524 :
525 0 : timingcmd::TimingMasterSetEndpointDelayCmdPayload cmd_payload;
526 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
527 :
528 0 : auto design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
529 0 : design->apply_endpoint_delay(cmd_payload.address,
530 : cmd_payload.coarse_delay,
531 : cmd_payload.fine_delay,
532 : cmd_payload.phase_delay,
533 0 : cmd_payload.measure_rtt,
534 0 : cmd_payload.control_sfp,
535 : cmd_payload.sfp_mux);
536 0 : }
537 :
538 : void
539 0 : TimingHardwareManagerBase::send_fl_cmd(const timingcmd::TimingHwCmd& hw_cmd)
540 : {
541 0 : timingcmd::TimingMasterSendFLCmdCmdPayload cmd_payload;
542 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
543 :
544 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " send fl cmd. Payload: " << hw_cmd.payload.dump()
545 0 : << ", parsed data: " << cmd_payload.fl_cmd_id << ", " << cmd_payload.channel << ", "
546 0 : << cmd_payload.number_of_commands_to_send;
547 :
548 0 : auto design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
549 0 : design->get_master_node_plain()->send_fl_cmd(
550 : cmd_payload.fl_cmd_id, cmd_payload.channel, cmd_payload.number_of_commands_to_send);
551 0 : }
552 :
553 : // endpoint commands
554 : void
555 0 : TimingHardwareManagerBase::endpoint_enable(const timingcmd::TimingHwCmd& hw_cmd)
556 : {
557 0 : timingcmd::TimingEndpointConfigureCmdPayload cmd_payload;
558 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
559 :
560 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " ept enable, adr: " << cmd_payload.address
561 0 : << ", part: " << cmd_payload.partition;
562 :
563 0 : auto design = get_timing_device<const timing::EndpointDesignInterface*>(hw_cmd.device);
564 0 : design->get_endpoint_node_plain(cmd_payload.endpoint_id)->enable(cmd_payload.address, cmd_payload.partition);
565 0 : }
566 :
567 : void
568 0 : TimingHardwareManagerBase::endpoint_disable(const timingcmd::TimingHwCmd& hw_cmd)
569 : {
570 0 : timingcmd::TimingEndpointCmdPayload cmd_payload;
571 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
572 :
573 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " ept disable";
574 :
575 0 : auto design = get_timing_device<const timing::EndpointDesignInterface*>(hw_cmd.device);
576 0 : design->get_endpoint_node_plain(cmd_payload.endpoint_id)->disable();
577 0 : }
578 :
579 : void
580 0 : TimingHardwareManagerBase::endpoint_reset(const timingcmd::TimingHwCmd& hw_cmd)
581 : {
582 0 : timingcmd::TimingEndpointConfigureCmdPayload cmd_payload;
583 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
584 :
585 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " ept reset, adr: " << cmd_payload.address
586 0 : << ", part: " << cmd_payload.partition;
587 :
588 0 : auto design = get_timing_device<const timing::EndpointDesignInterface*>(hw_cmd.device);
589 0 : design->get_endpoint_node_plain(cmd_payload.endpoint_id)->reset(cmd_payload.address, cmd_payload.partition);
590 0 : }
591 :
592 : // hsi commands
593 : void
594 0 : TimingHardwareManagerBase::hsi_reset(const timingcmd::TimingHwCmd& hw_cmd)
595 : {
596 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi reset";
597 :
598 0 : auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
599 0 : design->get_hsi_node().reset_hsi();
600 0 : }
601 :
602 : void
603 0 : TimingHardwareManagerBase::hsi_configure(const timingcmd::TimingHwCmd& hw_cmd)
604 : {
605 0 : timingcmd::HSIConfigureCmdPayload cmd_payload;
606 0 : timingcmd::from_json(hw_cmd.payload, cmd_payload);
607 :
608 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi configure";
609 :
610 0 : auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
611 0 : design->configure_hsi(cmd_payload.data_source,
612 : cmd_payload.rising_edge_mask,
613 : cmd_payload.falling_edge_mask,
614 : cmd_payload.invert_edge_mask,
615 : cmd_payload.random_rate);
616 0 : }
617 :
618 : void
619 0 : TimingHardwareManagerBase::hsi_start(const timingcmd::TimingHwCmd& hw_cmd)
620 : {
621 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi start";
622 :
623 0 : auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
624 0 : design->get_hsi_node().start_hsi();
625 0 : }
626 :
627 : void
628 0 : TimingHardwareManagerBase::hsi_stop(const timingcmd::TimingHwCmd& hw_cmd)
629 : {
630 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi stop";
631 :
632 0 : auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
633 0 : design->get_hsi_node().stop_hsi();
634 0 : }
635 :
636 : void
637 0 : TimingHardwareManagerBase::hsi_print_status(const timingcmd::TimingHwCmd& hw_cmd)
638 : {
639 0 : TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi print status";
640 :
641 0 : auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
642 0 : TLOG() << std::endl << design->get_hsi_node().get_status();
643 0 : }
644 :
645 : } // namespace timinglibs
646 : } // namespace dunedaq
|