nmxptool_getoptlong.c 29.4 KB
Newer Older
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1
2
3
4
5
6
7
8
9
/*! \file
 *
 * \brief Nanometrics Protocol Tool
 *
 * Author:
 * 	Matteo Quintiliani
 * 	Istituto Nazionale di Geofisica e Vulcanologia - Italy
 *	quintiliani@ingv.it
 *
10
 * $Id: nmxptool_getoptlong.c,v 1.83 2008-03-18 19:05:25 mtheo Exp $
Matteo Quintiliani's avatar
Matteo Quintiliani committed
11
12
13
 *
 */

14
15
16
17
18
19
20
21
22
23
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "config.h"
#include "nmxp.h"

#include "nmxptool_getoptlong.h"


24
const NMXPTOOL_PARAMS NMXPTOOL_PARAMS_DEFAULT =
25
26
{
    NULL,
27
28
    DEFAULT_PORT_DAP,
    DEFAULT_PORT_PDS,
29
30
31
    NULL,
    NULL,
    NULL,
32
33
    0.0,
    0.0,
34
    DEFAULT_INTERVAL_NO_VALUE,
35
36
    NULL,
    NULL,
37
38
    DEFAULT_STC,
    DEFAULT_RATE,
39
    NULL,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
40
    DEFAULT_DELAY,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
41
42
    DEFAULT_MAX_TOLERABLE_LATENCY,
    DEFAULT_TIMEOUTRECV,
43
    DEFAULT_VERBOSE_LEVEL,
44
    NULL,
45
    NULL,
46
    DEFAULT_BUFFERED_TIME,
47
48
    DEFAULT_N_CHANNEL,
    DEFAULT_N_USEC,
49
    DEFAULT_MAX_TIME_TO_RETRIEVE,
50
    0,
51
52
53
54
    0,
    0,
    0,
    0,
55
    0,
56
    0,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
57
    0,
58
59
60
    0
};

61
62

void nmxptool_author_support() {
63
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
64
65
Matteo Quintiliani - Istituto Nazionale di Geofisica e Vulcanologia - Italy\n\
Mail bug reports and suggestions to <%s>.\n",
66
	    NMXP_LOG_STR(PACKAGE_BUGREPORT)
67
68
69
70
71
	    );
}


void nmxptool_version() {
72
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
73
%s %s, Nanometrics tool\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
74
        (Private Data Stream 1.4, Data Access Protocol 1.0)\n",
75
	NMXP_LOG_STR(PACKAGE_NAME), NMXP_LOG_STR(PACKAGE_VERSION)
76
	/*
77
	nmxp_log_version()
78
	*/
79
	    );
Matteo Quintiliani's avatar
Matteo Quintiliani committed
80
81

    nmxptool_supports();
82
83
}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
84
void nmxptool_supports() {
85
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
86
         Enabled features: libmseed ");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
87
#ifdef HAVE_LIBMSEED
88
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "YES");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
89
#else
90
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "NO");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
91
92
#endif

93
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, ", SeedLink ");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
94
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
95
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "YES");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
96
#else
97
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "NO");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
98
99
#endif

100
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, ", Earthworm ");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
101
#ifdef HAVE_EARTHWORMOBJS
102
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "YES");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
103
#else
104
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "NO");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
105
#endif
106
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, ".\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
107
108
}

109

110
111
void nmxptool_usage(struct option long_options[])
{
112
    nmxptool_version();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
113

114
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
115
\n\
116
Usage: %s -H hostname   -l | -L\n\
117
118
             Print list of available Time Series channels\n\
             on DataServer and NaqsServer respectively.\n\
119
120
\n\
       %s -H hostname -C channellist [...]\n\
121
             Receive data in near real-time from NaqsServer by PDS.\n\
122
\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
123
       %s -H hostname -F statefile [-A SECs] [...]\n\
124
             Receive data from NaqsServer, and from DataServer if is necessary.\n\
125
126
\n\
       %s -H hostname -C channellist -s DATE -e DATE [...]\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
127
       %s -H hostname -C channellist -s DATE -t SECs [...]\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
128
             Receive data from DataServer by DAP.\n\
129
130
131
132
133
134
\n",
NMXP_LOG_STR(PACKAGE_NAME),
NMXP_LOG_STR(PACKAGE_NAME),
NMXP_LOG_STR(PACKAGE_NAME),
NMXP_LOG_STR(PACKAGE_NAME),
NMXP_LOG_STR(PACKAGE_NAME));
Matteo Quintiliani's avatar
Matteo Quintiliani committed
135
136

#ifdef HAVE_EARTHWORMOBJS
137
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
138
       %s nmxptool.d\n\
139
             Launched as Earthworm module to redirect data into the EW-Rings.\n\
140
\n", NMXP_LOG_STR(PACKAGE_NAME));
141
142
143
144
145
146
#endif

#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
       %s <option ... option> -k\n\
             Launched as SeedLink plug-in to feed the SL-Server.\n\
147
\n", NMXP_LOG_STR(PACKAGE_NAME));
Matteo Quintiliani's avatar
Matteo Quintiliani committed
148
149
#endif

150
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
151
152
       %s --help\n\
             Print this help.\n\
153
\n", NMXP_LOG_STR(PACKAGE_NAME));
154
155

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
156
Main arguments:\n\
157
158
  -H, --hostname=HOST     NaqsServer or DataServer hostname.\n\
  -C, --channels=LIST     List of NET.STA.CHAN separated by comma.\n\
159
                          NET  is optional and used only for output.\n\
160
161
                          STA  can be '*', it stands for all stations.\n\
                          CHAN can contain '?', it stands for any character.\n\
162
163
			  Network code will be assigned from the first\n\
                          pattern that includes station and channel.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
164
                          DO NOT USE with -F.\n\
165
166
167
168
                                Example: N1.AAA.HH?,N2.*.HH?,MMM.BH?\n\
                          Second pattern includes the first. Unless AAA, all\n\
                          stations with HH channels will have network to N2.\n\
                          Station MMM will have default network defined by -N.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
169
  -F, --statefile=FILE    List of channel patterns like -C. One for each line.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
170
171
172
                          Load/Save time of the last sample of each channel\n\
                          into a file with the same name, same directory,\n\
                          appending the suffix '%s'.\n\
173
174
                          Allow data continuity between program restarts.\n\
                          Related to -A and it enables -b.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
175
176
177
                          DO NOT USE with -C.\n",
			  NMXP_STR_STATE_EXT
);
178
179

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
180
  -A, --maxdataretr=SECs  Max amount of data of the past to retrieve from the\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
181
                          DataServer when program restarts (default %d) [%d..%d].\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
182
183
184
                          0 to disable connection to DataServer.\n\
                          If this option is equal to zero and -F is used,\n\
                          only data buffered by NaqsServer will be retrieved.\n\
185
186
                          It is preferable, inside the section Datastream of\n\
                          the file Naqs.ini, setting DataBufferLength to a high\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
187
188
189
190
                          value, than using -A. It allows to retrieve much more\n\
                          data of the past when the program restarts but it\n\
                          slows down the execution.\n\
                          It is extremely harmful when you have many channels.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
191
                          Related to -F.\n\
192
193
194
195
196
197
198
\n",
	    DEFAULT_MAX_TIME_TO_RETRIEVE,
	    DEFAULT_MAX_TIME_TO_RETRIEVE_MINIMUM,
	    DEFAULT_MAX_TIME_TO_RETRIEVE_MAXIMUM
);

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
199
200
PDS arguments for NaqsServer:\n\
  -P, --portpds=PORT      NaqsServer port number (default %d).\n\
201
202
  -S, --stc=SECs          Short-Term-Completion (default %d).\n\
                          -1 is for Raw Stream, no Short-Term-Completion.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
203
                             Packets contain compressed data. Related to -M, -T.\n\
204
205
                             It enables --rate=-1.\n\
                           0 decompressed packets are received in chronological\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
206
                             order without waiting for missing packets.\n\
207
                          [1..300] decompressed packets are received in\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
208
                             chronological order but waiting for missing packets\n\
209
                             at most SECs seconds.\n\
210
211
212
213
214
215
216
  -R, --rate=Hz           Receive data with specified sample rate (default %d).\n\
                          -1 for original sample rate and compressed data.\n\
                           0 for original sample rate and decompressed data.\n\
                          >0 for specified sample rate and decompressed data.\n\
  -b, --buffered          Request also recent packets into the past.\n\
  -B, --buff_date=DATE    Request also recent packets into the past\n\
                          but consider only samples after DATE.\n\
217
  -L, --listchannelsnaqs  List of available Time Series channels on NaqsServer.\n\
218
219
  -M, --maxlatency=SECs   Max tolerable latency (default %d) [%d..%d].\n\
  -T, --timeoutrecv=SECs  Time-out for flushing buffered packets.\n\
220
                          (default %d, no time-out) [%d..%d].\n\
221
                          -T is useful for retrieving Data On Demand.\n\
222
                          -M, -T are usable only with Raw Stream, -S=-1.\n\
223
224
225
                          In general, -M and -T are not used together.\n\
\n\
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
226
	    DEFAULT_PORT_PDS,
227
228
229
230
231
232
233
234
235
236
237
	    DEFAULT_STC,
	    DEFAULT_RATE,
	    DEFAULT_MAX_TOLERABLE_LATENCY,
	    DEFAULT_MAX_TOLERABLE_LATENCY_MINIMUM,
	    DEFAULT_MAX_TOLERABLE_LATENCY_MAXIMUM,
	    DEFAULT_TIMEOUTRECV,
	    DEFAULT_TIMEOUTRECV_MINIMUM,
	    DEFAULT_TIMEOUTRECV_MAXIMUM
	  );

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
238
DAP arguments for DataServer:\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
239
  -D, --portdap=PORT      DataServer port number (default %d).\n\
240
241
242
243
244
245
246
  -s, --start_time=DATE   Start time in date format.\n\
  -e, --end_time=DATE     End time in date format.\n\
                          DATE can be in formats:\n\
                              <date>,<time> | <date>\n\
                          where:\n\
                              <date> = yyyy/mm/dd | yyy.jjj\n\
                              <time> = hh:mm:ss | hh:mm:ss.dddd | hh:mm\n\
247
248
249
  -t, --interval=TIME     Time interval from start_time (greater than zero).\n\
                          TIME is in seconds, otherwise append 'm' for minutes\n\
                          'h' for hours or 'd' for days. [1 sec .. %d days]\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
250
                          DO NOT USE with -e.\n\
251
252
253
  -d, --delay=SECs        Receive continuosly data with delay [%d..%d].\n\
  -u, --username=USER     DataServer username.\n\
  -p, --password=PASS     DataServer password.\n\
254
  -l, --listchannels      List of available Time Series channels on DataServer.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
255
  -i, --channelinfo       Print channelinfo (network name) when using -l.\n\
256
257
\n\
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
258
DEFAULT_PORT_DAP,
259
(DEFAULT_INTERVAL_MAXIMUM / 86400),
260
261
DEFAULT_DELAY_MINIMUM,
DEFAULT_DELAY_MAXIMUM);
262

263
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
264
Other arguments:\n\
265
  -N, --network=NET       Default output Network code. (default '%s').\n\
266
  -n, --location=LOC      Default output Location code. DISABLED!\n\
267
  -v, --verbose=level     Be verbose. level is a bitmap:\n\
268
                          %d Channel State, %d Channel, %d Raw Stream,\n\
269
270
271
                          %d CRC32, %d Connection flow,\n\
                          %d Packet Management, %d Extra, %d Date,\n\
                          %d Gap, %d DOD, %d All messages.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
272
  -g, --logdata           Print info about packet data.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
273
  -G, --logsample         Print sample values of packets. Includes -g.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
274
",
275
	    NMXP_LOG_STR(DEFAULT_NETWORK),
276
	    NMXP_LOG_D_CHANSTATE,
277
278
279
280
281
282
283
284
285
286
	    NMXP_LOG_D_CHANNEL,
	    NMXP_LOG_D_RAWSTREAM,
	    NMXP_LOG_D_CRC,
	    NMXP_LOG_D_CONNFLOW,
	    NMXP_LOG_D_PACKETMAN,
	    NMXP_LOG_D_EXTRA,
	    NMXP_LOG_D_DATE,
	    NMXP_LOG_D_GAP,
	    NMXP_LOG_D_DOD,
	    NMXP_LOG_D_ANY
287
288
289
		);

#ifdef HAVE_LIBMSEED
290
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
291
292
  -m, --writeseed         Pack received data in Mini-SEED records\n\
                          and write to a file.\n");
293
294
#endif

295
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
296
  -w, --writefile         Dump received packets to a file.\n");
297

298
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
299
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
300
  -k, --slink=pluginid    Send received data to SeedLink as a plug-in.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
301
                          THIS OPTION, INSIDE THE FILE seedlink.ini, MUST BE\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
302
303
                          THE LAST WITHOUT ADDING VALUE FOR pluginid!\n\
                          pluginid is set by SeisComP daemon.\n");
304
#endif
305

306
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\
307
  -V, --version           Print tool version.\n\
308
  -h, --help              Print this help.\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
309
310
\n");

311
    nmxptool_author_support();
312
313
314
315
316

    /*
    if(long_options) {
	int i=0;
	while(long_options[i].name) {
317
318
319
	    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "%s %d %d %d %c\n",
	    NMXP_LOG_STR(long_options[i].name), long_options[i].has_arg,
	    (long_options[i].flag)? *(long_options[i].flag) : 0, long_options[i].val, long_options[i].val);
320
321
322
323
324
325
326
	    i++;
	}
    }
    */
}


327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#define MAXSIZE_LINE_CHAN_STATE 2048
#define MAXSIZECHANNELSTRINGARGUMENT 8000
#define MAXSIZE_CHANNEL_STRING 64

char *get_channel_list_argument_from_state_file(const char *filename) {
    char *ret_channel_string = NULL;
    char line[MAXSIZE_LINE_CHAN_STATE];
    char str_chan[MAXSIZE_CHANNEL_STRING];
    int k;
    FILE *fstatefile = NULL;

    fstatefile = fopen(filename, "r");

    /* Read only channel names from state file */
    if(fstatefile) {
	ret_channel_string = (char *) malloc (MAXSIZECHANNELSTRINGARGUMENT);
	ret_channel_string[0] = 0;
	while(fgets(line, MAXSIZE_LINE_CHAN_STATE, fstatefile) != NULL) {
	    k = 0;
	    while(line[k] != 0
		    &&  line[k] != ' '
		    &&  line[k] != 10
		    &&  line[k] != 13
		    &&  k < MAXSIZE_CHANNEL_STRING) {
		str_chan[k] = line[k];
		k++;
	    }
	    str_chan[k] = 0;
	    if(ret_channel_string[0] == 0) {
		strncpy(ret_channel_string, str_chan, MAXSIZECHANNELSTRINGARGUMENT);
	    } else {
		strncat(ret_channel_string, ",", MAXSIZECHANNELSTRINGARGUMENT);
		strncat(ret_channel_string, str_chan, MAXSIZECHANNELSTRINGARGUMENT);
	    }
	}
	fclose(fstatefile);
    }
    return ret_channel_string;
}

367
int nmxptool_getopt_long(int argc, char **argv, NMXPTOOL_PARAMS *params)
368
{
369
370
    int ret_errors = 0;

371
    NMXP_TM_T tmp_tmt;
372
373
374
375
    int i;
    char one_time_option[255];
    int c;

376
377
378
379
    int len_int, j;
    char unit = 'X';
    char str_interval[100];

380
381
382
383
384
385
386
387
    struct option long_options[] =
    {
	/* These options set a flag. */
	/* It is not safe use reference to params in this way */
	/* {"verbose",        no_argument,       &(params->flag_verbose), 1}, */
	/* {"quiet",          no_argument,       &(params->flag_verbose), 0}, */
	/* These options don't set a flag.
	 *                   We distinguish them by their indices. */
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
	{"hostname",     required_argument, NULL, 'H'},
	{"portpds",      required_argument, NULL, 'P'},
	{"portdap",      required_argument, NULL, 'D'},
	{"channels",     required_argument, NULL, 'C'},
	{"network",      required_argument, NULL, 'N'},
	{"location",     required_argument, NULL, 'n'},
	{"stc",          required_argument, NULL, 'S'},
	{"rate",         required_argument, NULL, 'R'},
	{"start_time",   required_argument, NULL, 's'},
	{"end_time",     required_argument, NULL, 'e'},
	{"interval",     required_argument, NULL, 't'},
	{"delay",        required_argument, NULL, 'd'},
	{"username",     required_argument, NULL, 'u'},
	{"password",     required_argument, NULL, 'p'},
	{"maxlatency",   required_argument, NULL, 'M'},
	{"timeoutrecv",  required_argument, NULL, 'T'},
	{"verbose",      required_argument, NULL, 'v'},
	{"bufferedt",    required_argument, NULL, 'B'},
406
	{"maxdataretr",  required_argument, NULL, 'A'},
407
	/* Following are flags */
408
	{"logdata",      no_argument,       NULL, 'g'},
Matteo Quintiliani's avatar
Matteo Quintiliani committed
409
	{"logsample",    no_argument,       NULL, 'G'},
410
411
412
413
	{"buffered",     no_argument,       NULL, 'b'},
	{"listchannels", no_argument,       NULL, 'l'},
	{"listchannelsnaqs", no_argument,   NULL, 'L'},
	{"channelinfo",  no_argument,       NULL, 'i'},
414
#ifdef HAVE_LIBMSEED
415
	{"writeseed",    no_argument,       NULL, 'm'},
416
#endif
417
	{"writefile",    no_argument,       NULL, 'w'},
418
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
419
	{"slink",        required_argument, NULL, 'k'},
420
#endif
421
422
423
	{"statefile",    required_argument, NULL, 'F'},
	{"help",         no_argument,       NULL, 'h'},
	{"version",      no_argument,       NULL, 'V'},
424
425
426
	{0, 0, 0, 0}
    };

Matteo Quintiliani's avatar
Matteo Quintiliani committed
427
    char optstr[300] = "H:P:D:C:N:n:S:R:s:e:t:d:u:p:M:T:v:B:A:F:gGblLiwhV";
428

Matteo Quintiliani's avatar
Matteo Quintiliani committed
429
430
431
    int option_index = 0;


432
433
434
#ifdef HAVE_LIBMSEED
    strcat(optstr, "m");
#endif
435

436
437
438
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
    strcat(optstr, "k:");
#endif
439
440
441
442
443
444
445
446
447
448


    /* getopt_long stores the option index here. */
    /* init array for checking one time option */
    for(i=0; i<255; i++) {
	one_time_option[i] = 0;
    }


    /* init params */
449
    memcpy(params, &NMXPTOOL_PARAMS_DEFAULT, sizeof(NMXPTOOL_PARAMS_DEFAULT));
450

451
452
453
454
455
456
457
458
459
460
461
462
463
464
    /* Check number of command line arguments for earthworm */
    if (argc == 2)
    {
	int l = strlen(argv[1]);
	if(l >= 3) {
	    if(argv[1][0] != '-') {
		if(argv[1][l-2] == '.'  &&  argv[1][l-1] == 'd') {
		    params->ew_configuration_file = argv[1];
		    return 0;
		}
	    }
	}
    }

465
466
467
468
469
470
471
    while ( (c = getopt_long (argc, argv, optstr, long_options, &option_index)) != -1) {

	/* BE CAREFUL if use synonym options !!! */
	one_time_option[c]++;

	if(one_time_option[c] > 1) {
	    ret_errors++;
472
	    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "Replicated option -%c (value %s)\n", c, NMXP_LOG_STR(optarg));
473
474
475
476
477
478
479
	} else {
	    switch (c)
	    {
		case 0:
		    /* If this option set a flag, do nothing else now. */
		    if (long_options[option_index].flag != 0)
			break;
480
481
482
483
484
		    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "option %s",
			    NMXP_LOG_STR(long_options[option_index].name));
		    if (optarg) {
			nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, " with arg %s", NMXP_LOG_STR(optarg));
		    }
485
		    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\n");
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
		    break;

		case 'H':
		    params->hostname = optarg;
		    break;

		case 'P':
		    params->portnumberpds = atoi(optarg);
		    break;

		case 'D':
		    params->portnumberdap = atoi(optarg);
		    break;

		case 'C':
501
		    if(params->channels) {
502
503
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY,
				"Channels have been already defined by State File (option -F)!\n");
504
505
506
507
			ret_errors++;
		    } else {
			params->channels = optarg;
		    }
508
509
510
511
512
513
		    break;

		case 'N':
		    params->network = optarg;
		    break;

514
		case 'n':
515
516
517
518
519
		    if(1) {
			nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Location is currently disabled!\n");
		    } else {
			params->location = optarg;
		    }
520
521
		    break;

522
523
		case 'S':
		    params->stc = atoi(optarg);
524
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Short-Term-Completion %d.\n", params->stc);
525
526
527
528
529
530
		    break;

		case 'R':
		    params->rate = atoi(optarg);
		    break;

531
		case 's':
532
		    if(nmxp_data_parse_date(optarg, &tmp_tmt) == -1) {
533
			/* MESSAGE ERROR */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
534
			ret_errors++;
535
		    } else {
536
			params->start_time = nmxp_data_tm_to_time(&tmp_tmt);
537
538
539
540
		    }
		    break;

		case 'e':
541
		    if(nmxp_data_parse_date(optarg, &tmp_tmt) == -1) {
542
			/* MESSAGE ERROR */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
543
			ret_errors++;
544
		    } else {
545
			params->end_time = nmxp_data_tm_to_time(&tmp_tmt);
546
547
548
		    }
		    break;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
549
		case 't':
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
		    strncpy(str_interval, optarg, 100);
		    len_int = strlen(str_interval);
		    if(len_int <= 0) {
			/* ERROR */
			ret_errors++;
		    } else {
			j=0;
			while(j < len_int  && str_interval[j] >= '0' && str_interval[j] <= '9') {
			    j++;
			}
			if(j < len_int) {
			    if(j == len_int-1) {
				unit = str_interval[j];
				str_interval[j] = 0;
				if(unit == 'm' || unit == 'h' || unit == 'd') {
				    params->interval = atoi(str_interval);
				    switch(unit) {
					case 'm' :
					    params->interval *= 60;
					    break;
					case 'h' :
					    params->interval *= ( 60 * 60 );
					    break;
					case 'd' :
					    params->interval *= ( 60 * 60 * 24 );
					    break;
				    }
				} else {
				    ret_errors++;
				    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY,
					    "Syntax of interval is not correct!\n");
				}
			    } else {
				ret_errors++;
				nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY,
					"Syntax of interval is not correct!\n");
			    }
			} else {
			    /* All numbers, then seconds */
			    params->interval = atoi(str_interval);
			}

		    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
594
595
		    break;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
596
597
598
599
		case 'd':
		    params->delay = atoi(optarg);
		    break;

600
601
602
603
604
605
606
607
		case 'u':
		    params->datas_username = optarg;
		    break;

		case 'p':
		    params->datas_password = optarg;
		    break;

608
		case 'M':
Matteo Quintiliani's avatar
Matteo Quintiliani committed
609
		    params->max_tolerable_latency = atoi(optarg);
610
611
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Max_tolerable_latency %d\n",
			    params->max_tolerable_latency);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
612
613
		    break;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
614
		case 'T':
615
		    params->timeoutrecv = atoi(optarg);
616
617
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Time-out receiving %d\n",
			    params->timeoutrecv);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
618
619
		    break;

620
621
622
623
		case 'v':
		    params->verbose_level = atoi(optarg);
		    break;

624
625
626
		case 'B':
		    params->flag_buffered = 1;
		    if(nmxp_data_parse_date(optarg, &tmp_tmt) == -1) {
627
			/* MESSAGE ERROR */
628
629
630
631
632
633
			ret_errors++;
		    } else {
			params->buffered_time = nmxp_data_tm_to_time(&tmp_tmt);
		    }
		    break;

634
635
		case 'A':
		    if(optarg) {
636
			params->max_data_to_retrieve = atoi(optarg);
637
		    }
638
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Max_time_to_retrieve %d\n", params->max_data_to_retrieve);
639
		    break;
640

641
642
643
644
645
646
647
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
		case 'k':
		    params->flag_slink = 1;
		    params->plugin_slink = optarg;
		    break;
#endif

648
		case 'F':
649
		    params->flag_buffered = 1;
650
		    params->statefile = optarg;
651
652
653
654
655
656
		    if(params->channels == NULL) {
			params->channels = get_channel_list_argument_from_state_file(params->statefile);
			if(params->channels) {
			    /* Do nothing */
			} else {
			    ret_errors++;
657
658
			    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY,
				    "State file %s not found or unable to read!\n", NMXP_LOG_STR(params->statefile));
659
			}
660
661
		    } else {
			ret_errors++;
662
663
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY,
				"Channels have been already defined by option -C!\n");
664
665
666
		    }
		    break;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
667
		case 'g':
668
669
670
		    params->flag_logdata = 1;
		    break;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
671
		case 'G':
Matteo Quintiliani's avatar
Matteo Quintiliani committed
672
		    params->flag_logdata = 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
673
674
675
		    params->flag_logsample = 1;
		    break;

676
		case 'b':
677
		    params->flag_buffered = 1;
678
679
		    break;

680
681
682
683
		case 'l':
		    params->flag_listchannels = 1;
		    break;

684
685
686
687
		case 'L':
		    params->flag_listchannelsnaqs = 1;
		    break;

688
689
690
691
		case 'i':
		    params->flag_request_channelinfo = 1;
		    break;

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
#ifdef HAVE_LIBMSEED
		case 'm':
		    params->flag_writeseed = 1;
		    break;
#endif

		case 'w':
		    params->flag_writefile = 1;
		    break;

		case 'h':
		    nmxptool_usage(long_options);
		    exit (1);
		    break;

707
708
		case 'V':
		    nmxptool_version();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
709
		    nmxptool_author_support();
710
711
712
		    exit (1);
		    break;

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
		case '?':
		    /* getopt_long already printed an error message. */
		    ret_errors++;
		    break;

		default:
		    nmxptool_usage(long_options);
		    exit (1);
	    }
	}
    }

    /* Print any remaining command line arguments (not options). */
    if (optind < argc)
    {
	ret_errors += optind;

730
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "non-option ARGV-elements: ");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
731
732
	while (optind < argc) {
	    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "%s ",
733
734
		    NMXP_LOG_STR(argv[optind]));
	    optind++;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
735
	}
736
737
738
739
740
741
742
	putchar ('\n');
    }

    return ret_errors;
}


743
744
745
746
747
void nmxptool_log_params(NMXPTOOL_PARAMS *params) {
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
    char *hostname: %s\n\
    int portnumberdap: %d\n\
    int portnumberpds: %d\n\
748
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
749
    NMXP_LOG_STR(params->hostname),
750
751
752
753
754
    params->portnumberdap,
    params->portnumberpds
);

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
755
    char *channels: %s\n\
756
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
757
    NMXP_LOG_STR(params->channels)
758
759
760
);

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
761
762
763
764
765
    char *network: %s\n\
    char *location: %s\n\
    double start_time: %f\n\
    double end_time: %f\n\
    int32_t interval: %d\n\
766
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
767
768
    NMXP_LOG_STR(params->network),
    NMXP_LOG_STR(params->location),
769
770
771
772
773
774
775
    params->start_time,
    params->end_time,
    params->interval
);


    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
776
777
    char *datas_username: %s\n\
    char *datas_password: %s\n\
778
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
779
780
    NMXP_LOG_STR(params->datas_username),
    NMXP_LOG_STR(params->datas_password)
781
782
783
);

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
784
785
786
787
788
789
790
    int32_t stc: %d\n\
    int32_t rate: %d\n\
    char *plugin_slink: %s\n\
    int32_t delay: %d\n\
    int32_t max_tolerable_latency: %d\n\
    int32_t timeoutrecv: %d\n\
    int32_t verbose_level: %d\n\
791
792
793
",
    params->stc,
    params->rate,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
794
    NMXP_LOG_STR(params->plugin_slink),
795
796
797
798
799
800
801
    params->delay,
    params->max_tolerable_latency,
    params->timeoutrecv,
    params->verbose_level
);

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
802
803
    char *ew_configuration_file: %s\n\
    char *statefile: %s\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
804
    int32_t max_data_to_retrieve: %d\n\
805
",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
806
807
    NMXP_LOG_STR(params->ew_configuration_file),
    NMXP_LOG_STR(params->statefile),
Matteo Quintiliani's avatar
Matteo Quintiliani committed
808
    params->max_data_to_retrieve
809
810
811
);

    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_EXTRA, "\
812
813
814
815
816
817
818
819
820
    double buffered_time: %f\n\
    int flag_writeseed: %d\n\
    int flag_listchannels: %d\n\
    int flag_listchannelsnaqs: %d\n\
    int flag_request_channelinfo: %d\n\
    int flag_writefile: %d\n\
    int flag_slink: %d\n\
    int flag_buffered: %d\n\
    int flag_logdata: %d\n\
Matteo Quintiliani's avatar
Matteo Quintiliani committed
821
    int flag_logsample: %d\n\
822
823
824
825
826
827
828
829
830
",
    params->buffered_time,
    params->flag_writeseed,
    params->flag_listchannels,
    params->flag_listchannelsnaqs,
    params->flag_request_channelinfo,
    params->flag_writefile,
    params->flag_slink,
    params->flag_buffered,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
831
832
    params->flag_logdata,
    params->flag_logsample
833
834
835
    );
}

836
837


838
int nmxptool_check_params(NMXPTOOL_PARAMS *params) {
839
840
    int ret = 0;

841
842
843
    if(params->ew_configuration_file != NULL) {
	/* Do nothing */
    } else if(params->hostname == NULL) {
844
	ret = -1;
845
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<hostname> is required!\n");
846
    } else if(params->flag_listchannels) {
847
848
849
850
851
	if(params->flag_listchannelsnaqs) {
	    ret = -1;
	    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "-l and -L can not be used together!\n");
	}
    } else if(params->flag_listchannelsnaqs) {
852
853
854
	/* Do nothing */
    } else if(params->hostname == NULL) {
	ret = -1;
855
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<hostname> is required!\n");
856
857
    } else if(params->channels == NULL) {
	ret = -1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
858
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "Channel list is required!\n");
859
    } else if(params->start_time == 0.0 &&  params->end_time != 0.0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
860
	ret = -1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
861
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<end_time> is required when declaring <start_time>!\n");
862
    } else if(params->start_time != 0.0  &&  params->end_time != 0.0  && params->interval != DEFAULT_INTERVAL_NO_VALUE) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
863
	ret = -1;
864
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<start_time> has to be used with either <end_time> or <interval>!\n");
865
866
867
    } else if(params->interval != DEFAULT_INTERVAL_NO_VALUE && params->interval <= 0) {
	ret = -1;
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<interval> has to be greater than zero!\n");
868
869
870
    } else if(params->interval > DEFAULT_INTERVAL_MAXIMUM) {
	ret = -1;
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<interval> has to be less than %d seconds (%d days)!\n", DEFAULT_INTERVAL_MAXIMUM, DEFAULT_INTERVAL_MAXIMUM / 86400);
871
    } else if(params->start_time != 0.0   &&   params->end_time != 0.0
872
	    && params->start_time >= params->end_time) {
873
	ret = -1;
874
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<start_time> is less than <end_time>!\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
875
    } else if(params->stc < DEFAULT_STC_MINIMUM   ||   params->stc > DEFAULT_STC_MAXIMUM) {
876
	ret = -1;
877
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<stc> has to be in the interval [%d..%d] secs.\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
878
		DEFAULT_STC_MINIMUM, DEFAULT_STC_MAXIMUM);
879
880
    } else if(params->stc == -1   &&   params->rate != DEFAULT_RATE) {
	ret = -1;
881
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<rate> has to be equal to -1 when <stc> is equal to -1 (Raw Stream).\n");
882
    } else if(params->delay > 0 && params->start_time != 0.0   &&   params->end_time != 0.0) {
883
	ret = -1;
884
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<delay> can not be used with options <start_time> and <end_time>.\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
885
886
887
    } else if( params->delay != DEFAULT_DELAY &&
	    (params->delay < DEFAULT_DELAY_MINIMUM  || params->delay > DEFAULT_DELAY_MAXIMUM) ) {
	ret = -1;
888
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<delay> has to be in the interval [%d..%d] secs.\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
889
		DEFAULT_DELAY_MINIMUM, DEFAULT_DELAY_MAXIMUM);
890
891
892
893
    } else if(params->verbose_level < DEFAULT_VERBOSE_LEVEL_MINIMUM  ||  params->verbose_level > DEFAULT_VERBOSE_LEVEL_MAXIMUM) {
	ret = -1;
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<verbose_level> has to be in the interval [%d..%d].\n",
		DEFAULT_VERBOSE_LEVEL_MINIMUM, DEFAULT_VERBOSE_LEVEL_MAXIMUM);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
894
895
    } else if(params->rate < DEFAULT_RATE_MINIMUM  ||  params->rate > DEFAULT_RATE_MAXIMUM) {
	ret = -1;
896
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<rate> has to be in the interval [%d..%d].\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
897
		DEFAULT_RATE_MINIMUM, DEFAULT_RATE_MAXIMUM);
898
    } else if(params->rate != -1 && params->start_time != 0.0   &&   params->end_time != 0.0) {
899
	ret = -1;
900
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<rate> can not be used with options <start_time> and <end_time>.\n");
901
    } else if(params->flag_buffered != 0 && params->start_time != 0.0   &&   params->end_time != 0.0) {
902
	ret = -1;
903
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "<buffered> can not be used with options <start_time> and <end_time>.\n");
904
905
    } else if( (params->max_data_to_retrieve < DEFAULT_MAX_TIME_TO_RETRIEVE_MINIMUM  ||
		params->max_data_to_retrieve > DEFAULT_MAX_TIME_TO_RETRIEVE_MAXIMUM)) {
906
	ret = -1;
907
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<maxdataretr> has to be within [%d..%d].\n",
908
909
		DEFAULT_MAX_TIME_TO_RETRIEVE_MINIMUM,
		DEFAULT_MAX_TIME_TO_RETRIEVE_MAXIMUM);
910
    } else if( params->stc == -1
Matteo Quintiliani's avatar
Matteo Quintiliani committed
911
912
	    && (params->max_tolerable_latency < DEFAULT_MAX_TOLERABLE_LATENCY_MINIMUM  ||
		params->max_tolerable_latency > DEFAULT_MAX_TOLERABLE_LATENCY_MAXIMUM)) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
913
	ret = -1;
914
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<maxlatency> has to be within [%d..%d].\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
915
916
917
918
919
920
921
		DEFAULT_MAX_TOLERABLE_LATENCY_MINIMUM,
		DEFAULT_MAX_TOLERABLE_LATENCY_MAXIMUM);
    } else if( params->stc == -1
	    && (params->timeoutrecv < DEFAULT_TIMEOUTRECV_MINIMUM  ||
		params->timeoutrecv > DEFAULT_TIMEOUTRECV_MAXIMUM)) {
	if(params->timeoutrecv != 0) {
	    ret = -1;
922
	    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "<timeoutrecv> has to be within [%d..%d] or equal to zero for not time-out.\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
923
924
925
926
		    DEFAULT_TIMEOUTRECV_MINIMUM,
		    DEFAULT_TIMEOUTRECV_MAXIMUM);
	}
    } else if( params->stc != -1 && params->max_tolerable_latency > 0 ){
927
	nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "<maxlatency> ignored since not defined --stc=-1.\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
928
929
    } else if(params->stc != -1 && params->timeoutrecv > 0) {
	params->timeoutrecv = 0;
930
	nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "<timeoutrecv> ignored since not defined --stc=-1.\n");
931
    }
932

Matteo Quintiliani's avatar
Matteo Quintiliani committed
933
    /*
934
    if( params->stc == -1 ) {
935
	nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "<maxlatency> is equal to %d sec.\n", params->max_tolerable_latency);
936
    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
937
    */
938

939
940
    return ret;
}