Line data Source code
1 : /**
2 : * @file FLCmdGeneratorNode.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 "timing/FLCmdGeneratorNode.hpp"
10 :
11 : #include "timing/toolbox.hpp"
12 : #include "logging/Logging.hpp"
13 :
14 : #include <string>
15 : #include <vector>
16 :
17 : namespace dunedaq {
18 : namespace timing {
19 :
20 0 : UHAL_REGISTER_DERIVED_NODE(FLCmdGeneratorNode)
21 :
22 : //-----------------------------------------------------------------------------
23 0 : FLCmdGeneratorNode::FLCmdGeneratorNode(const uhal::Node& node)
24 0 : : TimingNode(node)
25 0 : {}
26 : //-----------------------------------------------------------------------------
27 :
28 : //-----------------------------------------------------------------------------
29 0 : FLCmdGeneratorNode::~FLCmdGeneratorNode() {}
30 : //-----------------------------------------------------------------------------
31 :
32 : //-----------------------------------------------------------------------------
33 : std::string
34 0 : FLCmdGeneratorNode::get_status(bool print_out) const
35 : {
36 0 : std::stringstream status;
37 0 : auto subnodes = read_sub_nodes(getNode("csr.stat"));
38 0 : status << format_reg_table(subnodes, "FL Cmd gen state");
39 0 : if (print_out)
40 0 : TLOG() << status.str();
41 0 : return status.str();
42 0 : }
43 : //-----------------------------------------------------------------------------
44 :
45 : //-----------------------------------------------------------------------------
46 : void
47 0 : FLCmdGeneratorNode::validate_command(uint32_t command) const // NOLINT(build/unsigned)
48 : {
49 0 : if (command > 0xff)
50 : {
51 0 : throw InvalidFixedLatencyCommand(ERS_HERE, command);
52 : }
53 0 : }
54 : //-----------------------------------------------------------------------------
55 :
56 : //-----------------------------------------------------------------------------
57 : void
58 0 : FLCmdGeneratorNode::validate_channel(uint32_t channel) const // NOLINT(build/unsigned)
59 : {
60 0 : if (channel > 0x4)
61 : {
62 0 : throw InvalidFixedLatencyCommandChannel(ERS_HERE, channel);
63 : }
64 0 : }
65 : //-----------------------------------------------------------------------------
66 :
67 : //-----------------------------------------------------------------------------
68 : void
69 0 : FLCmdGeneratorNode::send_fl_cmd(uint32_t command, // NOLINT(build/unsigned)
70 : uint32_t channel) const // NOLINT(build/unsigned)
71 : {
72 0 : validate_command(command);
73 0 : validate_channel(channel);
74 :
75 0 : getNode("sel").write(channel);
76 :
77 0 : reset_sub_nodes(getNode("chan_ctrl"));
78 :
79 0 : getNode("chan_ctrl.type").write(command);
80 0 : getNode("ctrl.force").write(0x1);
81 0 : getClient().dispatch();
82 :
83 0 : getNode("ctrl.force").write(0x0);
84 0 : getClient().dispatch();
85 0 : }
86 : //-----------------------------------------------------------------------------
87 :
88 : //-----------------------------------------------------------------------------
89 : void
90 0 : FLCmdGeneratorNode::enable_periodic_fl_cmd(uint32_t channel, // NOLINT(build/unsigned)
91 : double rate,
92 : bool poisson,
93 : uint32_t clock_frequency_hz) const
94 : {
95 0 : enable_periodic_fl_cmd(0x8+channel, channel, rate, poisson, clock_frequency_hz);
96 0 : }
97 : //-----------------------------------------------------------------------------
98 :
99 : //-----------------------------------------------------------------------------
100 : void
101 0 : FLCmdGeneratorNode::enable_periodic_fl_cmd(uint32_t command, // NOLINT(build/unsigned)
102 : uint32_t channel, // NOLINT(build/unsigned)
103 : double rate,
104 : bool poisson,
105 : uint32_t clock_frequency_hz) const
106 : {
107 0 : uint32_t divisor;
108 0 : uint32_t prescale;
109 0 : double actual_rate;
110 :
111 0 : parse_periodic_fl_cmd_rate(rate, clock_frequency_hz, actual_rate, divisor, prescale);
112 :
113 0 : TLOG() << "Requested rate, actual rate: " << rate << ", " << actual_rate;
114 0 : TLOG() << "prescale, divisor: " << prescale << ", " << divisor;
115 :
116 0 : std::stringstream trig_stream;
117 0 : trig_stream << "> Periodic rate for command 0x" << std::hex << command << ", on channel 0x" << channel
118 0 : << " set to " << std::setprecision(3) << std::scientific << actual_rate << " Hz";
119 0 : TLOG() << trig_stream.str();
120 :
121 0 : std::stringstream trigger_mode_stream;
122 0 : trigger_mode_stream << "> Trigger mode: ";
123 :
124 0 : if (poisson) {
125 0 : trigger_mode_stream << "poisson";
126 : } else {
127 0 : trigger_mode_stream << "periodic";
128 : }
129 0 : TLOG() << trigger_mode_stream.str();
130 0 : enable_periodic_fl_cmd(command, channel, divisor, prescale, poisson);
131 :
132 0 : }
133 : //-----------------------------------------------------------------------------
134 :
135 : //-----------------------------------------------------------------------------
136 : void
137 0 : FLCmdGeneratorNode::enable_periodic_fl_cmd(uint32_t channel, // NOLINT(build/unsigned)
138 : uint32_t divisor, // NOLINT(build/unsigned)
139 : uint32_t prescale, // NOLINT(build/unsigned)
140 : bool poisson) const
141 : {
142 0 : enable_periodic_fl_cmd(0x8+channel, channel, divisor, prescale, poisson);
143 0 : }
144 : //-----------------------------------------------------------------------------
145 :
146 : //-----------------------------------------------------------------------------
147 : void
148 0 : FLCmdGeneratorNode::enable_periodic_fl_cmd(uint32_t command, // NOLINT(build/unsigned)
149 : uint32_t channel, // NOLINT(build/unsigned)
150 : uint32_t divisor, // NOLINT(build/unsigned)
151 : uint32_t prescale, // NOLINT(build/unsigned)
152 : bool poisson) const
153 : {
154 0 : validate_command(command);
155 0 : validate_channel(channel);
156 :
157 0 : getNode("sel").write(channel);
158 :
159 0 : getNode("chan_ctrl.type").write(command);
160 0 : getNode("chan_ctrl.rate_div_d").write(divisor);
161 0 : getNode("chan_ctrl.rate_div_p").write(prescale);
162 0 : getNode("chan_ctrl.patt").write(poisson);
163 0 : getNode("chan_ctrl.en").write(1); // Start the command stream
164 0 : getClient().dispatch();
165 0 : }
166 : //-----------------------------------------------------------------------------
167 :
168 : //-----------------------------------------------------------------------------
169 : void
170 0 : FLCmdGeneratorNode::disable_fake_trigger(uint32_t channel) const // NOLINT(build/unsigned)
171 : {
172 0 : validate_channel(channel);
173 :
174 : // Clear the internal trigger generator.
175 0 : getNode("sel").write(channel);
176 0 : reset_sub_nodes(getNode("chan_ctrl"));
177 0 : TLOG() << "Fake trigger generator " << format_reg_value(channel) << " configuration cleared";
178 0 : }
179 : //------------------------------------------------------------------------------
180 :
181 : //------------------------------------------------------------------------------
182 : std::string
183 0 : FLCmdGeneratorNode::get_cmd_counters_table(bool print_out) const
184 : {
185 0 : std::stringstream counters_table;
186 0 : auto accepted_counters = getNode("actrs").readBlock(getNode("actrs").getSize());
187 0 : auto rejected_counters = getNode("rctrs").readBlock(getNode("actrs").getSize());
188 0 : getClient().dispatch();
189 :
190 0 : std::vector<uhal::ValVector<uint32_t>> counters_container = { accepted_counters, rejected_counters }; // NOLINT(build/unsigned)
191 :
192 0 : counters_table << format_counters_table(counters_container,
193 : { "Accept counters", "Reject counters" },
194 : "Cmd gen counters",
195 : { "0x0", "0x1", "0x2", "0x3", "0x4" },
196 0 : "Chan");
197 :
198 0 : if (print_out)
199 0 : TLOG() << counters_table.str();
200 0 : return counters_table.str();
201 0 : }
202 : //-----------------------------------------------------------------------------
203 :
204 : //-----------------------------------------------------------------------------
205 : // void
206 : // FLCmdGeneratorNode::get_info(opmonlib::InfoCollector& ic, int /*level*/) const
207 : // {
208 : // auto accepted_counters = getNode("actrs").readBlock(getNode("actrs").getSize());
209 : // auto rejected_counters = getNode("rctrs").readBlock(getNode("actrs").getSize());
210 : // getClient().dispatch();
211 :
212 : // uint number_of_channels = 5;
213 :
214 : // for (uint i = 0; i < number_of_channels; ++i) { // NOLINT(build/unsigned)
215 :
216 : // timingfirmwareinfo::TimingFLCmdCounter cmd_counter;
217 : // opmonlib::InfoCollector cmd_counter_ic;
218 :
219 : // cmd_counter.accepted = accepted_counters.at(i);
220 : // cmd_counter.rejected = rejected_counters.at(i);
221 :
222 : // std::string channel = "fl_cmd_channel_" + std::to_string(i);
223 :
224 : // cmd_counter_ic.add(cmd_counter);
225 : // ic.add(channel, cmd_counter_ic);
226 : // }
227 : // }
228 : //-----------------------------------------------------------------------------
229 :
230 : //-----------------------------------------------------------------------------
231 0 : void FLCmdGeneratorNode::parse_periodic_fl_cmd_rate(double requested_rate,
232 : uint32_t clock_frequency_hz,
233 : double& actual_rate,
234 : uint32_t& divisor,
235 : uint32_t& prescale)
236 : {
237 : // Rate = (clock_frequency_hz / 2^(d+8)) / p where n in [0,15] and p in [1,256]
238 :
239 : // DIVIDER (int): Frequency divider.
240 :
241 : // The division from clock_frequency_hz to the desired rate is done in three steps:
242 : // a) A pre-division by 256
243 : // b) Division by a power of two set by n = 2 ^ rate_div_d (ranging from 2^0 -> 2^15)
244 : // c) 1-in-n prescaling set by n = rate_div_p
245 :
246 0 : double div = ceil(log(clock_frequency_hz / (requested_rate * 256 * 256)) / log(2));
247 0 : if (div < 0) {
248 0 : divisor = 0;
249 0 : } else if (div > 15) {
250 0 : divisor = 15;
251 : } else {
252 0 : divisor = div;
253 : }
254 :
255 0 : uint32_t ps = (uint32_t)((clock_frequency_hz / (requested_rate * 256 * (1 << divisor))) + 0.5); // NOLINT(build/unsigned)
256 0 : if (ps == 0 || ps > 256)
257 : {
258 0 : throw BadRequestedFakeTriggerRate(ERS_HERE, requested_rate, ps);
259 : } else {
260 0 : prescale = ps;
261 : }
262 0 : actual_rate = static_cast<double>(clock_frequency_hz) / (256 * prescale * (1 << divisor));
263 0 : }
264 : //-----------------------------------------------------------------------------
265 :
266 : } // namespace timing
267 : } // namespace dunedaq
|