nmxptool.c 21 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
 *
Matteo Quintiliani's avatar
Matteo Quintiliani committed
10
 * $Id: nmxptool.c,v 1.75 2007-09-28 21:04:27 mtheo Exp $
Matteo Quintiliani's avatar
Matteo Quintiliani committed
11
 *
Matteo Quintiliani's avatar
Matteo Quintiliani committed
12
13
 */

14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <nmxp.h>
Matteo Quintiliani's avatar
Matteo Quintiliani committed
19
20
21
22
23

#ifndef WIN32
#include <signal.h>
#endif

24
#include "config.h"
25
#include "nmxptool_getoptlong.h"
26
27

#ifdef HAVE_EARTHWORMOBJS
28
#include "nmxptool_ew.h"
29
#endif
30

31
32
33
#ifdef HAVE_LIBMSEED
#include <libmseed.h>
#endif
34

35
36
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_H
#include "seedlink_plugin.h"
37
38
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
39
40
#define CURRENT_NETWORK (params.network)? params.network : DEFAULT_NETWORK
#define GAP_TOLLERANCE 0.001
41

42
43
44
45
typedef struct {
    int significant;
    double last_time;
    int32_t x_1;
46
    NMXP_RAW_STREAM_DATA raw_stream_buffer;
47
48
} NMXPTOOL_CHAN_SEQ;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
49
50
51
static void clientShutdown(int sig);
static void clientDummyHandler(int sig);

52
#ifdef HAVE_LIBMSEED
Matteo Quintiliani's avatar
Matteo Quintiliani committed
53
int nmxptool_write_miniseed(NMXP_DATA_PROCESS *pd);
54
55
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
56
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
Matteo Quintiliani's avatar
Matteo Quintiliani committed
57
int nmxptool_send_raw_depoch(NMXP_DATA_PROCESS *pd);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
58
59
#endif

60
int nmxptool_print_seq_no(NMXP_DATA_PROCESS *pd);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
61
62

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
63
void nmxptool_str_time_to_filename(char *str_time);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
64
65


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/* Global variable for main program and handling terminitation program */
NMXPTOOL_PARAMS params;
int naqssock = 0;
FILE *outfile = NULL;
NMXP_CHAN_LIST *channelList = NULL;
NMXP_CHAN_LIST *channelList_subset = NULL;
NMXPTOOL_CHAN_SEQ *channelListSeq = NULL;

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


81
int main (int argc, char **argv) {
82
    int32_t connection_time;
83
    int request_SOCKET_OK;
84
    int i_chan, cur_chan;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
85
    int exitpdscondition;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
86
87
    int exitdapcondition;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
88
    int span_interval = 10;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
89
90
    int time_to_sleep = 0;

91
92
    char str_start_time[200];
    char str_end_time[200];
Matteo Quintiliani's avatar
Matteo Quintiliani committed
93
    char str_pd_time[200];
94
95
96

    NMXP_MSG_SERVER type;
    void *buffer;
97
    int32_t length;
98
99
100
    int ret;

    char filename[500];
101
    char station_code[20], channel_code[20];
102
103
104
105
106
107
108
109

    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
110
111
112
113
114
115
116
117
#ifndef WIN32
    /* 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);
118

Matteo Quintiliani's avatar
Matteo Quintiliani committed
119
120
121
122
123
124
125
126
127
128
129
    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 */
130
131
132
133
134
135
136
    nmxp_log(-1, 0);

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

137
    if(params.ew_configuration_file) {
138
	/* TODO set structure "params" from file */
139
140
141
142
143
144
145
146
147
148
	nmxp_log(NMXP_LOG_NORM_NO, 0, "\n");
	nmxp_log(NMXP_LOG_WARN, 0, "Earthworm support is still under development!\n");
	nmxp_log(NMXP_LOG_NORM_NO, 0, "\n");
	exit(0);
    } else {
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}

149
150
151
	if(params.flag_verbose) {
	    nmxp_log(-1, 2);
	}
152

153
154
	/* List available channels on server */
	if(params.flag_listchannels) {
155

156
157
158
159
	    // TOREMOVE
	    // channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
	    // TOREMOVE
	    // nmxp_chan_print_channelList(channelList);
160

161
	    nmxp_getMetaChannelList(params.hostname, params.portnumberdap, NMXP_DATA_TIMESERIES, params.flag_request_channelinfo);
162

163
164
165
	    return 1;
	}
    }
166

167
168
#ifdef HAVE_EARTHWORMOBJS
    if(params.ew_configuration_file) {
169
	nmxptool_ew_attach();
170
    }
171
#endif
172
173
174
175
176
177
178
179
180

    /* Get list of available channels and get a subset list of params.channels */
    channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
    channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels);

    /* Check if some channel already exists */
    if(channelList_subset->number <= 0) {
	nmxp_log(1, 0, "Channels not found!\n");
	return 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
181
182
    } else {
	nmxp_chan_print_channelList(channelList_subset);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
183

184
185
186
187
188
189
190
	nmxp_log(0, 1, "Init channelListSeq.\n");

	/* 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
191
	    channelListSeq[i_chan].x_1 = 0;
192
	    nmxp_raw_stream_init(&(channelListSeq[i_chan].raw_stream_buffer), params.max_tollerable_latency);
193
194
	}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
195
#ifdef HAVE_LIBMSEED
196
197
198
	nmxp_log(0, 1, "Init mini-SEED record list.\n");

	/* Init mini-SEED record list */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
199
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
200
201
202
203
204
205
206
207

	    nmxp_log(0, 1, "Init mini-SEED record for %s\n", channelList_subset->channel[i_chan].name);

	    msr_list_chan[i_chan] = msr_init(NULL);

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

208
		nmxp_log(0, 1, "%s.%s.%s\n", CURRENT_NETWORK, station_code, channel_code);
209

210
		strcpy(msr_list_chan[i_chan]->network, CURRENT_NETWORK);
211
212
213
214
215
216
217
218
219
220
221
		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 {
		nmxp_log(1, 0, "Channels %s error in format!\n");
		return 1;
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
222
223
	}
#endif
224

225
226
227
228
229
230
231
232
    }

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
233
234
    nmxp_log(0, 1, "Starting comunication.\n");

235
    /* TODO condition starting DAP or PDS */
236
237
238
    if( (params.start_time != 0   &&   params.end_time != 0)
	    || params.delay > 0
	    ) {
239

Matteo Quintiliani's avatar
Matteo Quintiliani committed
240
	if(params.delay > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
241
	    params.start_time = ((time(NULL) - params.delay - span_interval) / 10) * 10;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
242
243
244
	    params.end_time = params.start_time + span_interval;
	}

245

246
247
248
	/* ************************************************************** */
	/* Start subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************** */
249

250
251
252
253
254
	/* DAP Step 1: Open a socket */
	if( (naqssock = nmxp_openSocket(params.hostname, params.portnumberdap)) == NMXP_SOCKET_ERROR) {
	    nmxp_log(1, 0, "Error opening socket!\n");
	    return 1;
	}
255

256
257
258
259
260
	/* DAP Step 2: Read connection time */
	if(nmxp_readConnectionTime(naqssock, &connection_time) != NMXP_SOCKET_OK) {
	    nmxp_log(1, 0, "Error reading connection time from server!\n");
	    return 1;
	}
261

262
263
264
265
266
267
268
269
270
271
272
	/* DAP Step 3: Send a ConnectRequest */
	if(nmxp_sendConnectRequest(naqssock, params.datas_username, params.datas_password, connection_time) != NMXP_SOCKET_OK) {
	    nmxp_log(1, 0, "Error sending connect request!\n");
	    return 1;
	}

	/* DAP Step 4: Wait for a Ready message */
	if(nmxp_waitReady(naqssock) != NMXP_SOCKET_OK) {
	    nmxp_log(1, 0, "Error waiting Ready message!\n");
	    return 1;
	}
273

274
275
276
277
278
279
	exitdapcondition = 1;

	while(exitdapcondition) {

	nmxp_log(0, 1, "start_time = %d - end_time = %d\n", params.start_time, params.end_time);

280
281
282
	/* Start loop for sending requests */
	i_chan=0;
	request_SOCKET_OK = NMXP_SOCKET_OK;
283

284
	while(request_SOCKET_OK == NMXP_SOCKET_OK  &&  i_chan < channelList_subset->number) {
285

286
	    /* DAP Step 5: Send Data Request */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
287
	    request_SOCKET_OK = nmxp_sendDataRequest(naqssock, channelList_subset->channel[i_chan].key, (double) params.start_time, (double) params.end_time);
288

289
	    if(request_SOCKET_OK == NMXP_SOCKET_OK) {
290

291
292
293
294
295
		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);

296
297
		if(params.flag_writefile) {
		    /* Open output file */
298
		    sprintf(filename, "%s.%s_%s_%s.nmx",
299
			    CURRENT_NETWORK,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
300
			    channelList_subset->channel[i_chan].name,
301
302
			    str_start_time,
			    str_end_time);
303

304
305
306
307
		    outfile = fopen(filename, "w");
		    if(!outfile) {
			nmxp_log(1, 0, "Can not to open file %s!", filename);
		    }
308
309
310
		}

#ifdef HAVE_LIBMSEED
311
312
		if(params.flag_writeseed) {
		    /* Open output Mini-SEED file */
313
		    sprintf(data_seed.filename_mseed, "%s.%s_%s_%s.miniseed",
314
			    CURRENT_NETWORK,
Matteo Quintiliani's avatar
Matteo Quintiliani committed
315
			    channelList_subset->channel[i_chan].name,
316
317
			    str_start_time,
			    str_end_time);
318

319
320
321
322
323
324
		    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
		    if(!data_seed.outfile_mseed) {
			nmxp_log(1, 0, "Can not to open file %s!", data_seed.filename_mseed);
		    }
		}
#endif
325

326
327
328
		if(params.flag_writefile  &&  outfile) {
		    /* Compute SNCL line */

329
330
331
332
333
		    /* Separate station_code_old_way and channel_code_old_way */
		    if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[i_chan].name, station_code, channel_code)) {
			/* Write SNCL line */
			fprintf(outfile, "%s.%s.%s.%s\n",
				station_code,
334
				CURRENT_NETWORK,
335
336
				channel_code,
				(params.location)? params.location : "");
337
		    }
338
339
340

		}

341
342
343
		/* DAP Step 6: Receive Data until receiving a Ready message */
		ret = nmxp_receiveMessage(naqssock, &type, &buffer, &length);
		nmxp_log(0, 1, "ret = %d, type = %d\n", ret, type);
344

345
		while(ret == NMXP_SOCKET_OK   &&    type != NMXP_MSG_READY) {
346

347
		    /* Process a packet and return value in NMXP_DATA_PROCESS structure */
348
		    pd = nmxp_processCompressedData(buffer, length, channelList_subset, CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
349
		    nmxp_data_trim(pd, params.start_time, params.end_time, 0);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
350
351

		    /* Log contents of last packet */
352
353
354
		    if(params.flag_logdata) {
			nmxp_data_log(pd);
		    }
355

356
		    /* Set cur_chan */
357
		    cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
358
359

		    /* Management of gaps */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
360
		    if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
361
362
			channelListSeq[cur_chan].significant = 1;
		    } else {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
363
			if(channelListSeq[cur_chan].significant) {
364
365
			    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
366
367
				nmxp_data_to_str(str_pd_time, pd->time);
				nmxp_log(NMXP_LOG_WARN, 0, "%s.%s x0 set to zero at %s!\n", pd->station, pd->channel, str_pd_time);
368
			    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
369
370
			}
		    }
371
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
372
			channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
373
374
		    }

375
#ifdef HAVE_LIBMSEED
376
377
		    /* Write Mini-SEED record */
		    if(params.flag_writeseed) {
378
			nmxptool_write_miniseed(pd);
379
		    }
380
#endif
381

382
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
383
		    /* Send data to SeedLink Server */
384
		    if(params.flag_slink) {
385
			nmxptool_send_raw_depoch(pd);
386
		    }
387
388
#endif

389
390
391
		    if(params.flag_writefile  &&  outfile) {
			/* Write buffer to the output file */
			if(outfile && buffer && length > 0) {
392
			    int32_t length_int = length;
393
394
395
396
397
			    nmxp_data_swap_4b((int32_t *) &length_int);
			    fwrite(&length_int, sizeof(length_int), 1, outfile);
			    fwrite(buffer, length, 1, outfile);
			}
		    }
398

Matteo Quintiliani's avatar
Matteo Quintiliani committed
399
400
401
402
403
		    /* 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
404
405
406
		    if(pd->buffer) {
			free(pd->buffer);
			pd->buffer = NULL;
407
		    }
408
409
410
411

		    /* Receive Data */
		    ret = nmxp_receiveMessage(naqssock, &type, &buffer, &length);
		    nmxp_log(0, 1, "ret = %d, type = %d\n", ret, type);
412
413
		}

414
415
416
		if(params.flag_writefile  &&  outfile) {
		    /* Close output file */
		    fclose(outfile);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
417
		    outfile = NULL;
418
419
		}

420
421
422
423
#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
424
		    data_seed.outfile_mseed = NULL;
425
426
		}
#endif
427
428

	    }
429
430
431
	    i_chan++;
	}
	/* DAP Step 7: Repeat steps 5 and 6 for each data request */
432

Matteo Quintiliani's avatar
Matteo Quintiliani committed
433
	if(params.delay > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
434
435
436
437
438
439
440
	    time_to_sleep = (params.end_time - params.start_time) - (time(NULL) - (params.start_time + params.delay + span_interval));
	    if(time_to_sleep >= 0) {
		sleep(time_to_sleep);
	    } else {
		nmxp_log(1, 0, "time to sleep %dsec.\n", time_to_sleep);
		sleep(3);
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
441
442
443
444
445
446
	    params.start_time = params.end_time;
	    params.end_time = params.start_time + span_interval;
	} else {
	    exitdapcondition = 0;
	}

447

Matteo Quintiliani's avatar
Matteo Quintiliani committed
448
    } /* END while(exitdapcondition) */
449

450
451
452
453
454
455
456
457
458
459
460
	/* 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 */
	/* ************************************************************ */


461

Matteo Quintiliani's avatar
Matteo Quintiliani committed
462
    } else {
463

464
	int n_func_pd = 0;
465
	int (*p_func_pd[NMXP_MAX_FUNC_PD]) (NMXP_DATA_PROCESS *);
466
467
468

	if(params.stc == -1) {

469

470
471
472
473
	    if(params.flag_logdata) {
		p_func_pd[n_func_pd++] = nmxptool_print_seq_no;
	    }

474
475
476
477
478
479
480
481
482
483
484
485
486
487
#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
	}
488

489
490
491
492
493
494
495
496
497
	/* ************************************************************* */
	/* 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;
498
499
	}

500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
	/* 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 */
	channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels);


	/* PDS Step 4: Send a Request Pending (optional) */
517
518


519
520
521
522
523
524
	/* 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
525
526
527
528
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed) {
	    /* Open output Mini-SEED file */
	    sprintf(data_seed.filename_mseed, "%s.realtime.miniseed",
529
		    CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
530
531
532
533
534
535
536
537
538
539

	    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
	    if(!data_seed.outfile_mseed) {
		nmxp_log(1, 0, "Can not to open file %s!", data_seed.filename_mseed);
	    } else {
		nmxp_log(0, 1, "Opened file %s!\n", data_seed.filename_mseed);
	    }
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
540
541
542
543
	// TODO
	exitpdscondition = 1;

	while(exitpdscondition) {
544
	    /* Process Compressed or Decompressed Data */
545
	    pd = nmxp_receiveData(naqssock, channelList_subset, CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
546
547

	    /* Log contents of last packet */
548
549
550
	    if(params.flag_logdata) {
		nmxp_data_log(pd);
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
551

552
	    /* Set cur_chan */
553
	    cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
554

555
556
	    /* Manage Raw Stream */
	    if(params.stc == -1) {
557
		nmxp_raw_stream_manage(&(channelListSeq[cur_chan].raw_stream_buffer), pd, p_func_pd, n_func_pd);
558
	    } else {
559
560
561
562
563
564
565
566

		/* Management of gaps */
		if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].significant = 1;
		} else {
		    if(channelListSeq[cur_chan].significant) {
			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
567
568
			    nmxp_data_to_str(str_pd_time, pd->time);
			    nmxp_log(NMXP_LOG_WARN, 0, "%s.%s x0 set to zero at %s!\n", pd->station, pd->channel, str_pd_time);
569
			}
570
		    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
571
		}
572
573
574
		if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
		}
575

Matteo Quintiliani's avatar
Matteo Quintiliani committed
576
577

#ifdef HAVE_LIBMSEED
578
579
580
581
		/* Write Mini-SEED record */
		if(params.flag_writeseed) {
		    nmxptool_write_miniseed(pd);
		}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
582
583
#endif

584
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
585
586
587
588
		/* Send data to SeedLink Server */
		if(params.flag_slink) {
		    nmxptool_send_raw_depoch(pd);
		}
589
#endif
590
	    }
591

Matteo Quintiliani's avatar
Matteo Quintiliani committed
592
593
594
595
596
	    /* 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
597
598
599
600
601
	    if(pd->buffer) {
		free(pd->buffer);
		pd->buffer = NULL;
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
602
603
	    // TODO
	    exitpdscondition = 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
604
605
606
607
608
609
610
611
612
	}

#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	    /* Close output Mini-SEED file */
	    fclose(data_seed.outfile_mseed);
	}
#endif

613
614
615
616
617
618
619
620
621
622
623

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

624
625
626



627
    }
628

629
630
631
632
633
634
635
636
637
638
#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

639
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
640
	    nmxp_raw_stream_free(&(channelListSeq[i_chan].raw_stream_buffer));
641
642
	}

643
644
645
646
647
648
649
650
651
	if(channelListSeq) {
	    free(channelListSeq);
	}

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

652
#ifdef HAVE_EARTHWORMOBJS
653
	if(params.ew_configuration_file) {
654
	    nmxptool_ew_detach();
655
	}
656
657
#endif

658
    return 0;
659
} /* End MAIN */
660
661
662
663
664





Matteo Quintiliani's avatar
Matteo Quintiliani committed
665
666
/* Do any needed cleanup and exit */
static void clientShutdown(int sig) {
667

Matteo Quintiliani's avatar
Matteo Quintiliani committed
668
669
670
671
672
673
674
675
676
677
678
679
680
681
    nmxp_log(0, 0, "Program interrupted!\n");

    if(params.flag_writefile  &&  outfile) {
	/* Close output file */
	fclose(outfile);
    }

#ifdef HAVE_LIBMSEED
    if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	/* Close output Mini-SEED file */
	fclose(data_seed.outfile_mseed);
    }
#endif

682

Matteo Quintiliani's avatar
Matteo Quintiliani committed
683
684
685
686
687
688
    /* PDS Step 7: Send Terminate Subscription */
    nmxp_sendTerminateSubscription(naqssock, NMXP_SHUTDOWN_NORMAL, "Good Bye!");

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

689

Matteo Quintiliani's avatar
Matteo Quintiliani committed
690
691
692
    if(channelList == NULL) {
	free(channelList);
    }
693

694
695
    int i_chan = 0;

696
697
698
699
700
701
702
703
704
705
#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

706
    for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
707
	nmxp_raw_stream_free(&(channelListSeq[i_chan].raw_stream_buffer));
708
709
    }

710
711
712
713
714
    if(channelListSeq) {
	free(channelListSeq);
    }

    /* This has to be the last */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
715
716
717
718
719
720
    if(channelList_subset == NULL) {
	free(channelList_subset);
    }

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
722
723
724
725

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




730
#ifdef HAVE_LIBMSEED
Matteo Quintiliani's avatar
Matteo Quintiliani committed
731
732
733
734
735
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) {

736
	ret = nmxp_data_msr_pack(pd, &data_seed, msr_list_chan[cur_chan]);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
737
738
739
740
741
742

    } else {
	nmxp_log(1, 0, "Key %d not found in channelList_subset!\n", pd->key);
    }
    return ret;
}
743
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
744

745
746
747
int nmxptool_print_seq_no(NMXP_DATA_PROCESS *pd) {
    int ret = 0;

748
    nmxp_log(NMXP_LOG_NORM_NO, 0, "%s.%s %2d %d %d  lat. %.1fs\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
749
750
	    pd->station,
	    pd->channel,
751
752
	    pd->packet_type,
	    pd->seq_no,
753
754
	    pd->oldest_seq_no,
	    nmxp_data_latency(pd)
755
756
757
758
759
	    );

    return ret;
}

760

Matteo Quintiliani's avatar
Matteo Quintiliani committed
761
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
Matteo Quintiliani's avatar
Matteo Quintiliani committed
762
763
764
765
766
767
768
769
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
770
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
771
772
773
774



int nmxptool_check_and_log_gap(double time1, double time2, const double gap_tollerance, const char *station, const char *channel) {
775
776
    char str_time1[200];
    char str_time2[200];
Matteo Quintiliani's avatar
Matteo Quintiliani committed
777
778
    int ret = 0;
    double gap = time1 - time2 ;
779
780
    nmxp_data_to_str(str_time1, time1);
    nmxp_data_to_str(str_time2, time2);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
781
    if(gap > gap_tollerance) {
782
	nmxp_log(1, 0, "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
783
784
	ret = 1;
    } else if (gap < -gap_tollerance) {
785
	nmxp_log(1, 0, "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
786
787
788
789
	ret = 1;
    }
    return ret;
}
790

Matteo Quintiliani's avatar
Matteo Quintiliani committed
791
void nmxptool_str_time_to_filename(char *str_time) {
792
793
794
795
796
797
798
799
800
801
802
803
804
    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] = '.';
	}
    }
}