Program Listing for File register.hpp

Return to documentation for file (register.hpp)

#include "log.hpp"
#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 "network/netio_evloop.hpp"

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

    private:
        RegmapManager m_regmap;
        std::variant<NetioEventLoop> 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.evloop_type){
        case EventLoopType::netio_next:
            return std::variant<NetioEventLoop>{NetioEventLoop()};
        case EventLoopType::netio3_native:
        case EventLoopType::netio3_asio:
            throw std::runtime_error("Netio3 not implemented");
        default:
            throw std::runtime_error("Unknown event loop type");
    }
}()}
{
    log_init(c.verbose);
    for (const auto & dc : c.dconfs){
        LOG_INFO("Opening device %d", 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) {
        LOG_INFO("Device %u: send commands to fid 0x%lx, get reply from 0x%lx", dc.dev_no, dc.fid_cmd, dc.fid_reply);
        int primary_no = get_or_init_primary(dc.dev_no);
        m_dev_registers.emplace(std::piecewise_construct,
            std::forward_as_tuple(dc.dev_no),
            std::forward_as_tuple(
                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});
                }
            }
        }
        LOG_INFO("Monitoring info for all devices on fid 0x%lx", c.fid_mon);
        hw_mon = std::make_unique<HwMonitor<DEV>>(all_devices, c);
    }
    std::visit([] (auto& evloop) { evloop.start(); }, m_evt_loop);
}


template <class DEV>
void Register<DEV>::init_device(int dev_no)
{
    m_devices.emplace(dev_no, new 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){
        LOG_INFO("Opening required primary device %d", 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){
            LOG_INFO("Opening required secondary device (for monitoring) %d", 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;
}