nmxptool.c 28 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.c,v 1.99 2007-12-17 10:36:57 mtheo Exp $
Matteo Quintiliani's avatar
Matteo Quintiliani committed
11
 *
Matteo Quintiliani's avatar
Matteo Quintiliani committed
12
13
 */

Matteo Quintiliani's avatar
Matteo Quintiliani committed
14
15
#include "config.h"

16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Matteo Quintiliani's avatar
Matteo Quintiliani committed
19
#include <errno.h>
20
21

#include <nmxp.h>
Matteo Quintiliani's avatar
Matteo Quintiliani committed
22

Matteo Quintiliani's avatar
Matteo Quintiliani committed
23
#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
24
25
26
#include <signal.h>
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
27
28
29
30
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif

31
#include "nmxptool_getoptlong.h"
32
33

#ifdef HAVE_EARTHWORMOBJS
34
#include "nmxptool_ew.h"
35
#endif
36

37
38
39
#ifdef HAVE_LIBMSEED
#include <libmseed.h>
#endif
40

41
42
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_H
#include "seedlink_plugin.h"
43
44
#endif

45
46
47
#define CURRENT_NETWORK ( (params.network)? params.network : DEFAULT_NETWORK )
#define NETCODE_OR_CURRENT_NETWORK ( (network_code[0] != 0)? network_code : CURRENT_NETWORK )

Matteo Quintiliani's avatar
Matteo Quintiliani committed
48
#define GAP_TOLLERANCE 0.001
49

50
51
52
typedef struct {
    int significant;
    double last_time;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
53
    time_t last_time_call_raw_stream;
54
    int32_t x_1;
55
    NMXP_RAW_STREAM_DATA raw_stream_buffer;
56
57
} NMXPTOOL_CHAN_SEQ;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
58
59

#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
60
61
static void clientShutdown(int sig);
static void clientDummyHandler(int sig);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
62
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
63

Matteo Quintiliani's avatar
Matteo Quintiliani committed
64
static void save_channel_states();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
65
66
static void flushing_raw_data_stream();

67
#ifdef HAVE_LIBMSEED
Matteo Quintiliani's avatar
Matteo Quintiliani committed
68
int nmxptool_write_miniseed(NMXP_DATA_PROCESS *pd);
69
70
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
71
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
Matteo Quintiliani's avatar
Matteo Quintiliani committed
72
int nmxptool_send_raw_depoch(NMXP_DATA_PROCESS *pd);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
73
74
#endif

75
int nmxptool_print_seq_no(NMXP_DATA_PROCESS *pd);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
76
77

int nmxptool_check_and_log_gap(double time1, double time2, const double gap_tollerance, const char *station, const char *channel);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
78
void nmxptool_str_time_to_filename(char *str_time);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
79
80


81
82
83
84
85
/* Global variable for main program and handling terminitation program */
NMXPTOOL_PARAMS params;
int naqssock = 0;
FILE *outfile = NULL;
NMXP_CHAN_LIST *channelList = NULL;
86
NMXP_CHAN_LIST_NET *channelList_subset = NULL;
87
NMXPTOOL_CHAN_SEQ *channelListSeq = NULL;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
88
89
90
int n_func_pd = 0;
int (*p_func_pd[NMXP_MAX_FUNC_PD]) (NMXP_DATA_PROCESS *);

91
92
93
94
95
96
97
98

#ifdef HAVE_LIBMSEED
/* Mini-SEED variables */
NMXP_DATA_SEED data_seed;
MSRecord *msr_list_chan[MAX_N_CHAN];
#endif


99
int main (int argc, char **argv) {
100
    int32_t connection_time;
101
    int request_SOCKET_OK;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
102
    int i_chan, cur_chan = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
103
    int to_cur_chan = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
104
    int exitpdscondition;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
105
    int exitdapcondition;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
106
    time_t timeout_for_channel;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
107

Matteo Quintiliani's avatar
Matteo Quintiliani committed
108
    int span_interval = 10;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
109
110
    int time_to_sleep = 0;

111
112
    char str_start_time[200];
    char str_end_time[200];
Matteo Quintiliani's avatar
Matteo Quintiliani committed
113
    char str_pd_time[200];
114
115
116

    NMXP_MSG_SERVER type;
    void *buffer;
117
    int32_t length;
118
119
    int ret;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
120
121
    int recv_errno = 0;

122
    char filename[500];
123
    char station_code[20], channel_code[20], network_code[20];
124
125
126
127
128
129
130
131

    NMXP_DATA_PROCESS *pd;

#ifdef HAVE_LIBMSEED
    /* Init mini-SEED variables */
    nmxp_data_seed_init(&data_seed);
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
132
#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
133
134
135
136
137
138
139
    /* Signal handling, use POSIX calls with standardized semantics */
    struct sigaction sa;

    sa.sa_handler = clientDummyHandler;
    sa.sa_flags = SA_RESTART;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);
140

Matteo Quintiliani's avatar
Matteo Quintiliani committed
141
142
143
144
145
146
147
148
149
150
151
    sa.sa_handler = clientShutdown;
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGQUIT, &sa, NULL); 
    sigaction(SIGTERM, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGPIPE, &sa, NULL); 
#endif

    /* Default is normal output */
152
    nmxp_log(NMXP_LOG_SET, NMXP_LOG_D_NULL);
153
154
155
156
157
158

    /* Initialize params from argument values */
    if(nmxptool_getopt_long(argc, argv, &params) != 0) {
	return 1;
    }

159
    if(params.ew_configuration_file) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
160
161

#ifdef HAVE_EARTHWORMOBJS
162
163
	nmxp_log_init(nmxptool_ew_logit_msg, nmxptool_ew_logit_err);

Matteo Quintiliani's avatar
Matteo Quintiliani committed
164
	nmxptool_ew_configure(argv, &params);
165

Matteo Quintiliani's avatar
Matteo Quintiliani committed
166
167
168
169
170
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}
#endif
171

172
    } else {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
173

Matteo Quintiliani's avatar
Matteo Quintiliani committed
174
175
	nmxp_log_init(nmxp_log_stdout, nmxp_log_stderr);

176
177
178
179
180
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}

181
182
	/* List available channels on server */
	if(params.flag_listchannels) {
183

184
	    nmxp_getMetaChannelList(params.hostname, params.portnumberdap, NMXP_DATA_TIMESERIES, params.flag_request_channelinfo);
185
	    return 1;
186

187
188
189
190
	} else if(params.flag_listchannelsnaqs) {

	    channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
	    nmxp_chan_print_channelList(channelList);
191
	    return 1;
192

193
194
	}
    }
195

196
197
198
    nmxp_log(NMXP_LOG_SET, params.verbose_level);
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "verbose_level %d\n", params.verbose_level);

199
200
    /* Get list of available channels and get a subset list of params.channels */
    channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
201
    channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
202
203
204

    /* Check if some channel already exists */
    if(channelList_subset->number <= 0) {
205
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL, "Channels not found!\n");
206
	return 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
207
    } else {
208
	nmxp_chan_print_netchannelList(channelList_subset);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
209

210
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CHANNEL, "Init channelListSeq.\n");
211
212
213
214
215
216

	/* init channelListSeq */
	channelListSeq = (NMXPTOOL_CHAN_SEQ *) malloc(sizeof(NMXPTOOL_CHAN_SEQ) * channelList_subset->number);
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
	    channelListSeq[i_chan].significant = 0;
	    channelListSeq[i_chan].last_time = 0.0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
217
	    channelListSeq[i_chan].last_time_call_raw_stream = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
218
	    channelListSeq[i_chan].x_1 = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
219
	    nmxp_raw_stream_init(&(channelListSeq[i_chan].raw_stream_buffer), params.max_tolerable_latency, params.timeoutrecv);
220
221
	}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
222
#ifdef HAVE_LIBMSEED
223
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Init mini-SEED record list.\n");
224
225

	/* Init mini-SEED record list */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
226
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
227

228
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Init mini-SEED record for %s\n", channelList_subset->channel[i_chan].name);
229
230
231
232

	    msr_list_chan[i_chan] = msr_init(NULL);

	    /* Separate station_code and channel_code */
233
	    if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[i_chan].name, station_code, channel_code, network_code)) {
234

235
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "%s.%s.%s\n", NETCODE_OR_CURRENT_NETWORK, station_code, channel_code);
236

237
		strcpy(msr_list_chan[i_chan]->network, NETCODE_OR_CURRENT_NETWORK);
238
239
240
241
242
243
244
		strcpy(msr_list_chan[i_chan]->station, station_code);
		strcpy(msr_list_chan[i_chan]->channel, channel_code);

		msr_list_chan[i_chan]->reclen = 512;         /* byte record length */
		msr_list_chan[i_chan]->encoding = DE_STEIM1;  /* Steim 1 compression */

	    } else {
245
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL, "Channels %s error in format!\n");
246
247
248
		return 1;
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
249
250
	}
#endif
251

252
253
254
255
256
257
258
259
    }

    /* Free the complete channel list */
    if(channelList) {
	free(channelList);
	channelList = NULL;
    }

260
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "Starting comunication.\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
261

262
    /* TODO condition starting DAP or PDS */
263
    if( (params.start_time != 0.0   &&   params.end_time != 0.0)
264
265
	    || params.delay > 0
	    ) {
266

Matteo Quintiliani's avatar
Matteo Quintiliani committed
267
	if(params.delay > 0) {
268
	    params.start_time = ((double) (time(NULL) - params.delay - span_interval) / 10.0) * 10.0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
269
270
271
	    params.end_time = params.start_time + span_interval;
	}

272

273
274
275
	/* ************************************************************** */
	/* Start subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************** */
276

277
278
	/* DAP Step 1: Open a socket */
	if( (naqssock = nmxp_openSocket(params.hostname, params.portnumberdap)) == NMXP_SOCKET_ERROR) {
279
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error opening socket!\n");
280
281
	    return 1;
	}
282

283
284
	/* DAP Step 2: Read connection time */
	if(nmxp_readConnectionTime(naqssock, &connection_time) != NMXP_SOCKET_OK) {
285
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error reading connection time from server!\n");
286
287
	    return 1;
	}
288

289
290
	/* DAP Step 3: Send a ConnectRequest */
	if(nmxp_sendConnectRequest(naqssock, params.datas_username, params.datas_password, connection_time) != NMXP_SOCKET_OK) {
291
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error sending connect request!\n");
292
293
294
295
296
	    return 1;
	}

	/* DAP Step 4: Wait for a Ready message */
	if(nmxp_waitReady(naqssock) != NMXP_SOCKET_OK) {
297
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error waiting Ready message!\n");
298
299
	    return 1;
	}
300

301
302
303
304
	exitdapcondition = 1;

	while(exitdapcondition) {

305
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "start_time = %.4f - end_time = %.4f\n", params.start_time, params.end_time);
306

307
308
309
	/* Start loop for sending requests */
	i_chan=0;
	request_SOCKET_OK = NMXP_SOCKET_OK;
310

311
	while(request_SOCKET_OK == NMXP_SOCKET_OK  &&  i_chan < channelList_subset->number) {
312

313
	    /* DAP Step 5: Send Data Request */
314
	    request_SOCKET_OK = nmxp_sendDataRequest(naqssock, channelList_subset->channel[i_chan].key, (int32_t) params.start_time, (int32_t) (params.end_time + 1.0));
315

316
	    if(request_SOCKET_OK == NMXP_SOCKET_OK) {
317

318
319
320
321
322
		nmxp_data_to_str(str_start_time, params.start_time);
		nmxp_data_to_str(str_end_time, params.end_time);
		nmxptool_str_time_to_filename(str_start_time);
		nmxptool_str_time_to_filename(str_end_time);

323
324
		if(params.flag_writefile) {
		    /* Open output file */
325
326
327
328
329
330
331
332
333
334
335
336
337
		    if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[i_chan].name, station_code, channel_code, network_code)) {
			sprintf(filename, "%s.%s.%s_%s_%s.nmx",
				NETCODE_OR_CURRENT_NETWORK,
				station_code,
				channel_code,
				str_start_time,
				str_end_time);
		    } else {
			sprintf(filename, "%s_%s_%s.nmx",
				channelList_subset->channel[i_chan].name,
				str_start_time,
				str_end_time);
		    }
338

339
340
		    outfile = fopen(filename, "w");
		    if(!outfile) {
341
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!", filename);
342
		    }
343
344
345
		}

#ifdef HAVE_LIBMSEED
346
347
		if(params.flag_writeseed) {
		    /* Open output Mini-SEED file */
348
349
350
351
352
353
354
355
356
357
358
359
360
		    if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[i_chan].name, station_code, channel_code, network_code)) {
			sprintf(data_seed.filename_mseed, "%s.%s.%s_%s_%s.miniseed",
				NETCODE_OR_CURRENT_NETWORK,
				station_code,
				channel_code,
				str_start_time,
				str_end_time);
		    } else {
			sprintf(filename, "%s_%s_%s.miniseed",
				channelList_subset->channel[i_chan].name,
				str_start_time,
				str_end_time);
		    }
361

362
363
		    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
		    if(!data_seed.outfile_mseed) {
364
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!", data_seed.filename_mseed);
365
366
367
		    }
		}
#endif
368

369
370
371
		if(params.flag_writefile  &&  outfile) {
		    /* Compute SNCL line */

372
		    /* Separate station_code_old_way and channel_code_old_way */
373
		    if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[i_chan].name, station_code, channel_code, network_code)) {
374
375
376
			/* Write SNCL line */
			fprintf(outfile, "%s.%s.%s.%s\n",
				station_code,
377
				NETCODE_OR_CURRENT_NETWORK,
378
379
				channel_code,
				(params.location)? params.location : "");
380
		    }
381
382
383

		}

384
		/* DAP Step 6: Receive Data until receiving a Ready message */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
385
		ret = nmxp_receiveMessage(naqssock, &type, &buffer, &length, 0, &recv_errno);
386
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "ret = %d, type = %d\n", ret, type);
387

388
		while(ret == NMXP_SOCKET_OK   &&    type != NMXP_MSG_READY) {
389

390
		    /* Process a packet and return value in NMXP_DATA_PROCESS structure */
391
		    pd = nmxp_processCompressedData(buffer, length, channelList_subset, NETCODE_OR_CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
392
		    nmxp_data_trim(pd, params.start_time, params.end_time, 0);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
393
394

		    /* Log contents of last packet */
395
396
397
		    if(params.flag_logdata) {
			nmxp_data_log(pd);
		    }
398

399
		    /* Set cur_chan */
400
		    cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
401
402

		    /* Management of gaps */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
403
		    if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
404
405
			channelListSeq[cur_chan].significant = 1;
		    } else {
406
			if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
407
408
			    if(nmxptool_check_and_log_gap(pd->time, channelListSeq[cur_chan].last_time, GAP_TOLLERANCE, pd->station, pd->channel)) {
				channelListSeq[cur_chan].x_1 = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
409
				nmxp_data_to_str(str_pd_time, pd->time);
410
				nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_EXTRA, "%s.%s x0 set to zero at %s!\n", pd->station, pd->channel, str_pd_time);
411
			    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
412
413
			}
		    }
414
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
415
			channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
416
417
		    }

418
#ifdef HAVE_LIBMSEED
419
420
		    /* Write Mini-SEED record */
		    if(params.flag_writeseed) {
421
			nmxptool_write_miniseed(pd);
422
		    }
423
#endif
424

425
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
426
		    /* Send data to SeedLink Server */
427
		    if(params.flag_slink) {
428
			nmxptool_send_raw_depoch(pd);
429
		    }
430
431
#endif

432
433
434
		    if(params.flag_writefile  &&  outfile) {
			/* Write buffer to the output file */
			if(outfile && buffer && length > 0) {
435
			    int32_t length_int = length;
436
437
438
439
440
			    nmxp_data_swap_4b((int32_t *) &length_int);
			    fwrite(&length_int, sizeof(length_int), 1, outfile);
			    fwrite(buffer, length, 1, outfile);
			}
		    }
441

Matteo Quintiliani's avatar
Matteo Quintiliani committed
442
443
444
445
446
		    /* Store x_1 */
		    if(pd->nSamp > 0) {
			channelListSeq[cur_chan].x_1 = pd->pDataPtr[pd->nSamp-1];
		    }
		    /* Free pd->buffer */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
447
448
449
		    if(pd->buffer) {
			free(pd->buffer);
			pd->buffer = NULL;
450
		    }
451
452

		    /* Receive Data */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
453
		    ret = nmxp_receiveMessage(naqssock, &type, &buffer, &length, 0, &recv_errno);
454
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "ret = %d, type = %d\n", ret, type);
455
456
		}

457
458
459
		if(params.flag_writefile  &&  outfile) {
		    /* Close output file */
		    fclose(outfile);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
460
		    outfile = NULL;
461
462
		}

463
464
465
466
#ifdef HAVE_LIBMSEED
		if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
		    /* Close output Mini-SEED file */
		    fclose(data_seed.outfile_mseed);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
467
		    data_seed.outfile_mseed = NULL;
468
469
		}
#endif
470
471

	    }
472
473
474
	    i_chan++;
	}
	/* DAP Step 7: Repeat steps 5 and 6 for each data request */
475

Matteo Quintiliani's avatar
Matteo Quintiliani committed
476
	if(params.delay > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
477
478
	    time_to_sleep = (params.end_time - params.start_time) - (time(NULL) - (params.start_time + params.delay + span_interval));
	    if(time_to_sleep >= 0) {
479
		nmxp_sleep(time_to_sleep);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
480
	    } else {
481
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "time to sleep %d sec.\n", time_to_sleep);
482
		nmxp_sleep(3);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
483
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
484
485
486
487
488
489
	    params.start_time = params.end_time;
	    params.end_time = params.start_time + span_interval;
	} else {
	    exitdapcondition = 0;
	}

490

Matteo Quintiliani's avatar
Matteo Quintiliani committed
491
    } /* END while(exitdapcondition) */
492

493
494
495
496
497
498
499
500
501
502
503
	/* DAP Step 8: Send a Terminate message (optional) */
	nmxp_sendTerminateSubscription(naqssock, NMXP_SHUTDOWN_NORMAL, "Bye!");

	/* DAP Step 9: Close the socket */
	nmxp_closeSocket(naqssock);

	/* ************************************************************ */
	/* End subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************ */


504

Matteo Quintiliani's avatar
Matteo Quintiliani committed
505
    } else {
506

507
508
	if(params.stc == -1) {

509

510
511
512
513
	    if(params.flag_logdata) {
		p_func_pd[n_func_pd++] = nmxptool_print_seq_no;
	    }

514
515
516
517
518
519
520
521
522
523
524
525
526
#ifdef HAVE_LIBMSEED
	    /* Write Mini-SEED record */
	    if(params.flag_writeseed) {
		p_func_pd[n_func_pd++] = nmxptool_write_miniseed;
	    }
#endif

#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
	    /* Send data to SeedLink Server */
	    if(params.flag_slink) {
		p_func_pd[n_func_pd++] = nmxptool_send_raw_depoch;
	    }
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
527
528
529
530
531
532
533

#ifdef HAVE_EARTHWORMOBJS
	    if(params.ew_configuration_file) {
		p_func_pd[n_func_pd++] = nmxptool_ew_nmx2ew;
	    }
#endif

534
	}
535

536
537
538
539
540
541
542
543
544
	/* ************************************************************* */
	/* Start subscription protocol "PRIVATE DATA STREAM" version 1.4 */
	/* ************************************************************* */

	/* PDS Step 1: Open a socket */
	naqssock = nmxp_openSocket(params.hostname, params.portnumberpds);

	if(naqssock == NMXP_SOCKET_ERROR) {
	    return 1;
545
546
	}

547
548
549
550
551
552
553
554
555
556
557
558
559
	/* PDS Step 2: Send a Connect */
	if(nmxp_sendConnect(naqssock) != NMXP_SOCKET_OK) {
	    printf("Error on sendConnect()\n");
	    return 1;
	}

	/* PDS Step 3: Receive ChannelList */
	if(nmxp_receiveChannelList(naqssock, &channelList) != NMXP_SOCKET_OK) {
	    printf("Error on receiveChannelList()\n");
	    return 1;
	}

	/* Get a subset of channel from arguments */
560
	channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
561
562
563


	/* PDS Step 4: Send a Request Pending (optional) */
564
565


566
567
568
569
570
571
	/* PDS Step 5: Send AddChannels */
	/* Request Data */
	nmxp_sendAddTimeSeriesChannel(naqssock, channelList_subset, params.stc, params.rate, (params.flag_buffered)? NMXP_BUFFER_YES : NMXP_BUFFER_NO);

	/* PDS Step 6: Repeat until finished: receive and handle packets */

Matteo Quintiliani's avatar
Matteo Quintiliani committed
572
573
574
575
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed) {
	    /* Open output Mini-SEED file */
	    sprintf(data_seed.filename_mseed, "%s.realtime.miniseed",
576
		    CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
577
578
579

	    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
	    if(!data_seed.outfile_mseed) {
580
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!", data_seed.filename_mseed);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
581
	    } else {
582
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Opened file %s!\n", data_seed.filename_mseed);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
583
584
585
586
	    }
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
587
588
589
	// TODO
	exitpdscondition = 1;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
590
591
592
593
594
595
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_attach();
	}
#endif

596
597
	double after_start_time = params.buffered_time;
	int skip_current_packet = 0;
598
	
Matteo Quintiliani's avatar
Matteo Quintiliani committed
599
	while(exitpdscondition) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
600

601
	    /* Process Compressed or Decompressed Data */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
602
	    pd = nmxp_receiveData(naqssock, channelList_subset, NETCODE_OR_CURRENT_NETWORK, params.timeoutrecv, &recv_errno);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
603

604
	    if(recv_errno == 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
605
606
607
		// TODO
		exitpdscondition = 1;
	    } else {
608
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error receiving data. pd=%p recv_errno=%d\n", pd, recv_errno);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
609
610
		exitpdscondition = 0;
	    }
611

Matteo Quintiliani's avatar
Matteo Quintiliani committed
612
	    /* Log contents of last packet */
613
614
615
	    if(params.flag_logdata) {
		nmxp_data_log(pd);
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
616

617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
	    skip_current_packet = 0;
	    if(pd) {
		if(pd->time + ((double) pd->nSamp / (double) pd->sampRate) >= after_start_time) {
		    if(pd->time < after_start_time) {
			int first_nsample_to_remove = (after_start_time - pd->time) * (double) pd->sampRate;
			/* Remove the first sample in order avoiding overlap  */
			first_nsample_to_remove++;
			if(pd->nSamp > first_nsample_to_remove) {
			    pd->nSamp -= first_nsample_to_remove;
			    pd->time = after_start_time;
			    pd->pDataPtr += first_nsample_to_remove;
			    pd->x0 = pd->pDataPtr[0];
			} else {
			    skip_current_packet = 1;
			}
		    }
		} else {
		    skip_current_packet = 1;
		}
	    }

	    if(!skip_current_packet) {

Matteo Quintiliani's avatar
Matteo Quintiliani committed
640
	    if(pd) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
641
642
		/* Set cur_chan */
		cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
643
	    }
644

645
646
	    /* Manage Raw Stream */
	    if(params.stc == -1) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
647
648
649
650
651
652
653
654
655

		/* cur_char is computed only for pd != NULL */
		if(pd) {
		    nmxp_raw_stream_manage(&(channelListSeq[cur_chan].raw_stream_buffer), pd, p_func_pd, n_func_pd);
		    channelListSeq[cur_chan].last_time_call_raw_stream = nmxp_data_gmtime_now();
		}

		/* Check timeout for other channels */
		if(params.timeoutrecv > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
656
		    exitpdscondition = 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
657
658
659
660
661
		    to_cur_chan = 0;
		    while(to_cur_chan < channelList_subset->number) {
			timeout_for_channel = nmxp_data_gmtime_now() - channelListSeq[to_cur_chan].last_time_call_raw_stream;
			if(channelListSeq[to_cur_chan].last_time_call_raw_stream != 0
				&& timeout_for_channel >= params.timeoutrecv) {
662
			    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_DOD, "Timeout for channel %s (%d sec.)\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
663
664
665
666
667
668
669
670
				    channelList_subset->channel[to_cur_chan].name, timeout_for_channel);
			    nmxp_raw_stream_manage(&(channelListSeq[to_cur_chan].raw_stream_buffer), NULL, p_func_pd, n_func_pd);
			    channelListSeq[to_cur_chan].last_time_call_raw_stream = nmxp_data_gmtime_now();
			}
			to_cur_chan++;
		    }
		}

671
	    } else {
672

Matteo Quintiliani's avatar
Matteo Quintiliani committed
673
	    if(pd) {
674
675
676
677
		/* Management of gaps */
		if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].significant = 1;
		} else {
678
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
679
680
			if(nmxptool_check_and_log_gap(pd->time, channelListSeq[cur_chan].last_time, GAP_TOLLERANCE, pd->station, pd->channel)) {
			    channelListSeq[cur_chan].x_1 = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
681
			    nmxp_data_to_str(str_pd_time, pd->time);
682
			    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_EXTRA, "%s.%s x0 set to zero at %s!\n", pd->station, pd->channel, str_pd_time);
683
			}
684
		    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
685
		}
686
687
688
		if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
		}
689

Matteo Quintiliani's avatar
Matteo Quintiliani committed
690
691

#ifdef HAVE_LIBMSEED
692
693
694
695
		/* Write Mini-SEED record */
		if(params.flag_writeseed) {
		    nmxptool_write_miniseed(pd);
		}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
696
697
#endif

698
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
699
700
701
702
		/* Send data to SeedLink Server */
		if(params.flag_slink) {
		    nmxptool_send_raw_depoch(pd);
		}
703
#endif
704
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
705
	    }
706
	    } /* End skip_current_packet condition */
707

Matteo Quintiliani's avatar
Matteo Quintiliani committed
708
	    if(pd) {
709
710
711
712
713
714
715
716
717
		/* Store x_1 */
		if(pd->nSamp > 0) {
		    channelListSeq[cur_chan].x_1 = pd->pDataPtr[pd->nSamp-1];
		}
		/* Free pd->buffer */
		if(pd->buffer) {
		    free(pd->buffer);
		    pd->buffer = NULL;
		}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
718
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
719

Matteo Quintiliani's avatar
Matteo Quintiliani committed
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
#ifdef HAVE_EARTHWORMOBJS
	    if(params.ew_configuration_file) {

		/* Check if we are being asked to terminate */
		if( nmxptool_ew_check_flag_terminate() ) {
		    logit ("t", "nmxptool terminating on request\n");
		    exitpdscondition = 0;
		}

		/* Check if we need to send heartbeat message */
		nmxptool_ew_send_heartbeat_if_needed();

	    }
#endif

735
	} /* End main PDS loop */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
736
737
738
	
	/* Flush raw data stream for each channel */
	flushing_raw_data_stream();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
739
	save_channel_states();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
740

Matteo Quintiliani's avatar
Matteo Quintiliani committed
741
742
743
744
745
746
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_detach();
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
747
748
749
750
751
752
753
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	    /* Close output Mini-SEED file */
	    fclose(data_seed.outfile_mseed);
	}
#endif

754
755
756
757
758
759
760
761
762
763
764

	/* PDS Step 7: Send Terminate Subscription */
	nmxp_sendTerminateSubscription(naqssock, NMXP_SHUTDOWN_NORMAL, "Good Bye!");

	/* PDS Step 8: Close the socket */
	nmxp_closeSocket(naqssock);

	/* *********************************************************** */
	/* End subscription protocol "PRIVATE DATA STREAM" version 1.4 */
	/* *********************************************************** */

765
766


767
    }
768

769
770
771
772
773
774
775
776
777
778
#ifdef HAVE_LIBMSEED
	if(*msr_list_chan) {
	    for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
		if(msr_list_chan[i_chan]) {
		    msr_free(&(msr_list_chan[i_chan]));
		}
	    }
	}
#endif

779
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
780
	    nmxp_raw_stream_free(&(channelListSeq[i_chan].raw_stream_buffer));
781
782
	}

783
784
785
786
787
788
789
790
791
	if(channelListSeq) {
	    free(channelListSeq);
	}

	/* This has to be tha last */
	if(channelList_subset) {
	    free(channelList_subset);
	}

792
    return 0;
793
} /* End MAIN */
794
795


Matteo Quintiliani's avatar
Matteo Quintiliani committed
796
static void save_channel_states() {
797
798
799
800
801
    int to_cur_chan;
    char last_time_str[30];
    char raw_last_sample_time_str[30];
    char state_line_str[1000];

802
803
804
    if(params.statefile) {
	FILE *fstatefile = fopen(params.statefile, "w");
	if(fstatefile == NULL) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
805
806
807
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "Unable to write channel states into %s!\n", params.statefile);
	} else {
	    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Writing channel states into %s!\n", params.statefile);
808
	}
809

810
811
812
813
814
815
816
817
818
819
820
821
822
	/* Save state for each channel */
	// if(params.stc == -1)
	to_cur_chan = 0;
	while(to_cur_chan < channelList_subset->number) {
	    nmxp_data_to_str(last_time_str, channelListSeq[to_cur_chan].last_time);
	    nmxp_data_to_str(raw_last_sample_time_str, channelListSeq[to_cur_chan].raw_stream_buffer.last_sample_time);
	    sprintf(state_line_str, "%-14s %16.4f %s %16.4f %s",
		    channelList_subset->channel[to_cur_chan].name,
		    channelListSeq[to_cur_chan].last_time, last_time_str,
		    channelListSeq[to_cur_chan].raw_stream_buffer.last_sample_time, raw_last_sample_time_str
		   );
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CHANNEL, "%s\n", state_line_str);
	    if(fstatefile) {
823
824
825
826
827
		if( (channelListSeq[to_cur_chan].last_time != 0) || (channelListSeq[to_cur_chan].raw_stream_buffer.last_sample_time != -1.0) ) {
		    fprintf(fstatefile, "%s\n", state_line_str);
		} else {
		    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "%s\n", state_line_str);
		}
828
829
830
	    }
	    to_cur_chan++;
	}
831
	if(fstatefile) {
832
	    fclose(fstatefile);
833
834
835
836
	}
    }
}

837

Matteo Quintiliani's avatar
Matteo Quintiliani committed
838
839
840
841
842
843
844
static void flushing_raw_data_stream() {
    int to_cur_chan;

    /* Flush raw data stream for each channel */
    if(params.stc == -1) {
	to_cur_chan = 0;
	while(to_cur_chan < channelList_subset->number) {
845
	    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Flushing data for channel %s\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
846
847
848
849
850
851
		    channelList_subset->channel[to_cur_chan].name);
	    nmxp_raw_stream_manage(&(channelListSeq[to_cur_chan].raw_stream_buffer), NULL, p_func_pd, n_func_pd);
	    to_cur_chan++;
	}
    }
}
852

Matteo Quintiliani's avatar
Matteo Quintiliani committed
853
#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
854
855
/* Do any needed cleanup and exit */
static void clientShutdown(int sig) {
856

857
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Program interrupted!\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
858

Matteo Quintiliani's avatar
Matteo Quintiliani committed
859
    flushing_raw_data_stream();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
860
    save_channel_states();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
861

Matteo Quintiliani's avatar
Matteo Quintiliani committed
862
863
864
865
866
    if(params.flag_writefile  &&  outfile) {
	/* Close output file */
	fclose(outfile);
    }

867
868
869
870
871
872
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_detach();
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
873
874
875
876
877
878
879
#ifdef HAVE_LIBMSEED
    if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	/* Close output Mini-SEED file */
	fclose(data_seed.outfile_mseed);
    }
#endif

880

Matteo Quintiliani's avatar
Matteo Quintiliani committed
881
882
883
884
885
886
    /* PDS Step 7: Send Terminate Subscription */
    nmxp_sendTerminateSubscription(naqssock, NMXP_SHUTDOWN_NORMAL, "Good Bye!");

    /* PDS Step 8: Close the socket */
    nmxp_closeSocket(naqssock);

887

Matteo Quintiliani's avatar
Matteo Quintiliani committed
888
889
890

    /* Free the complete channel list */
    if(channelList) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
891
	free(channelList);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
892
	channelList = NULL;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
893
    }
894

895
896
    int i_chan = 0;

897
898
899
900
901
902
903
904
905
906
#ifdef HAVE_LIBMSEED
    if(*msr_list_chan) {
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
	    if(msr_list_chan[i_chan]) {
		msr_free(&(msr_list_chan[i_chan]));
	    }
	}
    }
#endif

907
    for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
908
	nmxp_raw_stream_free(&(channelListSeq[i_chan].raw_stream_buffer));
909
910
    }

911
912
913
914
915
    if(channelListSeq) {
	free(channelListSeq);
    }

    /* This has to be the last */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
916
917
918
919
920
921
    if(channelList_subset == NULL) {
	free(channelList_subset);
    }

    exit( sig );
} /* End of clientShutdown() */
922

Matteo Quintiliani's avatar
Matteo Quintiliani committed
923
924
925
926

/* Empty signal handler routine */
static void clientDummyHandler(int sig) {
}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
927

Matteo Quintiliani's avatar
Matteo Quintiliani committed
928
929
#endif /* HAVE_WINDOWS_H */

Matteo Quintiliani's avatar
Matteo Quintiliani committed
930
931
932



933
#ifdef HAVE_LIBMSEED
Matteo Quintiliani's avatar
Matteo Quintiliani committed
934
935
936
937
938
int nmxptool_write_miniseed(NMXP_DATA_PROCESS *pd) {
    int cur_chan;
    int ret = 0;
    if( (cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset)) != -1) {

939
	ret = nmxp_data_msr_pack(pd, &data_seed, msr_list_chan[cur_chan]);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
940
941

    } else {
942
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL, "Key %d not found in channelList_subset!\n", pd->key);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
943
944
945
    }
    return ret;
}
946
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
947

948
949
int nmxptool_print_seq_no(NMXP_DATA_PROCESS *pd) {
    int ret = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
950
951
    char str_time[200];
    nmxp_data_to_str(str_time, pd->time);
952

953
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "Process %s.%s.%s %2d %d %d %s %dpts lat. %.1fs\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
954
	    pd->network,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
955
956
	    pd->station,
	    pd->channel,
957
958
	    pd->packet_type,
	    pd->seq_no,
959
	    pd->oldest_seq_no,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
960
961
	    str_time,
	    pd->nSamp,
962
	    nmxp_data_latency(pd)
963
964
965
966
967
	    );

    return ret;
}

968

Matteo Quintiliani's avatar
Matteo Quintiliani committed
969
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
Matteo Quintiliani's avatar
Matteo Quintiliani committed
970
971
972
973
974
975
976
977
int nmxptool_send_raw_depoch(NMXP_DATA_PROCESS *pd) {
    /* TODO Set values */
    const int usec_correction = 0;
    const int timing_quality = 100;

    return send_raw_depoch(pd->station, pd->channel, pd->time, usec_correction, timing_quality,
	    pd->pDataPtr, pd->nSamp);
}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
978
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
979
980
981
982



int nmxptool_check_and_log_gap(double time1, double time2, const double gap_tollerance, const char *station, const char *channel) {
983
984
    char str_time1[200];
    char str_time2[200];
Matteo Quintiliani's avatar
Matteo Quintiliani committed
985
986
    int ret = 0;
    double gap = time1 - time2 ;
987
988
    nmxp_data_to_str(str_time1, time1);
    nmxp_data_to_str(str_time2, time2);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
989
    if(gap > gap_tollerance) {
990
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_GAP, "Gap %.2f sec. for %s.%s from %s to %s!\n", gap, station, channel, str_time2, str_time1);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
991
992
	ret = 1;
    } else if (gap < -gap_tollerance) {
993
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_GAP, "Overlap %.2f sec. for %s.%s from %s to %s!\n", gap, station, channel, str_time1, str_time2);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
994
995
996
997
	ret = 1;
    }
    return ret;
}
998

Matteo Quintiliani's avatar
Matteo Quintiliani committed
999
void nmxptool_str_time_to_filename(char *str_time) {
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
    int i;
    for(i=0; i<strlen(str_time); i++) {
	if(   (str_time[i] >= 'A'  &&  str_time[i] <= 'Z')
		|| (str_time[i] >= 'a'  &&  str_time[i] <= 'z')
		|| (str_time[i] >= '0'  &&  str_time[i] <= '9')
		|| (str_time[i] == '_')
	  ) {
	    /* Do nothing */
	} else {
	    str_time[i] = '.';
	}
    }
}