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 : }
|