LCOV - code coverage report
Current view: top level - felix-star/src - config_file_toflx.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 123 162 75.9 %
Date: 2025-06-10 03:23:28 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include <stdlib.h>
       2             : #include <argp.h>
       3             : #include <string.h>
       4             : #include <limits.h>
       5             : 
       6             : #include "felixtag.h"
       7             : 
       8             : #include "config.h"
       9             : #include "felix/felix_ports.h"
      10             : 
      11             : char buf[80];
      12             : const char *argp_program_version = buf;
      13             : const char *argp_program_bug_address = "<https://its.cern.ch/jira/projects/FLXUSERS>";
      14             : 
      15             : /* Program documentation. */
      16             : static char doc[] = "Host-to-Felix communication application (DCS)";
      17             : 
      18             : /* A description of the non-option arguments we accept. */
      19             : static char args_doc[] = "FILE";
      20             : 
      21             : enum option_names {
      22             :   OPT_STATS_OUT = 0x100,
      23             :   OPT_STATS_PERIOD,
      24             :   OPT_STATS_STDOUT,
      25             :   OPT_BUS_DIR,
      26             :   OPT_BUS_GROUPNAME,
      27             :   OPT_ERROR_OUT,
      28             :   OPT_CO,
      29             :   OPT_DID,
      30             :   OPT_CID,
      31             :   OPT_VID,
      32             :   OPT_REGMAP,
      33             :   OPT_VMEM,
      34             :   OPT_FREE_PREVIOUS_CMEM,
      35             :   OPT_IFACE,
      36             :   OPT_RAW,
      37             :   OPT_NO_OF_TAGS
      38             : };
      39             : 
      40             : static struct argp_option options[] = {
      41             :   {"verbose",                      'v', 0,         0,  "Produce verbose output" },
      42             :   {"device",                       'd', "DEVICE",  0,  "Use FLX device DEVICE. Default: 0" },
      43             :   {"dma",                          'D', "ID",      0,  "Use DMA descriptior ID. Default: highest dma" },
      44             :   {"cdma",                         'm',  0,        0,  "Use circular DMA buffer. Default: one-shot" },
      45             :   {"ip",                           'i', "IP",      0,  "Send data to the ip address IP. Default: localhost" },
      46             :   {"iface",                  OPT_IFACE, "IFACE",      0,  "Send data to the interface. Default: use ip value" },
      47             :   {"port",                         'p', "PORT",    0,  "Send data to port PORT. Default: 53200 + 10*device + dma" },
      48             :   {"cmem",                         'c', "SIZE",    0,  "CMEM buffer size in MB. Default: 16" },
      49             :   {"unbuffered",                   'u', 0,         0,  "Use unbuffered mode" },
      50             :   {"netio-buffersize",             'b', "SIZE",    0,  "NetIO receive buffer size in byte; maximum size for a single message. Default: 64kB" },
      51             :   {"netio-buffers",                'B', "SIZE",    0,  "Number of NetIO receive buffers. Default: 256" },
      52             :   {"netio-watermark",              'w', "SIZE",    0,  "NetIO receive watermark size in byte; start of flush. Default: 56kB" },
      53             :   {"stats-out",          OPT_STATS_OUT, "FIFO",    0,  "Write periodic statistics data to a UNIX FIFO: path to fifo. Default: disabled" },
      54             :   {"stats-period",    OPT_STATS_PERIOD, "MS",      0,  "Period in milliseconds for statistics dumps. Default: 1000" },
      55             :   {"stats-stdout",    OPT_STATS_STDOUT, 0,         0,  "Prints stats to stdout. Default: false" },
      56             :   {"bus-dir", OPT_BUS_DIR, "DIRECTORY", 0, "Write felix-bus information to this directory. Default: ./bus" },
      57             :   {"bus-groupname", OPT_BUS_GROUPNAME, "NAME", 0, "Use this groupname for the bus. Default: FELIX" },
      58             :   {"error-out", OPT_ERROR_OUT, "FIFO", 0, "Write error information to a UNIX FIFO" },
      59             :   {"co", OPT_CO, "N", 0, "CO (Connector Offset) to offset FID (Felix ID), incompatible with --did and --cid."},
      60             :   {"did", OPT_DID, "N", 0, "DID (Detector Id) to set in FID (Felix ID), incompatible with --co. Default: 0"},
      61             :   {"cid", OPT_CID, "N", 0, "CID (Connector Id) to set in FID (Felix ID), incompatible with --co. Default: device"},
      62             :   {"vid", OPT_VID, "N", 0, "VID (Version Id) to set in FID (Felix ID), incompatible with --co. Default: 1"},
      63             :   {"free-cmem", OPT_FREE_PREVIOUS_CMEM, 0, 0, "Free previously booked cmem segment by name-<device>-<dma>"},
      64             : 
      65             :   {"tag", 't', "TAG", 0, "Enable tag (elink). This option may be used multiple times (2048 max)."},
      66             :   {"no-of-tags", OPT_NO_OF_TAGS, "SIZE", 0, "Enable no of tags starting at --tag (elink). [default: 1]"},
      67             :   {"regmap", OPT_REGMAP, "hex_version", 0, "Register map version. Default: 0x0400"},
      68             :   {"vmem", OPT_VMEM, 0,         0,  "Use virtual memory. [default: cmem]" },
      69             : 
      70             :   {"raw", OPT_RAW, 0,         0,  "Write raw (binary) file. [default: json]" },
      71             : 
      72             :   { 0 }
      73             : };
      74             : 
      75             : /* Parse a single option. */
      76         623 : static error_t parse_opt(int key, char *arg, struct argp_state *state)
      77             : {
      78             :   /* Get the input argument from argp_parse, which we
      79             :      know is a pointer to our arguments structure. */
      80         623 :   struct config *config = state->input;
      81         623 :   char* end;
      82             : 
      83         623 :   switch (key)
      84             :     {
      85          39 :     case 'v':
      86          39 :       config->verbose = 1;
      87          39 :       break;
      88             : 
      89          16 :     case 'u':
      90          16 :       config->unbuffered = 1;
      91          16 :       break;
      92             : 
      93           2 :     case 'm':
      94           2 :       config->cdma = 1;
      95           2 :       break;
      96             : 
      97           2 :     case 'd':
      98           2 :       config->device = strtol(arg, &end, 0);
      99           2 :       if(end==arg) {
     100           0 :         argp_error(state, "'%s' is not a device number", arg);
     101             :       }
     102             :       break;
     103             : 
     104           2 :     case 'D':
     105           2 :       config->dmaid = strtol(arg, &end, 0);
     106           2 :       if(end==arg) {
     107           0 :         argp_error(state, "'%s' is not a DMA descriptor id", arg);
     108             :       }
     109             :       break;
     110             : 
     111          37 :     case 'i':
     112          37 :       config->ip = strdup(arg);
     113          37 :       break;
     114             : 
     115           2 :     case OPT_IFACE: {
     116           2 :       char* ip = get_ip_from_interface(arg);
     117           2 :       if(!ip) {
     118           0 :         argp_error(state, "'%s' is not an existing interface", arg);
     119             :       }
     120           2 :       config->ip = strdup(ip);
     121           2 :       break;
     122             :     }
     123             : 
     124          39 :     case 'p':
     125          39 :       config->port = strtol(arg, &end, 0);
     126          39 :       if(end==arg) {
     127           0 :         argp_error(state, "'%s' is not a number", arg);
     128             :       }
     129             :       break;
     130             : 
     131           2 :     case 'c':
     132           2 :       config->cmem_buffersize = strtol(arg, &end, 0);
     133           2 :       config->cmem_buffersize *= 1024*1024;
     134           2 :       if(end==arg) {
     135           0 :         argp_error(state, "'%s' is not a number", arg);
     136             :       }
     137             :       break;
     138             : 
     139           2 :     case 'b':
     140           2 :       config->netio_pagesize = strtol(arg, &end, 0);
     141           2 :       if(end==arg) {
     142           0 :         argp_error(state, "'%s' is not a number", arg);
     143             :       }
     144             :       break;
     145             : 
     146           2 :     case 'B':
     147           2 :       config->netio_pages = strtol(arg, &end, 0);
     148           2 :       if(end==arg) {
     149           0 :         argp_error(state, "'%s' is not a number", arg);
     150             :       }
     151             :       break;
     152             : 
     153           2 :     case 'w':
     154           2 :       config->netio_watermark = strtol(arg, &end, 0);
     155           2 :       if(end==arg) {
     156           0 :         argp_error(state, "'%s' is not a number", arg);
     157             :       }
     158             :       break;
     159             : 
     160          66 :     case 't':
     161          66 :       config->elinks[config->num_elinks] = strtol(arg, &end, 0);
     162          66 :       config->num_elinks++;
     163          66 :       if(end==arg) {
     164           0 :         argp_error(state, "'%s' is not a number", arg);
     165             :       }
     166             :       break;
     167             : 
     168           0 :     case OPT_NO_OF_TAGS:
     169           0 :       config->no_of_tags = strtol(arg, &end, 0);
     170           0 :       if(end==arg) {
     171           0 :         argp_error(state, "'%s' is not a number", arg);
     172             :       }
     173             :       break;
     174             : 
     175           2 :     case OPT_STATS_OUT:
     176           2 :       config->statistics_fifo = strdup(arg);
     177           2 :       break;
     178             : 
     179           2 :     case OPT_STATS_PERIOD:
     180           2 :       config->statistics_period = strtol(arg, &end, 0);
     181           2 :       if(end==arg) {
     182           0 :         argp_error(state, "'%s' is not a number", arg);
     183             :       }
     184             :       break;
     185             : 
     186           2 :     case OPT_STATS_STDOUT:
     187           2 :       config->statistics_stdout = true;
     188           2 :       break;
     189             : 
     190          39 :     case OPT_BUS_DIR:
     191          39 :       config->bus_dir = strdup(arg);
     192          39 :       break;
     193             : 
     194          39 :     case OPT_BUS_GROUPNAME:
     195          39 :       config->bus_groupname = strdup(arg);
     196          39 :       break;
     197             : 
     198           0 :     case OPT_ERROR_OUT:
     199           0 :       config->error_fifo = strdup(arg);
     200           0 :       break;
     201             : 
     202           0 :     case OPT_CO:
     203           0 :       config->co = strtol(arg, &end, 0);
     204           0 :       if(end==arg) {
     205           0 :         argp_error(state, "'%s' is not a number", arg);
     206             :       }
     207           0 :       config->did = get_did_from_co(config->co, config->vid);
     208           0 :       config->cid = get_cid_from_co(config->co, config->vid);
     209           0 :       break;
     210             : 
     211          39 :     case OPT_DID:
     212          39 :       config->did = strtol(arg, &end, 0);
     213          39 :       if(end==arg) {
     214           0 :         argp_error(state, "'%s' is not a number", arg);
     215             :       }
     216             :       break;
     217             : 
     218          39 :     case OPT_CID:
     219          39 :       config->cid = strtol(arg, &end, 0);
     220          39 :       if(end==arg) {
     221           0 :         argp_error(state, "'%s' is not a number", arg);
     222             :       }
     223             :       break;
     224             : 
     225           2 :     case OPT_VID:
     226           2 :       config->vid = strtol(arg, &end, 0);
     227           2 :       if(end==arg) {
     228           0 :         argp_error(state, "'%s' is not a number", arg);
     229             :       }
     230             :       break;
     231             : 
     232           0 :     case OPT_REGMAP:
     233           0 :       config->regmap = strtol(arg, &end, 0);
     234           0 :       if(end==arg) {
     235           0 :         argp_error(state, "'%s' is not a number", arg);
     236             :       }
     237             :       break;
     238             : 
     239          37 :     case OPT_VMEM:
     240          37 :       config->vmem = 1;
     241          37 :       break;
     242             : 
     243          12 :     case OPT_RAW:
     244          12 :       config->raw = 1;
     245          12 :       break;
     246             : 
     247           2 :     case OPT_FREE_PREVIOUS_CMEM:
     248           2 :       config->free_previous_cmem = 1;
     249           2 :       break;
     250             : 
     251          39 :     case ARGP_KEY_ARG:
     252          39 :       if (state->arg_num >= 1)
     253             :         /* Too many arguments. */
     254           0 :         argp_usage (state);
     255             : 
     256          39 :       config->file = strdup(arg);
     257          39 :       break;
     258             : 
     259          39 :     case ARGP_KEY_END:
     260          39 :       if (state->arg_num < 1)
     261             :         /* Not enough arguments. */
     262           0 :         argp_usage (state);
     263             :       break;
     264             : 
     265             :     default:
     266             :       return ARGP_ERR_UNKNOWN;
     267             :     }
     268             :   return 0;
     269             : }
     270             : 
     271             : /* Our argp parser. */
     272             : static struct argp argp = { options, parse_opt, args_doc, doc };
     273             : 
     274          39 : void cli_parse(int argc, char **argv, struct config* config)
     275             : {
     276          39 :   snprintf(buf, sizeof buf, "%s %s", argv[0], FELIX_TAG);
     277             : 
     278             :   // set default values
     279          39 :   config->appname = argv[0];
     280          39 :   config->ip = "127.0.0.1";
     281          39 :   config->port = -1;
     282          39 :   config->verbose = 0;
     283          39 :   config->unbuffered = 0;
     284          39 :   config->device = 0;
     285          39 :   config->dmaid = -1;
     286          39 :   config->cdma = 0;
     287          39 :   config->cmem_buffersize = 16*1024*1024;
     288          39 :   config->netio_pages = 256;
     289          39 :   config->netio_pagesize = 64*1024;
     290          39 :   config->netio_watermark = 56*1024;
     291          39 :   config->statistics_fifo = NULL;
     292          39 :   config->statistics_period = 1000;
     293          39 :   config->statistics_stdout = false;
     294          39 :   config->bus_dir = "./bus";
     295          39 :   config->bus_groupname = "FELIX";
     296          39 :   config->error_fifo = NULL;
     297          39 :   config->co = 0;
     298          39 :   config->did = 0;
     299          39 :   config->cid = -1;
     300          39 :   config->vid = FID_VERSION_ID;
     301          39 :   config->free_previous_cmem = 0;
     302             : 
     303             :   // flxcard
     304          39 :   config->regmap = REGMAP_VERSION;
     305          39 :   config->vmem = 0;
     306          39 :   config->raw = 0;
     307          39 :   config->no_of_tags = 1;
     308          39 :   config->dcs_egroup = -1;
     309             : 
     310             :   // parse arguments
     311          39 :   argp_parse(&argp, argc, argv, 0, 0, config);
     312             : 
     313          39 :   if (config->cid == -1) {
     314           0 :     config->cid = config->device;
     315             :   }
     316             : 
     317          39 :   if (config->co == 0) {
     318          78 :     config->co = get_co_from_ids(config->did, config->cid, config->vid);
     319             :   }
     320             : 
     321             :   // NOTE: we do not have the dmaid here, so we just assume 0, as the TOFLX region only uses one port per device
     322          39 :   if (config->port < 0) {
     323           0 :     config->port = PORT(PORT_TOFLX_OFFSET, config->device, 0);
     324             :   }
     325             : 
     326          39 :   if (config->no_of_tags > 1) {
     327           0 :     for (size_t i = 1; i < config->no_of_tags; i++) {
     328           0 :       config->elinks[i] = config->elinks[0] + i;
     329           0 :       config->has_streams[i] = 0;
     330             :     }
     331           0 :     config->num_elinks = config->no_of_tags;
     332             :   }
     333          39 : }

Generated by: LCOV version 1.0