nmxptool.c 28.1 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.100 2007-12-17 11:05:32 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
    double after_start_time;
56
    NMXP_RAW_STREAM_DATA raw_stream_buffer;
57
58
} NMXPTOOL_CHAN_SEQ;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
59
60

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

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

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

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

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

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
79
void nmxptool_str_time_to_filename(char *str_time);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
80
81


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

92
93
94
95
96
97
98
99

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


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

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

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

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

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

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

    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
133
#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
134
135
136
137
138
139
140
    /* 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);
141

Matteo Quintiliani's avatar
Matteo Quintiliani committed
142
143
144
145
146
147
148
149
150
151
152
    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 */
153
    nmxp_log(NMXP_LOG_SET, NMXP_LOG_D_NULL);
154
155
156
157
158
159

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

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

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

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

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

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

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

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

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

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

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

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

194
195
	}
    }
196

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

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

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

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

	/* 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
218
	    channelListSeq[i_chan].last_time_call_raw_stream = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
219
	    channelListSeq[i_chan].x_1 = 0;
220
	    channelListSeq[i_chan].after_start_time = 0.0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
221
	    nmxp_raw_stream_init(&(channelListSeq[i_chan].raw_stream_buffer), params.max_tolerable_latency, params.timeoutrecv);
222
223
	}

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

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

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

	    msr_list_chan[i_chan] = msr_init(NULL);

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

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

239
		strcpy(msr_list_chan[i_chan]->network, NETCODE_OR_CURRENT_NETWORK);
240
241
242
243
244
245
246
		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 {
247
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL, "Channels %s error in format!\n");
248
249
250
		return 1;
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
251
252
	}
#endif
253

254
255
256
257
258
259
260
261
    }

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

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

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

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

274

275
276
277
	/* ************************************************************** */
	/* Start subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************** */
278

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

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

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

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

303
304
305
306
	exitdapcondition = 1;

	while(exitdapcondition) {

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

309
310
311
	/* Start loop for sending requests */
	i_chan=0;
	request_SOCKET_OK = NMXP_SOCKET_OK;
312

313
	while(request_SOCKET_OK == NMXP_SOCKET_OK  &&  i_chan < channelList_subset->number) {
314

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

318
	    if(request_SOCKET_OK == NMXP_SOCKET_OK) {
319

320
321
322
323
324
		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);

325
326
		if(params.flag_writefile) {
		    /* Open output file */
327
328
329
330
331
332
333
334
335
336
337
338
339
		    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);
		    }
340

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

#ifdef HAVE_LIBMSEED
348
349
		if(params.flag_writeseed) {
		    /* Open output Mini-SEED file */
350
351
352
353
354
355
356
357
358
359
360
361
362
		    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);
		    }
363

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

371
372
373
		if(params.flag_writefile  &&  outfile) {
		    /* Compute SNCL line */

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

		}

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

390
		while(ret == NMXP_SOCKET_OK   &&    type != NMXP_MSG_READY) {
391

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

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

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

		    /* Management of gaps */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
405
		    if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
406
407
			channelListSeq[cur_chan].significant = 1;
		    } else {
408
			if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
409
410
			    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
411
				nmxp_data_to_str(str_pd_time, pd->time);
412
				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);
413
			    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
414
415
			}
		    }
416
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
417
			channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
418
419
		    }

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

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

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
444
445
446
447
448
		    /* 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
449
450
451
		    if(pd->buffer) {
			free(pd->buffer);
			pd->buffer = NULL;
452
		    }
453
454

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

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

465
466
467
468
#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
469
		    data_seed.outfile_mseed = NULL;
470
471
		}
#endif
472
473

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

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

492

Matteo Quintiliani's avatar
Matteo Quintiliani committed
493
    } /* END while(exitdapcondition) */
494

495
496
497
498
499
500
501
502
503
504
505
	/* 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 */
	/* ************************************************************ */


506

Matteo Quintiliani's avatar
Matteo Quintiliani committed
507
    } else {
508

509
510
	if(params.stc == -1) {

511

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

516
517
518
519
520
521
522
523
524
525
526
527
528
#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
529
530
531
532
533
534
535

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

536
	}
537

538
539
540
541
542
543
544
545
546
	/* ************************************************************* */
	/* 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;
547
548
	}

549
550
551
552
553
554
555
556
557
558
559
560
561
	/* 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 */
562
	channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
563
564
565


	/* PDS Step 4: Send a Request Pending (optional) */
566
567


568
569
570
571
572
573
	/* 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
574
575
576
577
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed) {
	    /* Open output Mini-SEED file */
	    sprintf(data_seed.filename_mseed, "%s.realtime.miniseed",
578
		    CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
579
580
581

	    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
	    if(!data_seed.outfile_mseed) {
582
		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
583
	    } else {
584
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Opened file %s!\n", data_seed.filename_mseed);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
585
586
587
588
	    }
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
589
590
591
	// TODO
	exitpdscondition = 1;

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

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

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

606
	    if(recv_errno == 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
607
608
609
		// TODO
		exitpdscondition = 1;
	    } else {
610
		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
611
612
		exitpdscondition = 0;
	    }
613

614
615
616
617
618
	    if(pd) {
		/* Set cur_chan */
		cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
619
	    /* Log contents of last packet */
620
621
622
	    if(params.flag_logdata) {
		nmxp_data_log(pd);
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
623

624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
	    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) {

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

		/* 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
658
		    exitpdscondition = 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
659
660
661
662
663
		    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) {
664
			    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_DOD, "Timeout for channel %s (%d sec.)\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
665
666
667
668
669
670
671
672
				    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++;
		    }
		}

673
	    } else {
674

Matteo Quintiliani's avatar
Matteo Quintiliani committed
675
	    if(pd) {
676
677
678
679
		/* Management of gaps */
		if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].significant = 1;
		} else {
680
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
681
682
			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
683
			    nmxp_data_to_str(str_pd_time, pd->time);
684
			    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);
685
			}
686
		    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
687
		}
688
689
690
		if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
		}
691

Matteo Quintiliani's avatar
Matteo Quintiliani committed
692
693

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

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
710
	    if(pd) {
711
712
713
714
715
716
717
718
719
		/* 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
720
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
721

Matteo Quintiliani's avatar
Matteo Quintiliani committed
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
#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

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

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

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

756
757
758
759
760
761
762
763
764
765
766

	/* 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 */
	/* *********************************************************** */

767
768


769
    }
770

771
772
773
774
775
776
777
778
779
780
#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

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

785
786
787
788
789
790
791
792
793
	if(channelListSeq) {
	    free(channelListSeq);
	}

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

794
    return 0;
795
} /* End MAIN */
796
797


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

804
805
806
    if(params.statefile) {
	FILE *fstatefile = fopen(params.statefile, "w");
	if(fstatefile == NULL) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
807
808
809
	    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);
810
	}
811

812
813
814
815
816
817
818
819
820
821
822
823
824
	/* 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) {
825
826
827
828
829
		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);
		}
830
831
832
	    }
	    to_cur_chan++;
	}
833
	if(fstatefile) {
834
	    fclose(fstatefile);
835
836
837
838
	}
    }
}

839

Matteo Quintiliani's avatar
Matteo Quintiliani committed
840
841
842
843
844
845
846
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) {
847
	    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Flushing data for channel %s\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
848
849
850
851
852
853
		    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++;
	}
    }
}
854

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

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
861
    flushing_raw_data_stream();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
862
    save_channel_states();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
863

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

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

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

882

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

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

889

Matteo Quintiliani's avatar
Matteo Quintiliani committed
890
891
892

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

897
898
    int i_chan = 0;

899
900
901
902
903
904
905
906
907
908
#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

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

913
914
915
916
917
    if(channelListSeq) {
	free(channelListSeq);
    }

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

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
925
926
927
928

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
930
931
#endif /* HAVE_WINDOWS_H */

Matteo Quintiliani's avatar
Matteo Quintiliani committed
932
933
934



935
#ifdef HAVE_LIBMSEED
Matteo Quintiliani's avatar
Matteo Quintiliani committed
936
937
938
939
940
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) {

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

    } else {
944
	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
945
946
947
    }
    return ret;
}
948
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
949

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

955
    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
956
	    pd->network,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
957
958
	    pd->station,
	    pd->channel,
959
960
	    pd->packet_type,
	    pd->seq_no,
961
	    pd->oldest_seq_no,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
962
963
	    str_time,
	    pd->nSamp,
964
	    nmxp_data_latency(pd)
965
966
967
968
969
	    );

    return ret;
}

970

Matteo Quintiliani's avatar
Matteo Quintiliani committed
971
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
Matteo Quintiliani's avatar
Matteo Quintiliani committed
972
973
974
975
976
977
978
979
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
980
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
981
982
983
984



int nmxptool_check_and_log_gap(double time1, double time2, const double gap_tollerance, const char *station, const char *channel) {
985
986
    char str_time1[200];
    char str_time2[200];
Matteo Quintiliani's avatar
Matteo Quintiliani committed
987
988
    int ret = 0;
    double gap = time1 - time2 ;
989
990
    nmxp_data_to_str(str_time1, time1);
    nmxp_data_to_str(str_time2, time2);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
991
    if(gap > gap_tollerance) {
992
	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
993
994
	ret = 1;
    } else if (gap < -gap_tollerance) {
995
	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
996
997
998
999
	ret = 1;
    }
    return ret;
}
1000

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1001
void nmxptool_str_time_to_filename(char *str_time) {
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
    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] = '.';
	}
    }
}