Program Listing for File register.hpp

Return to documentation for file (register.hpp)

#include "ers/ers.h"
#include "config/config_register.hpp"
#include "device.hpp"
#include "regmap_manager.hpp"
#include "register_device_controller.hpp"
#include "hardware_monitor.hpp"
#include <sys/types.h>
#include <memory>

#include "netio3-backend/EventLoop/AsioEventLoop.hpp"
#include "netio3-backend/EventLoop/EpollEventLoop.hpp"
#include <format>
#include "network/netio3_evloop.hpp"

template <class DEV>
class Register {
    public:
        explicit Register(const ConfigRegister & conf);

    private:
        RegmapManager m_regmap;
        Netio3EventLoop m_evt_loop;
        std::map<int, std::shared_ptr<DEV>> m_devices;
        std::map<int, std::shared_ptr<RegisterDeviceController<DEV>>> m_dev_registers;
        std::unique_ptr<HwMonitor<DEV>> hw_mon;

        void init_device(int dev_no);

        int get_or_init_primary(int dev_no);

        int get_or_init_secondary(int dev_no);

        int get_primary(int dev_no);
};


template <class DEV>
Register<DEV>::Register(const ConfigRegister & c) : m_evt_loop{[&c]() {
    switch (c.network_mode) {
        case NetworkMode::tcp:
            return Netio3EventLoop{Netio3EventLoop::type_tag<netio3::AsioEventLoop>()};
        case NetworkMode::rdma:
            return Netio3EventLoop{Netio3EventLoop::type_tag<netio3::EpollEventLoop>()};
        default:
            throw std::runtime_error("Unknown network mode");
    }
}()}
{
    for (const auto & dc : c.dconfs){
        ERS_INFO(std::format("Opening device {}", dc.dev_no));
        init_device(dc.dev_no);
    }

    unsigned int idx = 0; //to pass the single-device configuration to DeviceRegister
    for (const auto & dc : c.dconfs) {
        ERS_INFO(std::format("Device {}: send commands to fid {:#x}, get reply from {:#x}", dc.dev_no, dc.fid_cmd, dc.fid_reply));
        int primary_no = get_or_init_primary(dc.dev_no);
        m_dev_registers.try_emplace(dc.dev_no, std::make_shared<RegisterDeviceController<DEV>>(m_evt_loop, m_regmap, m_devices.at(dc.dev_no), m_devices.at(primary_no), c, idx));
        ++idx;
    }

    if (c.enable_mon){
        using device_pair = std::pair<std::shared_ptr<DEV>, std::shared_ptr<DEV>>;
        std::vector<device_pair> all_devices;

        //make sure that that all requested devices are paired.
        for (const auto & dc : c.dconfs) {
            get_or_init_secondary(dc.dev_no);
        }
        //loop over all opened devices and match each primary with a secondary
        for (const auto &[dev_no, dev_ptr] : m_devices) {
            if (dev_ptr->is_primary()) {
                int secondary = get_or_init_secondary(dev_no);
                if (secondary != -1) {
                    all_devices.push_back({m_devices.at(dev_no), m_devices.at(secondary)});
                } else {
                    all_devices.push_back({m_devices.at(dev_no), nullptr});
                }
            }
        }
        ERS_INFO(std::format("Monitoring info for all devices on fid {:#x}", c.fid_mon));
        hw_mon = std::make_unique<HwMonitor<DEV>>(all_devices, c);
    }
    m_evt_loop.start();
}


template <class DEV>
void Register<DEV>::init_device(int dev_no)
{
    m_devices.emplace(dev_no, std::make_unique<DEV>(dev_no));
    unsigned int lock_mask = 0;
    m_devices.at(dev_no)->open_device(lock_mask);
}


template <class DEV>
int Register<DEV>::get_or_init_primary(int dev_no)
{
    int primary = get_primary(dev_no);
    if (dev_no != primary and m_devices.count(primary) == 0){
        ERS_INFO(std::format("Opening required primary device {}", primary));
        init_device(primary);
    }
    return primary;
}


template <class DEV>
int Register<DEV>::get_or_init_secondary(int dev_no)
{
    int secondary = -1;
    if (m_devices.at(dev_no)->is_primary() and m_devices.at(dev_no)->get_card_endpoints() > 1){
        secondary = dev_no + 1;
        if (m_devices.count(secondary) == 0){
            ERS_INFO(std::format("Opening required secondary device (for monitoring) {}", secondary));
            init_device(secondary);
        }
    }
    else if (not m_devices.at(dev_no)->is_primary()){
        secondary = dev_no;
    }
    return secondary;
}


template <class DEV>
int Register<DEV>::get_primary(int dev_no)
{
    int primary{-1};
    if ( m_devices.at(dev_no)->is_primary() ){
        primary = dev_no;
    } else {
        primary = dev_no - 1;
    }
    return primary;
}