Line data Source code
1 : /**
2 : * @file IONode.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/IONode.hpp"
10 :
11 : #include "logging/Logging.hpp"
12 :
13 : #include <map>
14 : #include <memory>
15 : #include <string>
16 : #include <utility>
17 : #include <vector>
18 :
19 : namespace dunedaq {
20 : namespace timing {
21 :
22 : // UHAL_REGISTER_DERIVED_NODE(IONode);
23 :
24 : //-----------------------------------------------------------------------------
25 0 : IONode::IONode(const uhal::Node& node,
26 : std::string uid_i2c_bus,
27 : std::string pll_i2c_bus,
28 : std::string pll_i2c_device,
29 : std::vector<std::string> clock_names,
30 0 : std::vector<std::string> sfp_i2c_buses)
31 : : TimingNode(node)
32 0 : , m_uid_i2c_bus(uid_i2c_bus)
33 0 : , m_pll_i2c_bus(pll_i2c_bus)
34 0 : , m_pll_i2c_device(pll_i2c_device)
35 0 : , m_clock_names(clock_names)
36 0 : , m_sfp_i2c_buses(sfp_i2c_buses)
37 : // mPLL (new SI534xSlave( getNode<I2CMasterNode>(m_pll_i2c_bus)& ,
38 : // getNode<I2CMasterNode>(m_pll_i2c_bus).get_slave_address(pll_i2c_device) ))
39 0 : {}
40 : //-----------------------------------------------------------------------------
41 :
42 : //-----------------------------------------------------------------------------
43 0 : IONode::~IONode() {}
44 : //-----------------------------------------------------------------------------
45 :
46 : //-----------------------------------------------------------------------------
47 : uint32_t // NOLINT(build/unsigned)
48 0 : IONode::read_board_type() const
49 : {
50 0 : uhal::ValWord<uint32_t> board_type = getNode("config.board_type").read(); // NOLINT(build/unsigned)
51 0 : getClient().dispatch();
52 0 : return board_type.value();
53 0 : }
54 : //-----------------------------------------------------------------------------
55 :
56 : //-----------------------------------------------------------------------------
57 : uint32_t // NOLINT(build/unsigned)
58 0 : IONode::read_carrier_type() const
59 : {
60 0 : uhal::ValWord<uint32_t> carrier_type = getNode("config.carrier_type").read(); // NOLINT(build/unsigned)
61 0 : getClient().dispatch();
62 0 : return carrier_type.value();
63 0 : }
64 : //-----------------------------------------------------------------------------
65 :
66 : //-----------------------------------------------------------------------------
67 : uint32_t // NOLINT(build/unsigned)
68 0 : IONode::read_design_type() const
69 : {
70 0 : uhal::ValWord<uint32_t> design_type = getNode("config.design_type").read(); // NOLINT(build/unsigned)
71 0 : getClient().dispatch();
72 0 : return design_type.value();
73 0 : }
74 : //-----------------------------------------------------------------------------
75 :
76 : //-----------------------------------------------------------------------------
77 : uint32_t // NOLINT(build/unsigned)
78 0 : IONode::read_firmware_frequency() const
79 : {
80 0 : uhal::ValWord<uint32_t> firmware_frequency = getNode("config.clock_frequency").read(); // NOLINT(build/unsigned)
81 0 : getClient().dispatch();
82 0 : return firmware_frequency.value();
83 0 : }
84 : //-----------------------------------------------------------------------------
85 :
86 : //-----------------------------------------------------------------------------
87 : uint64_t // NOLINT(build/unsigned)
88 0 : IONode::read_board_uid() const
89 : {
90 :
91 0 : uint64_t uid = 0; // NOLINT(build/unsigned)
92 0 : std::vector<uint8_t> uid_values = // NOLINT(build/unsigned)
93 0 : getNode<I2CMasterNode>(m_uid_i2c_bus).get_slave(get_uid_address_parameter_name()).read_i2cArray(0xfa, 6);
94 :
95 0 : for (uint8_t i = 0; i < uid_values.size(); ++i) { // NOLINT(build/unsigned)
96 0 : uid = (uid << 8) | uid_values.at(i);
97 : }
98 0 : return uid;
99 0 : }
100 : //-----------------------------------------------------------------------------
101 :
102 : //-----------------------------------------------------------------------------
103 : BoardRevision
104 0 : IONode::get_board_revision() const
105 : {
106 0 : auto uid = read_board_uid();
107 0 : try {
108 0 : return get_board_uid_revision_map().at(uid);
109 0 : } catch (const std::out_of_range& e) {
110 0 : ers::warning(UnknownBoardUID(ERS_HERE, format_reg_value(uid), e));
111 0 : return kBoardRevisionUnknown;
112 0 : }
113 : }
114 : //-----------------------------------------------------------------------------
115 :
116 : //-----------------------------------------------------------------------------
117 : std::string
118 0 : IONode::get_hardware_info(bool print_out) const
119 : {
120 0 : std::stringstream info;
121 0 : const BoardType board_type = convert_value_to_board_type(read_board_type());
122 0 : const BoardRevision board_revision = get_board_revision();
123 0 : const CarrierType carrier_type = convert_value_to_carrier_type(read_carrier_type());
124 0 : const DesignType design_type = convert_value_to_design_type(read_design_type());
125 0 : const double firmware_frequency = read_firmware_frequency()/1e6;
126 :
127 0 : std::vector<std::pair<std::string, std::string>> hardware_info;
128 :
129 0 : try {
130 0 : hardware_info.push_back(std::make_pair("Board type", get_board_type_map().at(board_type)));
131 0 : } catch (const std::out_of_range& e) {
132 0 : ers::error(MissingBoardTypeMapEntry(ERS_HERE, format_reg_value(board_type), e));
133 0 : }
134 :
135 0 : try {
136 0 : hardware_info.push_back(std::make_pair("Board revision", get_board_revision_map().at(board_revision)));
137 0 : } catch (const std::out_of_range& e) {
138 0 : ers::error(MissingBoardRevisionMapEntry(ERS_HERE, format_reg_value(board_revision), e));
139 0 : }
140 :
141 0 : hardware_info.push_back(std::make_pair("Board UID", format_reg_value(read_board_uid())));
142 :
143 0 : try {
144 0 : hardware_info.push_back(std::make_pair("Carrier type", get_carrier_type_map().at(carrier_type)));
145 0 : } catch (const std::out_of_range& e) {
146 0 : ers::error(MissingCarrierTypeMapEntry(ERS_HERE, format_reg_value(carrier_type), e));
147 0 : }
148 :
149 0 : try {
150 0 : hardware_info.push_back(std::make_pair("Design type", get_design_type_map().at(design_type)));
151 0 : } catch (const std::out_of_range& e) {
152 0 : ers::error(MissingDesignTypeMapEntry(ERS_HERE, format_reg_value(design_type), e));
153 0 : }
154 :
155 0 : hardware_info.push_back(std::make_pair("Firmware frequency [MHz]", std::to_string(firmware_frequency)));
156 :
157 0 : info << format_reg_table(hardware_info, "Hardware info", { "", "" });
158 :
159 0 : if (print_out)
160 0 : TLOG() << info.str();
161 0 : return info.str();
162 0 : }
163 : //-----------------------------------------------------------------------------
164 :
165 : //-----------------------------------------------------------------------------
166 : std::string
167 0 : IONode::get_full_clock_config_file_path(const ClockSource& clock_source) const
168 : {
169 0 : std::string config_file;
170 0 : std::stringstream clock_config_key;
171 :
172 0 : const BoardType board_type = convert_value_to_board_type(read_board_type());
173 : // const BoardRevision board_revision = get_board_revision();
174 0 : const CarrierType carrier_type = convert_value_to_carrier_type(read_carrier_type());
175 0 : const DesignType design_type = convert_value_to_design_type(read_design_type());
176 : //const uint32_t firmware_frequency = read_firmware_frequency(); // NOLINT(build/unsigned)
177 :
178 0 : try {
179 0 : clock_config_key << get_board_type_map().at(board_type) << "_";
180 0 : } catch (const std::out_of_range& e) {
181 0 : throw MissingBoardTypeMapEntry(ERS_HERE, format_reg_value(board_type), e);
182 0 : }
183 :
184 0 : auto pll = get_pll();
185 0 : auto pll_model = pll->read_device_version();
186 0 : clock_config_key << std::hex << pll_model;
187 :
188 : // try {
189 : // clock_config_key = clock_config_key + get_carrier_type_map().at(carrier_type) + "_";
190 : // } catch (const std::out_of_range& e) {
191 : // throw MissingCarrierTypeMapEntry(ERS_HERE, format_reg_value(carrier_type), e);
192 : // }
193 :
194 0 : try {
195 0 : clock_config_key << "_" << get_design_type_map().at(design_type);
196 0 : } catch (const std::out_of_range& e) {
197 0 : throw MissingDesignTypeMapEntry(ERS_HERE, format_reg_value(design_type), e);
198 0 : }
199 :
200 0 : clock_config_key << "_" << clock_source_to_string(clock_source);
201 :
202 0 : TLOG_DEBUG(0) << "Using pll config key: " << clock_config_key.str();
203 :
204 0 : try {
205 0 : config_file = get_clock_config_map().at(clock_config_key.str());
206 0 : } catch (const std::out_of_range& e) {
207 0 : throw ClockConfigNotFound(ERS_HERE, clock_config_key.str(), e);
208 0 : }
209 :
210 0 : TLOG_DEBUG(0) << "PLL config file: " << config_file << " from key: " << clock_config_key.str();
211 :
212 0 : const char* env_var_char = std::getenv("TIMING_SHARE");
213 :
214 0 : if (env_var_char == nullptr) {
215 0 : throw EnvironmentVariableNotSet(ERS_HERE, "TIMING_SHARE");
216 : }
217 :
218 0 : std::string env_var(env_var_char);
219 :
220 0 : std::string full_pll_config_file_path = env_var + "/config/etc/clock/" + config_file;
221 :
222 0 : TLOG_DEBUG(0) << "Full PLL config file path: " << full_pll_config_file_path;
223 :
224 0 : return full_pll_config_file_path;
225 0 : }
226 : //-----------------------------------------------------------------------------
227 :
228 : //-----------------------------------------------------------------------------
229 : std::unique_ptr<const SI534xSlave>
230 0 : IONode::get_pll() const
231 : {
232 0 : return get_i2c_device<SI534xSlave>(m_pll_i2c_bus, m_pll_i2c_device);
233 : }
234 : //-----------------------------------------------------------------------------
235 :
236 : //-----------------------------------------------------------------------------
237 : void
238 0 : IONode::configure_pll(const std::string& clock_config_file) const
239 : {
240 0 : auto pll = get_pll();
241 :
242 0 : TLOG() << "PLL configuration file : " << clock_config_file;
243 :
244 0 : uint32_t si_pll_version = pll->read_device_version(); // NOLINT(build/unsigned)
245 0 : TLOG_DEBUG(0) << "Configuring PLL : SI" << format_reg_value(si_pll_version);
246 :
247 0 : pll->configure(clock_config_file);
248 :
249 0 : TLOG_DEBUG(0) << "PLL configuration id : " << pll->read_config_id();
250 0 : }
251 : //-----------------------------------------------------------------------------
252 :
253 : //-----------------------------------------------------------------------------
254 : std::vector<double>
255 0 : IONode::read_clock_frequencies() const
256 : {
257 0 : return getNode<FrequencyCounterNode>("freq").measure_frequencies(m_clock_names.size());
258 : }
259 : //-----------------------------------------------------------------------------
260 :
261 : //-----------------------------------------------------------------------------
262 : std::string
263 0 : IONode::get_clock_frequencies_table(bool print_out) const
264 : {
265 0 : std::stringstream table;
266 0 : std::vector<double> frequencies = read_clock_frequencies();
267 0 : for (uint8_t i = 0; i < frequencies.size(); ++i) { // NOLINT(build/unsigned)
268 0 : table << m_clock_names.at(i) << " freq: " << std::setprecision(12) << frequencies.at(i) << std::endl;
269 : }
270 : // TODO add freq validation Stoyan Trilov stoyan.trilov@cern.ch
271 0 : if (print_out)
272 0 : TLOG() << table.str();
273 0 : return table.str();
274 0 : }
275 : //-----------------------------------------------------------------------------
276 :
277 : //-----------------------------------------------------------------------------
278 : std::string
279 0 : IONode::get_pll_status(bool print_out) const
280 : {
281 0 : return get_pll()->get_status(print_out);
282 : }
283 : //-----------------------------------------------------------------------------
284 :
285 : //-----------------------------------------------------------------------------
286 : void
287 0 : IONode::write_soft_reset_register() const
288 : {
289 0 : getNode("csr.ctrl.soft_rst").write(0x1);
290 0 : getClient().dispatch();
291 0 : }
292 : //-----------------------------------------------------------------------------
293 :
294 : //-----------------------------------------------------------------------------
295 : void
296 0 : IONode::soft_reset() const
297 : {
298 0 : write_soft_reset_register();
299 0 : TLOG_DEBUG(0) << "Soft reset done";
300 0 : }
301 : //-----------------------------------------------------------------------------
302 :
303 : //-----------------------------------------------------------------------------
304 : void
305 0 : IONode::reset(const ClockSource& clock_source) const
306 : {
307 0 : TLOG() << "Setting IO preliminaries: I2C access, etc..";
308 0 : set_up_io_infrastructure();
309 :
310 : // Find the right pll config file
311 0 : std::string clock_config = get_full_clock_config_file_path(clock_source);
312 0 : reset(clock_config);
313 0 : }
314 : //-----------------------------------------------------------------------------
315 :
316 : //-----------------------------------------------------------------------------
317 : std::string
318 0 : IONode::get_sfp_status(uint32_t sfp_id, bool print_out) const // NOLINT(build/unsigned)
319 : {
320 0 : std::stringstream status;
321 0 : std::string sfp_i2c_bus;
322 0 : try {
323 0 : sfp_i2c_bus = m_sfp_i2c_buses.at(sfp_id);
324 0 : } catch (const std::out_of_range& e) {
325 0 : throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id), e);
326 0 : }
327 0 : auto sfp = get_i2c_device<I2CSFPSlave>(sfp_i2c_bus, "SFP_EEProm");
328 0 : status << sfp->get_status();
329 0 : if (print_out)
330 0 : TLOG() << status.str();
331 0 : return status.str();
332 0 : }
333 : //-----------------------------------------------------------------------------
334 :
335 : //-----------------------------------------------------------------------------
336 : void
337 0 : IONode::switch_sfp_soft_tx_control_bit(uint32_t sfp_id, bool turn_on) const // NOLINT(build/unsigned)
338 : {
339 0 : std::string sfp_i2c_bus;
340 0 : try {
341 0 : sfp_i2c_bus = m_sfp_i2c_buses.at(sfp_id);
342 0 : } catch (const std::out_of_range& e) {
343 0 : throw InvalidSFPId(ERS_HERE, format_reg_value(sfp_id), e);
344 0 : }
345 0 : auto sfp = get_i2c_device<I2CSFPSlave>(sfp_i2c_bus, "SFP_EEProm");
346 0 : sfp->switch_soft_tx_control_bit(turn_on);
347 0 : }
348 : //-----------------------------------------------------------------------------
349 :
350 : } // namespace timing
351 : } // namespace dunedaq
|