DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
SI534xNode.cpp
Go to the documentation of this file.
1
10
11// PDT headers
12#include "ers/ers.hpp"
13#include "logging/Logging.hpp"
14
15#include "timing/toolbox.hpp"
16
17#include <boost/algorithm/string/predicate.hpp>
18#include <boost/tuple/tuple.hpp>
19
20#include <chrono>
21#include <fstream>
22#include <map>
23#include <sstream>
24#include <string>
25#include <thread>
26#include <vector>
27
28namespace dunedaq {
29namespace timing {
30
31// uHAL Node registation
32UHAL_REGISTER_DERIVED_NODE(SI534xNode)
33
34//-----------------------------------------------------------------------------
35SI534xSlave::SI534xSlave(const I2CMasterNode* i2c_master, uint8_t address) // NOLINT(build/unsigned)
36 : SIChipSlave(i2c_master, address)
37{}
38//-----------------------------------------------------------------------------
39
40//-----------------------------------------------------------------------------
41SI534xSlave::~SI534xSlave() {}
42//-----------------------------------------------------------------------------
43
44//-----------------------------------------------------------------------------
45std::string
46SI534xSlave::read_config_id() const
47{
48 std::string id;
49
50 for (size_t i(0); i < 8; ++i) {
51 char id_char = static_cast<char>(read_clock_register(0x26b + i));
52 // in case null paddding was used for spaces
53 if (id_char == '\0')
54 {
55 id += ' ';
56 }
57 else
58 {
59 id += id_char;
60 }
61 }
62 return id;
63}
64//-----------------------------------------------------------------------------
65
66//-----------------------------------------------------------------------------
67std::string
68SI534xSlave::seek_header(std::ifstream& file) const
69{
70
71 // std::string config_line;
72 std::string design_id;
73
74 std::string config_line;
75 uint32_t line_number; // NOLINT(build/unsigned)
76 for (line_number = 1; std::getline(file, config_line); ++line_number) {
77
78 // Gracefully deal with those damn dos-encoded files
79 if (config_line.back() == '\r')
80 config_line.pop_back();
81
82 // Section end found. Break here
83 if (boost::starts_with(config_line, "# Design ID:")) {
84 design_id = config_line.substr(13);
85 }
86
87 // Skip comments
88 if (config_line[0] == '#')
89 continue;
90
91 // Stop if the line is empty
92 if (config_line.length() == 0)
93 continue;
94
95 // OK, header found, stop here
96 if (config_line == "Address,Data")
97 break;
98
99 if (file.eof()) {
100 throw SI534xConfigError(ERS_HERE, "Incomplete file: End of file detected while seeking the header.");
101 }
102 }
103
104 TLOG_DEBUG(8) << "Found desing ID " << design_id;
105
106 return design_id;
107}
108
109//-----------------------------------------------------------------------------
110// Seek Header
111// Seek conf start
112// read data
113// Stop on conf end
114
115std::vector<SI534xSlave::RegisterSetting_t>
116SI534xSlave::read_config_section(std::ifstream& file, std::string tag) const
117{
118
119 // Line buffer
120 // std::string config_line;
121
122 bool section_found(false);
123
124 std::vector<RegisterSetting_t> config;
125 std::string config_line;
126 uint32_t line_number; // NOLINT(build/unsigned)
127 for (line_number = 1; std::getline(file, config_line); ++line_number) {
128
129 // Gracefully deal with those damn dos-encoded files
130 if (config_line.back() == '\r')
131 config_line.pop_back();
132
133 // Is it a comment
134 if (config_line[0] == '#') {
135
136 if (tag.empty())
137 continue;
138
139 if (boost::starts_with(config_line, "# Start configuration " + tag)) {
140 section_found = true;
141 }
142
143 // Section end found. Break here
144 if (boost::starts_with(config_line, "# End configuration " + tag)) {
145 break;
146 }
147
148 continue;
149 }
150
151 // Oops
152 if (file.eof()) {
153 if (tag.empty())
154 return config;
155 else
156 throw SI534xConfigError(ERS_HERE,
157 "Incomplete file: End of file detected before the end of " + tag + " section.");
158 }
159
160 // Stop if the line is empty
161 if (config_line.length() == 0)
162 continue;
163
164 // If no sec
165 if (!section_found && !tag.empty()) {
167 }
168
169 uint32_t address, data; // NOLINT(build/unsigned)
170 char dummy;
171
172 std::istringstream line_stream(config_line);
173 line_stream >> std::hex >> address >> dummy >> std::hex >> data;
174
175 std::stringstream debug_stream;
176 debug_stream << std::showbase << std::hex << "Address: " << address << dummy << " Data: " << data;
177 TLOG_DEBUG(8) << debug_stream.str();
178
179 config.push_back(RegisterSetting_t(address, data));
180 }
181
182 return config;
183}
184//-----------------------------------------------------------------------------
185
186//-----------------------------------------------------------------------------
187void
188SI534xSlave::configure(const std::string& filename) const
189{
190
192
193 std::ifstream config_file(filename);
194 std::string config_line;
195 std::string conf_design_id;
196
197 // Seek the header line first
198 conf_design_id = seek_header(config_file);
199 std::ifstream::pos_type header_end = config_file.tellg();
200
201 // auto preamble = this->read_config_section(config_file, "preamble");
202 // TIMING_LOG(kDebug) << "Preamble size = " << preamble.size();
203 // auto registers = this->read_config_section(config_file, "registers");
204 // TIMING_LOG(kDebug) << "Registers size = " << registers.size();
205 // auto postamble = this->read_config_section(config_file, "postamble");
206 // TIMING_LOG(kDebug) << "PostAmble size = " << postamble.size();
207
208 std::vector<SI534xSlave::RegisterSetting_t> preamble, registers, postamble;
209
210 try {
211 preamble = this->read_config_section(config_file, "preamble");
212 registers = this->read_config_section(config_file, "registers");
213 postamble = this->read_config_section(config_file, "postamble");
214 } catch (SI534xMissingConfigSectionError&) {
215 config_file.seekg(header_end);
216 preamble.clear();
217 registers = this->read_config_section(config_file, "");
218 postamble.clear();
219 }
220
221 TLOG_DEBUG(8) << "Preamble size = " << preamble.size();
222 TLOG_DEBUG(8) << "Registers size = " << registers.size();
223 TLOG_DEBUG(8) << "PostAmble size = " << postamble.size();
224
225 config_file.close();
226
227 try {
228 this->write_clock_register(0x1E, 0x2);
229 } catch (timing::I2CException& excp) {
230 // Do nothing.
231 }
232
233 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
234
235 this->upload_config(preamble);
236 std::this_thread::sleep_for(std::chrono::milliseconds(300));
237 this->upload_config(registers);
238 this->upload_config(postamble);
239
240 std::string chip_design_id = this->read_config_id();
241
242 if (conf_design_id != chip_design_id) {
243 std::ostringstream message;
244 message << "Post-configuration check failed: Loaded design ID " << chip_design_id
245 << " does not match the configurationd design id " << conf_design_id << std::endl;
246 ers::error(SI534xConfigError(ERS_HERE, message.str()));
247 }
248}
249//-----------------------------------------------------------------------------
250
251//-----------------------------------------------------------------------------
252void
253SI534xSlave::upload_config(const std::vector<SI534xSlave::RegisterSetting_t>& config) const
254{
255
256 size_t k(0), notify_percent(10);
257 size_t notify_every = (notify_percent < config.size() ? config.size() / notify_percent : 1);
258
259 for (const auto& setting : config) {
260 std::stringstream debug_stream;
261 debug_stream << std::showbase << std::hex << "Writing to " << (uint32_t)setting.get<0>() // NOLINT(build/unsigned)
262 << " data " << (uint32_t)setting.get<1>(); // NOLINT(build/unsigned)
263 TLOG_DEBUG(9) << debug_stream.str();
264
265 uint32_t max_attempts(2), attempt(0); // NOLINT(build/unsigned)
266 while (attempt < max_attempts) {
267 TLOG_DEBUG(9) << "Attempt " << attempt;
268 if (attempt > 0) {
270 format_reg_value(attempt, 10),
271 format_reg_value((uint32_t)setting.get<0>()))); // NOLINT(build/unsigned)
272 }
273 try {
274 this->write_clock_register(setting.get<0>(), setting.get<1>());
275 } catch (const std::exception& e) {
276 ers::error(SI534xRegWriteFailed(ERS_HERE,
277 format_reg_value((uint32_t)setting.get<0>()), // NOLINT(build/unsigned)
278 format_reg_value((uint32_t)setting.get<1>()), // NOLINT(build/unsigned)
279 e));
280 ++attempt;
281 continue;
282 }
283 break;
284 }
285
286 ++k;
287 if ((k % notify_every) == 0) {
288 TLOG_DEBUG(9) << (k / notify_every) * notify_percent << "%";
289 }
290 }
291}
292//-----------------------------------------------------------------------------
293
294//-----------------------------------------------------------------------------
295std::map<uint16_t, uint8_t> // NOLINT(build/unsigned)
296SI534xSlave::registers() const
297{
298 // boost::format fmthex("%d");
299 std::map<uint16_t, uint8_t> values; // NOLINT(build/unsigned)
300
301 for (uint8_t reg_addr = 0xc; reg_addr <= 0x12; reg_addr++) { // NOLINT(build/unsigned)
302 if (reg_addr > 0xf && reg_addr < 0x11) {
303 continue;
304 }
305
306 // if( reg_addr > 25 && reg_addr < 31 ) {
307 // continue;
308 // }
309
310 // if( reg_addr > 36 && reg_addr < 40 ) {
311 // continue;
312 // }
313
314 // if( reg_addr > 48 && reg_addr < 55 ) {
315 // continue;
316 // }
317
318 // if( reg_addr > 55 && reg_addr < 128 ) {
319 // continue;
320 // }
321
322 // if( reg_addr == 133 ) {
323 // continue;
324 // }
325
326 // if( reg_addr == 137 ) {
327 // continue;
328 // }
329
330 // if( reg_addr > 139 && reg_addr < 142 ) {
331 // continue;
332 // }
333
334 values[reg_addr] = read_clock_register(reg_addr);
335 }
336
337 return values;
338}
339//-----------------------------------------------------------------------------
340
341//-----------------------------------------------------------------------------
342 void
343 SI534xSlave::get_info(timinghardwareinfo::TimingPLLMonitorData& mon_data) const
344 {
345 mon_data.config_id = this->read_config_id();
346
347 //lPLLVersion["Part number"] = pll->read_device_version();
348 //lPLLVersion["Device grade"] = pll->read_clock_register(0x4);
349 //lPLLVersion["Device revision"] = pll->read_clock_register(0x5);
350
351 uint8_t pll_reg_c = this->read_clock_register(0xc); // NOLINT(build/unsigned)
352 uint8_t pll_reg_d = this->read_clock_register(0xd); // NOLINT(build/unsigned)
353 uint8_t pll_reg_e = this->read_clock_register(0xe); // NOLINT(build/unsigned)
354 uint8_t pll_reg_f = this->read_clock_register(0xf); // NOLINT(build/unsigned)
355 uint8_t pll_reg_11 = this->read_clock_register(0x11); // NOLINT(build/unsigned)
356 uint8_t pll_reg_12 = this->read_clock_register(0x12); // NOLINT(build/unsigned)
357
358 mon_data.cal_pll = dec_rng(pll_reg_f, 5);
359 mon_data.hold = dec_rng(pll_reg_e, 5);
360 mon_data.lol = dec_rng(pll_reg_e, 1);
361 mon_data.los = dec_rng(pll_reg_d, 0, 4);
362 mon_data.los_xaxb = dec_rng(pll_reg_c, 1);
363 mon_data.los_xaxb_flg = dec_rng(pll_reg_11, 1);
364
365 mon_data.oof = dec_rng(pll_reg_d, 4, 4);
366 mon_data.oof_sticky = dec_rng(pll_reg_12, 4, 4);
367
368 mon_data.smbus_timeout = dec_rng(pll_reg_c, 5);
369 mon_data.smbus_timeout_flg = dec_rng(pll_reg_11, 5);
370
371 mon_data.sys_in_cal = dec_rng(pll_reg_c, 0);
372 mon_data.sys_in_cal_flg = dec_rng(pll_reg_11, 0);
373
374 mon_data.xaxb_err = dec_rng(pll_reg_c, 3);
375 mon_data.xaxb_err_flg = dec_rng(pll_reg_11, 3);
376 }
377//-----------------------------------------------------------------------------
378
379//-----------------------------------------------------------------------------
380std::string
381SI534xSlave::get_status(bool print_out) const
382{
383 std::stringstream status;
384 status << "PLL configuration id : " << this->read_config_id() << std::endl;
385
386 std::map<std::string, uint32_t> pll_version; // NOLINT(build/unsigned)
387 pll_version["Part number"] = this->read_device_version();
388 pll_version["Device grade"] = this->read_clock_register(0x4);
389 pll_version["Device revision"] = this->read_clock_register(0x5);
390
391 status << format_reg_table(pll_version, "PLL information") << std::endl;
392
393 std::map<std::string, uint32_t> pll_registers; // NOLINT(build/unsigned)
394
395 uint8_t pll_reg_c = this->read_clock_register(0xc); // NOLINT(build/unsigned)
396 uint8_t pll_reg_d = this->read_clock_register(0xd); // NOLINT(build/unsigned)
397 uint8_t pll_reg_e = this->read_clock_register(0xe); // NOLINT(build/unsigned)
398 uint8_t pll_reg_f = this->read_clock_register(0xf); // NOLINT(build/unsigned)
399 uint8_t pll_reg_11 = this->read_clock_register(0x11); // NOLINT(build/unsigned)
400 uint8_t pll_reg_12 = this->read_clock_register(0x12); // NOLINT(build/unsigned)
401
402 pll_registers["CAL_PLL"] = dec_rng(pll_reg_f, 5);
403 pll_registers["HOLD"] = dec_rng(pll_reg_e, 5);
404 pll_registers["LOL"] = dec_rng(pll_reg_e, 1);
405 pll_registers["LOS"] = dec_rng(pll_reg_d, 0, 4);
406 pll_registers["LOSXAXB"] = dec_rng(pll_reg_c, 1);
407 pll_registers["LOSXAXB_FLG"] = dec_rng(pll_reg_11, 1);
408
409 pll_registers["OOF"] = dec_rng(pll_reg_d, 4, 4);
410 pll_registers["OOF (sticky)"] = dec_rng(pll_reg_12, 4, 4);
411
412 pll_registers["SMBUS_TIMEOUT"] = dec_rng(pll_reg_c, 5);
413 pll_registers["SMBUS_TIMEOUT_FLG"] = dec_rng(pll_reg_11, 5);
414
415 pll_registers["SYSINCAL"] = dec_rng(pll_reg_c, 0);
416 pll_registers["SYSINCAL_FLG"] = dec_rng(pll_reg_11, 0);
417
418 pll_registers["XAXB_ERR"] = dec_rng(pll_reg_c, 3);
419 pll_registers["XAXB_ERR_FLG"] = dec_rng(pll_reg_11, 3);
420
421 status << format_reg_table(pll_registers, "PLL state");
422
423 if (print_out)
424 TLOG() << status.str();
425 return status.str();
426}
427//-----------------------------------------------------------------------------
428
429//-----------------------------------------------------------------------------
430SI534xNode::SI534xNode(const uhal::Node& node)
431 : I2CMasterNode(node)
432 , SI534xSlave(this, this->get_slave_address("i2caddr"))
433{}
434//-----------------------------------------------------------------------------
435
436//-----------------------------------------------------------------------------
437SI534xNode::SI534xNode(const SI534xNode& node)
438 : I2CMasterNode(node)
439 , SI534xSlave(this, this->get_slave_address("i2caddr"))
440{}
441//-----------------------------------------------------------------------------
442
443//-----------------------------------------------------------------------------
444SI534xNode::~SI534xNode() {}
445//-----------------------------------------------------------------------------
446
447} // namespace timing
448} // namespace dunedaq
#define ERS_HERE
OpenCode I2C interface to a ipbus node.
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
#define TLOG(...)
Definition macro.hpp:22
std::string format_reg_table(T data, std::string title, std::vector< std::string > headers)
Format reg-value table.
Definition toolbox.hxx:166
uint8_t dec_rng(uint8_t word, uint8_t ibit, uint8_t nbits=1)
Definition toolbox.cpp:167
void throw_if_not_file(const std::string &path)
Definition toolbox.cpp:147
std::string format_reg_value(T reg_value, uint32_t base)
Definition toolbox.hxx:117
Including Qt Headers.
SI534xMissingConfigSectionError
< Namespace
Missing configuration std::string tag SI534xRegWriteRetry
< Namespace
void warning(const Issue &issue)
Definition ers.hpp:115
void error(const Issue &issue)
Definition ers.hpp:81