Line data Source code
1 : #include <stdlib.h>
2 : #include <argp.h>
3 : #include <string.h>
4 : #include <stdio.h>
5 :
6 : #include "config.h"
7 :
8 : #include "felixtag.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[] = "FELIX central data acquisition application";
17 :
18 : /* A description of the 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_BUS_DIR,
25 : OPT_BUS_GROUPNAME,
26 : OPT_ERROR_OUT,
27 : OPT_CO,
28 : OPT_DID,
29 : OPT_CID,
30 : OPT_VID,
31 : OPT_BUF,
32 : OPT_TTC2H_ENABLE,
33 : OPT_TTC2H_PORT,
34 : OPT_TTC_PAGES,
35 : OPT_TTC_PAGESIZE,
36 : OPT_TTC_WATERMARK,
37 : OPT_TTC_TIMEOUT,
38 : OPT_DCS_PAGES,
39 : OPT_DCS_PAGESIZE,
40 : OPT_DCS_WATERMARK,
41 : OPT_DCS_TIMEOUT,
42 : OPT_DCS_UNBUFFERED,
43 : OPT_REGMAP,
44 : OPT_BLOCK_SIZE,
45 : OPT_BLOCK_RATE,
46 : OPT_VMEM,
47 : OPT_NO_REPEAT,
48 : OPT_FREE_PREVIOUS_CMEM,
49 : OPT_IFACE,
50 : OPT_DCS_RATE_LIMIT,
51 : OPT_DCS_SIZE_LIMIT,
52 : OPT_MAX_BUF_CHUNK,
53 : OPT_NO_OF_TAGS
54 : };
55 :
56 : /* The options we understand. */
57 : static struct argp_option options[] = {
58 : {"verbose", 'v', 0, 0, "Produce verbose output" },
59 : {"device", 'd', "DEVICE", 0, "Use FLX device DEVICE. [default: 0]" },
60 : {"dma", 'D', "ID", 0, "Use DMA descriptor ID. [default: 0]" },
61 : {"ip", 'i', "IP", 0, "Publish data on the ip address IP. [default: localhost]" },
62 : {"iface", OPT_IFACE, "IFACE", 0, "Send data to the interface. [default: use IP value]" },
63 : {"port", 'p', "PORT", 0, "Publish data on port PORT. [default: 53100 + 10*device + dma]" },
64 : {"ttcport", OPT_TTC2H_PORT, "PORT", 0, "Publish TTC2H data on port PORT. [default: 53300 + 10*device + dma]" },
65 : {"dcsport", 's', "PORT", 0, "Publish DCS data on port PORT. [default: 53500 + 10*device + dma]" },
66 : {"cmem", 'c', "SIZE", 0, "CMEM buffer size in MB. [default: 1024]" },
67 : {"l1id-check", 'l', "FORMAT", 0, "Check L1ID sequence. Formats: 1=TTC2H only, 2=LATOME, 3=FMEMU, 4=FELIG, 5=NSWVMM, 6=NSWTP. [default: 0]" },
68 : {"netio-pagesize", 'b', "SIZE", 0, "NetIO page size in Byte. [default: 64 kB]" },
69 : {"netio-pages", 'B', "SIZE", 0, "Number of NetIO pages. [default: 256]" },
70 : {"netio-watermark", 'w', "SIZE", 0, "NetIO watermark in Byte. [default: 56 kB]" },
71 : {"netio-timeout", 'T', "SIZE", 0, "NetIO timeout in ms. [default: 2 ms]" },
72 : {"ttc-netio-pagesize", OPT_TTC_PAGESIZE, "SIZE", 0, "TTC NetIO page size in Byte. [default: 1536 B]" },
73 : {"ttc-netio-pages", OPT_TTC_PAGES, "SIZE", 0, "TTC Number of NetIO pages. [default: 512]" },
74 : {"ttc-netio-watermark", OPT_TTC_WATERMARK, "SIZE", 0, "TTC NetIO watermark in Byte. [default: 1248 B]" },
75 : {"ttc-netio-timeout", OPT_TTC_TIMEOUT, "SIZE", 0, "TTC NetIO timeout in ms. Not necessary as TTC2H buffers are flushed at end-of-block. Default: 0" },
76 : {"dcs-pagesize", OPT_DCS_PAGESIZE, "SIZE", 0, "DCS NetIO page size in Byte. Default: 1 kB" },
77 : {"dcs-pages", OPT_DCS_PAGES, "SIZE", 0, "DCS Number of NetIO pages. Default: 512" },
78 : {"dcs-watermark", OPT_DCS_WATERMARK, "SIZE", 0, "DCS NetIO watermark in Byte. Default: 972 B" },
79 : {"dcs-timeout", OPT_DCS_TIMEOUT, "SIZE", 0, "DCS NetIO timeout in ms. Default: 1" },
80 : {"dcs-unbuffered", OPT_DCS_UNBUFFERED, 0, 0, "DCS TTC unbuffered mode. The page settings are not used." },
81 : {"dcs-rate-limit", OPT_DCS_RATE_LIMIT, "LIMIT", 0, "Drop DCS messages when elink message is above the given rate [KHz]." },
82 : {"dcs-size-limit", OPT_DCS_SIZE_LIMIT, "LIMIT", 0, "Drop DCS messages when message size is 0 or above this threshold." },
83 : {"stats-out", OPT_STATS_OUT, "FIFO", 0, "Write periodic statistics data to a UNIX FIFO" },
84 : {"stats-period", OPT_STATS_PERIOD, "ms", 0, "Period in milliseconds for statistics dumps" },
85 : {"poll-period", 'P', "us", 0, "Polling instead of interrupt-driven readout with the given poll period in microseconds"},
86 : {"bus-dir", OPT_BUS_DIR, "DIRECTORY", 0, "Write felix-bus information to this directory. Default: ./bus" },
87 : {"bus-groupname", OPT_BUS_GROUPNAME, "NAME", 0, "Use this groupname for the bus. Default: FELIX" },
88 : {"error-out", OPT_ERROR_OUT, "FIFO", 0, "Write error information to a UNIX FIFO" },
89 : {"co", OPT_CO, "N", 0, "CO (Connector Offset) to offset FID (Felix ID), incompatible with --did and --cid."},
90 : {"did", OPT_DID, "N", 0, "DID (Detector Id) to set in FID (Felix ID), incompatible with --co. Default: 0"},
91 : {"cid", OPT_CID, "N", 0, "CID (Connector Id) to set in FID (Felix ID), incompatible with --co. Default: device"},
92 : {"vid", OPT_VID, "N", 0, "VID (Version Id) to set in FID (Felix ID), incompatible with --co. Default: 1"},
93 : {"buffered", OPT_BUF, 0, 0, "Enable buffered mode (FULL-mode only)"},
94 : {"max-chunk-size-buffered", OPT_MAX_BUF_CHUNK, "LIMIT", 0, "Maximum chunk size supported for buffered traffic. Larger chunks are truncated."},
95 : {"ttc2h-enable", OPT_TTC2H_ENABLE, 0, 0, "Enable TTC2H elink"},
96 :
97 : {"regmap", OPT_REGMAP, "hex_version", 0, "Register map version. Default: 0x0400"},
98 : {"free-cmem", OPT_FREE_PREVIOUS_CMEM, 0, 0, "Free previously booked cmem segment by name-<device>-<dma>"},
99 :
100 : // FIXME, we should read the set of elinks from the file
101 : {"tag", 't', "TAG", 0, "Read tag (elink) from file. This option may be used multiple times (2048 max)."},
102 : {"no-of-tags", OPT_NO_OF_TAGS, "SIZE", 0, "Read no of tags starting at --tag (elink) from file. [default: 1]"},
103 : {"block-size", OPT_BLOCK_SIZE, "SIZE", 0, "Use as block size, multiple of 1024. [default: 1024]"},
104 : {"block-rate", OPT_BLOCK_RATE, "RATE", 0, "Use to define the reading rate. [default: 0 (max. speed)]"},
105 : {"stream", 'u', "TAG", 0, "Read tag (elink streams) from file. This option may be used multiple times (2048 max)."},
106 : {"full-mode", 'm', 0, 0, "Use full-mode. [default: gbt-mode]" },
107 : {"vmem", OPT_VMEM, 0, 0, "Use virtual memory. [default: cmem]" },
108 : {"no-repeat", OPT_NO_REPEAT, 0, 0, "Do not repeat reading the file" },
109 : { 0 }
110 : };
111 :
112 : /* Parse a single option. */
113 : static error_t
114 751 : parse_opt (int key, char *arg, struct argp_state *state)
115 : {
116 : /* Get the input argument from argp_parse, which we
117 : know is a pointer to our config structure. */
118 751 : struct config *config = state->input;
119 751 : char* end;
120 :
121 751 : switch (key)
122 : {
123 42 : case 'v':
124 42 : config->verbose = 1;
125 42 : break;
126 :
127 0 : case 'd':
128 0 : config->device = strtol(arg, &end, 0);
129 0 : if(end==arg) {
130 0 : argp_error(state, "'%s' is not a device number", arg);
131 : }
132 : break;
133 :
134 44 : case 'p':
135 44 : config->port = strtol(arg, &end, 0);
136 44 : if(end==arg) {
137 0 : argp_error(state, "'%s' is not a number", arg);
138 : }
139 : break;
140 :
141 44 : case 'i':
142 44 : config->ip = strdup(arg);
143 44 : break;
144 :
145 0 : case OPT_IFACE: {
146 0 : char* ip = get_ip_from_interface(arg);
147 0 : if(!ip) {
148 0 : argp_error(state, "'%s' is not an existing interface", arg);
149 : }
150 0 : config->ip = strdup(ip);
151 0 : break;
152 : }
153 :
154 32 : case 'c':
155 32 : config->cmem_buffersize = strtol(arg, &end, 0);
156 32 : config->cmem_buffersize *= 1024*1024;
157 32 : if(end==arg) {
158 0 : argp_error(state, "'%s' is not a number", arg);
159 : }
160 : break;
161 :
162 0 : case 'b':
163 0 : config->netio_pagesize = strtol(arg, &end, 0);
164 0 : if(end==arg) {
165 0 : argp_error(state, "'%s' is not a number", arg);
166 : }
167 : break;
168 :
169 0 : case 'B':
170 0 : config->netio_pages = strtol(arg, &end, 0);
171 0 : if(end==arg) {
172 0 : argp_error(state, "'%s' is not a number", arg);
173 : }
174 : break;
175 :
176 0 : case 'w':
177 0 : config->netio_watermark = strtol(arg, &end, 0);
178 0 : if(end==arg) {
179 0 : argp_error(state, "'%s' is not a number", arg);
180 : }
181 : break;
182 :
183 0 : case 'T':
184 0 : config->netio_timeout = strtol(arg, &end, 0);
185 0 : if(end==arg) {
186 0 : argp_error(state, "'%s' is not a number", arg);
187 : }
188 : break;
189 :
190 0 : case 'l':
191 0 : config->l1id_check = strtol(arg, &end, 0);
192 0 : if(end==arg) {
193 0 : argp_error(state, "'%s' is not a number", arg);
194 : }
195 : break;
196 :
197 4 : case OPT_TTC_PAGES:
198 4 : config->ttc_netio_pages = strtol(arg, &end, 0);
199 4 : if(end==arg) {
200 0 : argp_error(state, "'%s' is not a number", arg);
201 : }
202 : break;
203 :
204 0 : case OPT_TTC_PAGESIZE:
205 0 : config->ttc_netio_pagesize = strtol(arg, &end, 0);
206 0 : if(end==arg) {
207 0 : argp_error(state, "'%s' is not a number", arg);
208 : }
209 : break;
210 :
211 0 : case OPT_TTC_WATERMARK:
212 0 : config->ttc_netio_watermark = strtol(arg, &end, 0);
213 0 : if(end==arg) {
214 0 : argp_error(state, "'%s' is not a number", arg);
215 : }
216 : break;
217 :
218 0 : case OPT_TTC_TIMEOUT:
219 0 : config->ttc_netio_timeout = strtol(arg, &end, 0);
220 0 : if(end==arg) {
221 0 : argp_error(state, "'%s' is not a number", arg);
222 : }
223 : break;
224 :
225 53 : case 't':
226 53 : config->elinks[config->num_elinks] = strtol(arg, &end, 0);
227 53 : config->has_streams[config->num_elinks] = 0;
228 53 : config->num_elinks++;
229 53 : if(end==arg) {
230 0 : argp_error(state, "'%s' is not a number", arg);
231 : }
232 : break;
233 :
234 0 : case OPT_NO_OF_TAGS:
235 0 : config->no_of_tags = strtol(arg, &end, 0);
236 0 : if(end==arg) {
237 0 : argp_error(state, "'%s' is not a number", arg);
238 : }
239 : break;
240 :
241 6 : case 's':
242 6 : config->dcsport = strtol(arg, &end, 0);
243 6 : if(end==arg) {
244 0 : argp_error(state, "'%s' is not a number", arg);
245 : }
246 : break;
247 :
248 4 : case 'u':
249 4 : config->elinks[config->num_elinks] = strtol(arg, &end, 0);
250 4 : config->has_streams[config->num_elinks] = 1;
251 4 : config->num_elinks++;
252 4 : if(end==arg) {
253 0 : argp_error(state, "'%s' is not a number", arg);
254 : }
255 : break;
256 :
257 0 : case OPT_STATS_OUT:
258 0 : config->statistics_fifo = strdup(arg);
259 0 : break;
260 :
261 0 : case OPT_STATS_PERIOD:
262 0 : config->statistics_period = strtol(arg, &end, 0);
263 0 : if(end==arg) {
264 0 : argp_error(state, "'%s' is not a number", arg);
265 : }
266 : break;
267 :
268 44 : case OPT_BUS_DIR:
269 44 : config->bus_dir = strdup(arg);
270 44 : break;
271 :
272 44 : case OPT_BUS_GROUPNAME:
273 44 : config->bus_groupname = strdup(arg);
274 44 : break;
275 :
276 2 : case OPT_ERROR_OUT:
277 2 : config->error_fifo = strdup(arg);
278 2 : break;
279 :
280 0 : case OPT_CO:
281 0 : config->co = strtol(arg, &end, 0);
282 0 : if(end==arg) {
283 0 : argp_error(state, "'%s' is not a number", arg);
284 : }
285 0 : config->did = get_did_from_co(config->co, config->vid);
286 0 : config->cid = get_cid_from_co(config->co, config->vid);
287 0 : break;
288 :
289 44 : case OPT_DID:
290 44 : config->did = strtol(arg, &end, 0);
291 44 : if(end==arg) {
292 0 : argp_error(state, "'%s' is not a number", arg);
293 : }
294 : break;
295 :
296 44 : case OPT_CID:
297 44 : config->cid = strtol(arg, &end, 0);
298 44 : if(end==arg) {
299 0 : argp_error(state, "'%s' is not a number", arg);
300 : }
301 : break;
302 :
303 0 : case OPT_VID:
304 0 : config->vid = strtol(arg, &end, 0);
305 0 : if(end==arg) {
306 0 : argp_error(state, "'%s' is not a number", arg);
307 : }
308 : break;
309 :
310 4 : case OPT_TTC2H_ENABLE:
311 4 : config->ttc2h_enable = 1;
312 4 : break;
313 :
314 42 : case OPT_TTC2H_PORT:
315 42 : config->ttcport = strtol(arg, &end, 0);
316 42 : if(end==arg) {
317 0 : argp_error(state, "'%s' is not a number", arg);
318 : }
319 : break;
320 :
321 0 : case OPT_DCS_PAGES:
322 0 : config->dcs_netio_pages = strtol(arg, &end, 0);
323 0 : if(end==arg) {
324 0 : argp_error(state, "'%s' is not a number", arg);
325 : }
326 : break;
327 :
328 0 : case OPT_DCS_PAGESIZE:
329 0 : config->dcs_netio_pagesize = strtol(arg, &end, 0);
330 0 : if(end==arg) {
331 0 : argp_error(state, "'%s' is not a number", arg);
332 : }
333 : break;
334 :
335 0 : case OPT_DCS_WATERMARK:
336 0 : config->dcs_netio_watermark = strtol(arg, &end, 0);
337 0 : if(end==arg) {
338 0 : argp_error(state, "'%s' is not a number", arg);
339 : }
340 : break;
341 :
342 0 : case OPT_DCS_TIMEOUT:
343 0 : config->dcs_netio_timeout = strtol(arg, &end, 0);
344 0 : if(end==arg) {
345 0 : argp_error(state, "'%s' is not a number", arg);
346 : }
347 : break;
348 :
349 6 : case OPT_DCS_UNBUFFERED:
350 6 : config->dcs_buffered = 0;
351 6 : break;
352 :
353 0 : case OPT_DCS_RATE_LIMIT:
354 0 : config->dcs_rate_limit = strtol(arg, &end, 0);
355 0 : if(end==arg) {
356 0 : argp_error(state, "'%s' is not a number", arg);
357 : }
358 : break;
359 :
360 0 : case OPT_DCS_SIZE_LIMIT:
361 0 : config->dcs_size_limit = strtol(arg, &end, 0);
362 0 : if(end==arg) {
363 0 : argp_error(state, "'%s' is not a number", arg);
364 : }
365 : break;
366 :
367 0 : case 'D':
368 0 : config->dmaid = strtol(arg, &end, 0);
369 0 : if(end==arg) {
370 0 : argp_error(state, "'%s' is not a DMA descriptor id", arg);
371 : }
372 : break;
373 :
374 0 : case 'P':
375 0 : config->poll_time = strtol(arg, &end, 0);
376 0 : if(end==arg) {
377 0 : argp_error(state, "'%s' is not a number", arg);
378 : }
379 : break;
380 :
381 13 : case 'm':
382 13 : config->full_mode = 1;
383 13 : break;
384 :
385 0 : case OPT_BUF:
386 0 : config->buffered = 1;
387 0 : break;
388 :
389 0 : case OPT_MAX_BUF_CHUNK:
390 0 : config->max_buf_chunk_size = strtol(arg, &end, 0);
391 0 : if(end==arg) {
392 0 : argp_error(state, "'%s' is not a number", arg);
393 : }
394 : break;
395 :
396 0 : case OPT_REGMAP:
397 0 : config->regmap = strtol(arg, &end, 0);
398 0 : if(end==arg) {
399 0 : argp_error(state, "'%s' is not a number", arg);
400 : }
401 : break;
402 :
403 1 : case OPT_BLOCK_SIZE:
404 1 : config->block_size = strtol(arg, &end, 0);
405 1 : if(end==arg) {
406 0 : argp_error(state, "'%s' is not a number", arg);
407 : }
408 : break;
409 :
410 42 : case OPT_VMEM:
411 42 : config->vmem = 1;
412 42 : break;
413 :
414 12 : case OPT_NO_REPEAT:
415 12 : config->repeat = 0;
416 12 : break;
417 :
418 2 : case OPT_FREE_PREVIOUS_CMEM:
419 2 : config->free_previous_cmem = 1;
420 2 : break;
421 :
422 2 : case OPT_BLOCK_RATE:
423 2 : config->block_rate = strtol(arg, &end, 0);
424 2 : if(end==arg) {
425 0 : argp_error(state, "'%s' is not a number", arg);
426 : }
427 : break;
428 :
429 44 : case ARGP_KEY_ARG:
430 44 : if (state->arg_num >= 1)
431 : /* Too many arguments. */
432 0 : argp_usage (state);
433 :
434 44 : config->file = strdup(arg);
435 :
436 44 : break;
437 :
438 44 : case ARGP_KEY_END:
439 44 : if (state->arg_num < 1)
440 : /* Not enough arguments. */
441 0 : argp_usage (state);
442 : break;
443 :
444 : default:
445 : return ARGP_ERR_UNKNOWN;
446 : }
447 : return 0;
448 : }
449 :
450 : /* Our argp parser. */
451 : static struct argp argp = { options, parse_opt, args_doc, doc };
452 :
453 :
454 44 : void cli_parse(int argc, char **argv, struct config* config)
455 : {
456 44 : snprintf(buf, sizeof buf, "%s %s", argv[0], FELIX_TAG);
457 :
458 : // set default values
459 44 : config->appname = argv[0];
460 44 : config->ip = "127.0.0.1";
461 44 : config->port = -1;
462 44 : config->ttcport = -1;
463 44 : config->dcsport = -1;
464 44 : config->verbose = 0;
465 44 : config->device = 0;
466 44 : config->dmaid = 0;
467 44 : config->cmem_buffersize = 1024*1024*1024;
468 :
469 44 : config->netio_pages = 256;
470 44 : config->netio_pagesize = 64*1024;
471 44 : config->netio_watermark = 56*1024;
472 44 : config->netio_timeout = 2;
473 :
474 44 : config->ttc2h_enable = 0;
475 44 : config->ttc_netio_pages = 512;
476 44 : config->ttc_netio_pagesize = 1536;
477 44 : config->ttc_netio_watermark = 1248;
478 44 : config->ttc_netio_timeout = 0;
479 :
480 44 : config->dcs_netio_pages = 512;
481 44 : config->dcs_netio_pagesize = 1024;
482 44 : config->dcs_netio_watermark = 972;
483 44 : config->dcs_netio_timeout = 1;
484 44 : config->dcs_buffered = 1;
485 44 : config->dcs_rate_limit = 0;
486 44 : config->dcs_size_limit = 20;
487 :
488 44 : config->l1id_check = 0;
489 44 : config->statistics_fifo = NULL;
490 44 : config->statistics_period = 1000;
491 44 : config->poll_time = 0;
492 44 : config->bus_dir = "./bus";
493 44 : config->bus_groupname = "FELIX";
494 44 : config->error_fifo = NULL;
495 44 : config->co = 0;
496 44 : config->did = 0;
497 44 : config->cid = -1;
498 44 : config->vid = FID_VERSION_ID;
499 44 : config->num_elinks = 0;
500 44 : config->buffered = 0;
501 44 : config->free_previous_cmem = 0;
502 44 : config->max_buf_chunk_size = MAX_BUF_CHUNK_SIZE;
503 :
504 : // flxcard
505 :
506 : // flxfile
507 44 : config->file = NULL;
508 44 : config->full_mode = 0;
509 44 : config->regmap = REGMAP_VERSION;
510 44 : config->block_size = 1024;
511 44 : config->block_rate = 0;
512 44 : config->vmem = 0;
513 44 : config->repeat = 1;
514 44 : config->no_of_tags = 1;
515 44 : config->dcs_egroup = -1;
516 :
517 : // parse arguments
518 44 : argp_parse (&argp, argc, argv, 0, 0, config);
519 :
520 44 : if (config->cid == -1) {
521 0 : config->cid = config->device;
522 : }
523 :
524 44 : if (config->co == 0) {
525 88 : config->co = get_co_from_ids(config->did, config->cid, config->vid);
526 : }
527 :
528 44 : if (config->port < 0) {
529 0 : config->port = PORT(PORT_TOHOST_OFFSET, config->device, config->dmaid);
530 : }
531 :
532 44 : if (config->ttcport < 0) {
533 2 : config->ttcport = PORT(PORT_TTC2HOST_OFFSET, config->device, config->dmaid);
534 : }
535 :
536 44 : if (config->dcsport < 0) {
537 38 : config->dcsport = PORT(PORT_DCS_OFFSET, config->device, config->dmaid);
538 : }
539 :
540 44 : if (config->no_of_tags > 1) {
541 0 : for (size_t i = 1; i < config->no_of_tags; i++) {
542 0 : config->elinks[i] = config->elinks[0] + i;
543 0 : config->has_streams[i] = 0;
544 : }
545 0 : config->num_elinks = config->no_of_tags;
546 : }
547 44 : }
|