Program Listing for File hardware_monitor_backend.hpp
↰ Return to documentation for file (hardware_monitor_backend.hpp
)
#ifndef HW_MON_BACKEND_H_
#define HW_MON_BACKEND_H_
#include <cstdint>
#include <memory>
#include <vector>
#include <fstream>
#include <nlohmann/json.hpp>
#include "flxcard/FlxCard.h"
#include "nlohmann/json_fwd.hpp"
#include "regmap_manager.hpp"
#include "util.hpp"
#include "log.hpp"
template <class DEV>
class HwMonBackend
{
public:
using device_pair = std::pair<std::shared_ptr<DEV>, std::shared_ptr<DEV>>;
HwMonBackend(const std::vector<device_pair> & device_pairs, const std::string& extras_file);
std::string get_monitor_data();
private:
std::vector<device_pair> m_device_pairs;
std::vector<std::string> m_extra_registers;
std::vector<unsigned int> m_mon_masks;
nlohmann::json m_msg;
RegmapManager m_register_checker;
void card_monitor_data();
nlohmann::json link_alignment(std::shared_ptr<DEV> primary);
unsigned int make_mon_mask(unsigned int model);
nlohmann::json mondata_json(const monitoring_data_t& mondata);
nlohmann::json regdata_json(std::shared_ptr<DEV> d0, std::shared_ptr<DEV> d1);
};
template <class DEV>
HwMonBackend<DEV>::HwMonBackend(const std::vector<HwMonBackend<DEV>::device_pair> & device_pairs, const std::string& extras_file)
: m_device_pairs(device_pairs)
{
//determine mask depending on card type
for (auto & p : m_device_pairs){
unsigned int model = p.first->get_card_model();
m_mon_masks.emplace_back(make_mon_mask(model));
}
//extra registers
if (!extras_file.empty()){
std::ifstream extras;
extras.open(extras_file);
for( std::string line; getline( extras, line ); ){
if(m_register_checker.can_read(line)) {
m_extra_registers.emplace_back(line);
LOG_INFO("Register %s added to hardware monitoring.", line.c_str());
} else {
LOG_ERR("Requested register %s does not exist in the register map. Ignored.", line.c_str());
}
}
extras.close();
}
}
template <class DEV>
std::string HwMonBackend<DEV>::get_monitor_data()
{
m_msg.clear();
m_msg = nlohmann::json();
m_msg["ts"] = Util::ISO8601TimeUTC();
m_msg["host"] = Util::get_full_hostname();
m_msg["cards"] = nlohmann::json();
card_monitor_data();
return m_msg.dump();
}
template <class DEV>
unsigned int HwMonBackend<DEV>::make_mon_mask(unsigned int model)
{
unsigned int mask = 0x000;
if (model == 709) {
mask = FPGA_MONITOR;
}
else if (model == 712 || model == 711) {
mask = FPGA_MONITOR | POD_MONITOR_LOS | POD_MONITOR_TEMP_VOLT | POD_MONITOR_POWER | POD_MONITOR_POWER_RX;
}
else if (model == 182 || model == 155) {
mask = FPGA_MONITOR | FIREFLY_MONITOR;
}
else{
LOG_ERR("Device model %u not recognised. Monitoring not possible.", model);
}
return mask;
}
template <class DEV>
nlohmann::json HwMonBackend<DEV>::link_alignment(std::shared_ptr<DEV> primary)
{
nlohmann::json j = nlohmann::json::array();
u_long aligned_data = primary->get_register("GBT_ALIGNMENT_DONE");
u_long gbt_error_data = primary->get_register("GBT_ERROR");
u_long number_channels = 2*primary->get_register("NUM_OF_CHANNELS");
u_long mask, alignment, error, result;
for(u_long ch = 0; ch < number_channels; ch++){
mask = (1ul << ch);
alignment = aligned_data & mask;
error = gbt_error_data & mask;
if (alignment == 0 ){
result = 0;
} else {
result = (error == 0) ? 1 : 2;
}
j.emplace_back(result);
}
return j;
}
template <class DEV>
void HwMonBackend<DEV>::card_monitor_data()
{
int idx = 0; //if range-based loops also had an index...
for (const auto & p : m_device_pairs){
auto primary = p.first;
unsigned int mask = m_mon_masks.at(idx);
monitoring_data_t mondata = primary->hw_get_monitoring_data(mask);
nlohmann::json hwjson = mondata_json(mondata);
nlohmann::json regjson = regdata_json(p.first, p.second);
m_msg["cards"][std::to_string(idx)]["HWMON"] = hwjson;
m_msg["cards"][std::to_string(idx)]["HWMON"]["FPGA"]["CLOCK_LOCK"] = primary->get_register("MMCM_MAIN_PLL_LOCK");
m_msg["cards"][std::to_string(idx)]["HWMON"]["FPGA"]["BUSY"] = primary->get_register("TTC_DEC_CTRL_MASTER_BUSY");
m_msg["cards"][std::to_string(idx)]["LINK"]["ALIGN"] = link_alignment(primary);
m_msg["cards"][std::to_string(idx)]["REGS"] = regjson;
++idx;
}
}
template <class DEV>
nlohmann::json HwMonBackend<DEV>::mondata_json(const monitoring_data_t & mondata)
{
nlohmann::json card_data;
card_data["FPGA"] = nlohmann::json();
card_data["FPGA"]["DNA"] = std::format("{:#0x}", mondata.fpga.dna);
card_data["FPGA"]["Temp"] = std::lround(mondata.fpga.temperature);
card_data["FPGA"]["Fan_rpm"] = mondata.fpga.fanspeed;
card_data["FPGA"]["VCC_I"] = mondata.fpga.vccint;
//transceivers TODO
// RX optical power (minipod only)
// TX optical power (minipod only)
return card_data;
};
template <class DEV>
nlohmann::json HwMonBackend<DEV>::regdata_json(std::shared_ptr<DEV> d0, std::shared_ptr<DEV> d1)
{
nlohmann::json reg_data;
reg_data= nlohmann::json();
for(const auto & reg : m_extra_registers) {
reg_data[reg] = nlohmann::json::array();
reg_data[reg].push_back(d0->get_register(reg.c_str()));
if (d1 and m_register_checker.has_endpoint_1(reg)){
reg_data[reg].push_back(d1->get_register(reg.c_str()));
}
}
return reg_data;
};
#endif /* HW_MON_BACKEND_H_ */