LCOV - code coverage report
Current view: top level - timing/src - SI534xNode.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 207 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 23 0

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

Generated by: LCOV version 2.0-1