Program Listing for File config_register.cpp

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

#include "felixtag.h"
#include "felix/felix_fid.h"
#include "felix/felix_ports.h"
#include "felix/felix_client_util.hpp"
#include "config_register.hpp"

#include <cstdint>
#include <format>
#include <string>

std::string ConfigRegister::usage() {
    return
R"(felix-register - Receive control data for registers and reply.

    Usage:
      felix-register [options] <local_ip_or_interface> (<device> <did> <cid>)...
)";
}


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


std::string ConfigRegister::options() {
    return
std::format(R"(
    Options:
      -h --help                         Show this screen.
      --version                         Show version.
      --bus-dir=<bus-directory>         Set bus directory [default: bus]
      --bus-groupname=<groupname>       Set groupname for bus to use [default: FELIX]
      --cmd-port=<N>                    Set port number for commands to the devices [default: {} + (10 * first-device)]
      --pub-port=<N>                    Set port number for publications from the devices [default: {} + (10 * first-device)]
      --log-level=<loglevel>            Specify level of logging (trace, debug, info, notice, warning, error, fatal) [default: info]
      --mon-port=<N>                    Set port number for monitoring of the devices [default: {} + (10 * first-device)]
      --mon-interval=<seconds>          Set monitoring interval [default: 5]
      --mon-regfile=<file>              File containing the name of additinal card registers to monitor [default: ""]
      --verbose                         Show verbose output [default: false]
      --verbose-bus                     Show bus information [default: false]
      --no-cmd-channel                  Do not instantiate a Cmd channel, for testing only [default: false]
      --no-reply                        Do not reply, for unit tests only [default: false]
      --no-mon-channel                  Do not start MON channel [default: false]

    Arguments:
      <local_ip_or_interface>           Local IP or interface
      <device>                          Use FLX device
      <did>                             DID (Detector Id) to use in FID (Felix ID)
      <cid>                             CID (Connector Id) to use in FID (Felix ID)

    Notes:
      <device> <did> <cid> triplets should be declared in endpoint-0, endpoint-1 order.
      Requests for non-existing endpoint-1 will be routed to endpoint-0: device 1 -> device 0, device 3 -> device 2
)", PORT_COMMAND_OFFSET, PORT_REPLY_OFFSET, PORT_MON_OFFSET);
}


void ConfigRegister::parse(int argc, char **argv) {

    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



    local_ip = get_value_from_getifaddrs(args["<local_ip_or_interface>"].asString(), true);
    bus_dir = args["--bus-dir"].asString();
    bus_group = args["--bus-groupname"].asString();
    verbose  = args["--verbose"].asBool();
    verbose_bus  = args["--verbose-bus"].asBool();
    mon_interval = static_cast<unsigned int>(args["--mon-interval"].asLong());
    if (args["--mon-regfile"].asString() != ""){
        extra_mon = args["--mon-regfile"].asString();
    }

    enable_cmd   = not args["--no-cmd-channel"].asBool();
    enable_reply = not args["--no-reply"].asBool();
    enable_mon   = not args["--no-mon-channel"].asBool();

    unsigned int cmd_port_offset   = std::stoul(args["--cmd-port"].asString(), nullptr, 0);
    unsigned int reply_port_offset = std::stoul(args["--pub-port"].asString(), nullptr, 0);
    unsigned int mon_port_offset   = std::stoul(args["--mon-port"].asString(), nullptr, 0);

    auto devices = args["<device>"].asStringList();
    auto dids = args["<did>"].asStringList();
    auto cids = args["<cid>"].asStringList();

    constexpr uint8_t sid = 0;
    constexpr uint8_t virt = 1;
    int d0 = std::stoi(devices.at(0));
    int first_did = std::stoi(dids.at(0), nullptr, 0);
    int first_cid = std::stoi(cids.at(0), nullptr, 0);
    //use first did and cid for monitoring e-link
    fid_mon =  get_fid_from_ids(first_did, first_cid, MON_LINK, sid, FID_VERSION_ID, 0, virt); // to_flx = 0
    //use first device number for the port
    port_mon = static_cast<int>(mon_port_offset + 10*d0);

    for (unsigned int d = 0; d < args["<device>"].asStringList().size(); ++d){
        int did = std::stoi(dids[d], nullptr, 0);
        int cid = std::stoi(cids[d], nullptr, 0);
        int dev = std::stoi(devices.at(d), nullptr, 0);
        RegisterDeviceConfig c {
            .dev_no = dev,
            .did = did,
            .cid = cid,
            .port_cmd = static_cast<int>(cmd_port_offset + 10*dev),
            .port_reply = static_cast<int>(reply_port_offset + 10*dev),
            .fid_cmd = get_fid_from_ids(did, cid, COMMAND_REPLY_LINK, sid, FID_VERSION_ID, 1, virt), // to_flx = 1
            .fid_reply = get_fid_from_ids(did, cid, COMMAND_REPLY_LINK, sid, FID_VERSION_ID, 0, virt), // to_flx = 0
        };
        dconfs.push_back(c);
    }
}