Program Listing for File config.cpp

Return to documentation for file (config/config.cpp)

#include "config.hpp"
#include "felixtag.h"
#include "log.hpp"

#include "felix/felix_fid.h"
#include "felix/felix_ports.h"
#include "felix/felix_client_util.hpp"
#include <cstdint>

std::string Config::options() {
    return
R"(
    General Options:
        --bus-dir=DIRECTORY         Write felix-bus information to this directory. [default: ./bus]
        --bus-groupname=NAME        Use this groupname for the bus. [default: FELIX]
        --cid=<cid>...              CID (Connector Ids) to set in FID (Felix ID). Can be used multiple times. [default: device]
        --did=<did>                 DID (Detector Id) to set in FID (Felix ID). [default: 0]
    -d, --device=<device>...        Use FLX device DEVICE. [default: 0]
        --error-out=<fifo>          Write error information to a UNIX FIFO
        --free-cmem                 Free previously booked cmem segment by name-<device>-<dma>
        --iface=<iface>             Send data to the interface. [calculated: use --ip value]
    -i, --ip=<ip>                   Publish data on the ip address IP. [default: libfabric:127.0.0.1]
    -b, --netio-pagesize=<size>     NetIO page size in Byte. [default: 65536]
    -B, --netio-pages=<size>        Number of NetIO pages. [default: 256]
        --stats-out=<fifo>          Write periodic statistics data to a UNIX FIFO
        --stats-period=<ms>         Period in milliseconds for statistics dumps. [default: 1000]
    -?, --help                      Give this help list
    -v, --verbose                   Produce verbose output
        --verbose-bus               Produce verbose output for bus
    -V, --version                   Print program version
        --evloop-type=<type>        Event loop type to use. [default: netio-next]
        --vid=N                     VID (Version Id) to set in FID (Felix ID) [default: 1]
)";
}

Config::Config() {}

Config::~Config() {}


void Config::parse(int argc, char **argv) {
    appname = argv[0];

    std::map<std::string, docopt::value> args
            = docopt::docopt(usage() + options() + bugs(),
                            { argv + 1, argv + argc },
                            true,               // show help if requested
                            (std::string(argv[0]) + " " + FELIX_TAG).c_str());  // version string

    handle_cmd_line(args);
}

std::ostream& Config::format(std::ostream& os) const {
    os << "Config" << std::endl;
    os << "bus_dir: " << network.bus_dir << std::endl;
    os << "bus_groupname: " << network.bus_groupname << std::endl;
    os << "cid: ";
        std::copy(resource.cid.begin(), resource.cid.end(), std::ostream_iterator<int>(os << std::hex << std::showbase, " "));
        os << std::endl;
    os << "did: 0x" << std::hex << resource.did << std::dec << std::endl;
    os << "device: ";
        std::copy(resource.device.begin(), resource.device.end(), std::ostream_iterator<int>(os, " "));
        os << std::endl;
    os << "free_previous_cmem: " << resource.free_previous_cmem << std::endl;
    os << "ip: " << network.ip << std::endl;
    os << "netio_pagesize: " << network.netio_pagesize << std::endl;
    os << "netio_pages: " << network.netio_pages << std::endl;
    os << "statistics_fifo: " << stats.monitoring_fifo << std::endl;
    os << "statistics_period: " << stats.monitoring_period_ms << std::endl;
    os << "verbose: " << verbose << std::endl;
    os << "verbose_bus: " << network.verbose_bus << std::endl;
    os << "eventloop_type: " << evloop_type_to_str(network.evloop_type) << std::endl;
    os << "vid: 0x" << std::hex << (uint32_t)resource.vid << std::dec << std::endl;
    os << std::endl;
    return os;
}

std::ostream& operator<<(std::ostream& os, const Config& c) {
    return c.format(os);
}

void Config::handle_cmd_line(std::map<std::string, docopt::value> args) {

    auto devices = args["--device"].asStringList();
    for(const auto& i : devices){
        resource.device.push_back(stoi(i));
    }

    resource.vid = args["--vid"].asLong();
    resource.did = args["--did"].asLong();

    auto cids = args["--cid"].asStringList();
    if (cids.empty()) { // No cids, impossible, there should be the default
        LOG_ERR("No cid provided, aborting.");
        throw std::runtime_error("No cid provided, aborting.");
    }
    else if (cids.size() == 1) {
        if ( cids.at(0) == "device" ) {
            resource.cid = resource.device;
        }
        else {
            int base_cid = stoi(cids.at(0), 0, 16);
            for(unsigned int i = 0; i < resource.device.size(); ++i) {
                resource.cid.push_back(base_cid + i);
            }
        }
    }
    else if (cids.size() == devices.size()){
        for(unsigned int i = 0; i < cids.size(); ++i) {
            uint16_t cid = static_cast<uint16_t>(stoi(cids.at(i), 0, 16));
            resource.cid.push_back(cid);
        }
    }
    else {
        LOG_ERR("The number of provided CIDs is not one nor equal to the number of devices.");
        throw std::runtime_error("No cid provided, aborting.");
    }

    resource.free_previous_cmem = args["--free-cmem"].asBool();

    network.bus_dir = args["--bus-dir"].asString();
    network.bus_groupname = args["--bus-groupname"].asString();
    network.dcs_tcp = false;
    network.netio_pagesize = args["--netio-pagesize"].asLong();
    network.netio_pages = args["--netio-pages"].asLong();
    network.verbose_bus = args["--verbose-bus"].asBool();

    network.evloop_type = evloop_type_from_str(args["--evloop-type"].asString());

    stats.monitoring_fifo = args["--stats-out"] ? args["--stats-out"].asString() : "";
    stats.monitoring_period_ms = args["--stats-period"].asLong();

    verbose = args["--verbose"].asBool();

    // derive ip
    if (args["--iface"]) {
        network.ip = get_value_from_getifaddrs(args["--iface"].asString(), true);
    } else {
        network.ip = args["--ip"].asString();
    }
}


std::string Config::bugs() {
    return
R"(
Report bugs to <https://its.cern.ch/jira/projects/FLXUSERS>.
)";
}


int Config::get_number_devices()
{
    return resource.device.size();
};


uint16_t Config::get_device_cid(unsigned int dev_no)
{
    auto it = std::find(resource.device.begin(), resource.device.end(), dev_no);
    if ( it == resource.device.end() ){
        throw std::invalid_argument("Cannot find cid for the requested device.");
    } else {
        int idx = it - resource.device.begin();
        return resource.cid.at(idx);
    }
}


int Config::get_unique_dmaid(int dmaid, uint16_t device)
{
    return (dmaid + 10*device);
}


int Config::udmaid_to_dmaid(int udmaid)
{
    return (udmaid % 10);
}


int Config::udmaid_to_deviceid(int udmaid)
{
    return ( (udmaid - udmaid_to_dmaid(udmaid)) / 10 );
}

std::string Config::evloop_type_to_str(EventLoopType type)
{
    switch (type) {
        case EventLoopType::netio_next:
            return "netio-next";
        case EventLoopType::netio3_native:
            return "netio3-native";
        case EventLoopType::netio3_asio:
            return "netio3-asio";
        default:
            throw std::logic_error("Invalid EventLoopType");
    }
}

EventLoopType Config::evloop_type_from_str(std::string_view type)
{
    if (type == "netio-next") {
        return EventLoopType::netio_next;
    } else if (type == "netio3-native") {
        return EventLoopType::netio3_native;
    } else if (type == "netio3-asio") {
        return EventLoopType::netio3_asio;
    } else {
        throw std::logic_error("Invalid EventLoopType");
    }
}