nmxptool.c 31.3 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.101 2007-12-19 14:13:59 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();
66
void load_channel_states(NMXP_CHAN_LIST_NET *chan_list, NMXPTOOL_CHAN_SEQ *chan_list_seq);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
67
68
static void flushing_raw_data_stream();

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

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

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

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


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

93
94
95
96
97
98
99
100

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


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

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

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

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

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

124
    char filename[500];
125
    char station_code[20], channel_code[20], network_code[20];
126

127
128
129
130
    double cur_after_start_time = DEFAULT_BUFFERED_TIME;
    int skip_current_packet = 0;
	

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
147
148
149
150
151
152
153
154
155
156
157
    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 */
158
    nmxp_log(NMXP_LOG_SET, NMXP_LOG_D_NULL);
159
160
161
162
163
164

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

165
    if(params.ew_configuration_file) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
166
167

#ifdef HAVE_EARTHWORMOBJS
168
169
	nmxp_log_init(nmxptool_ew_logit_msg, nmxptool_ew_logit_err);

Matteo Quintiliani's avatar
Matteo Quintiliani committed
170
	nmxptool_ew_configure(argv, &params);
171

Matteo Quintiliani's avatar
Matteo Quintiliani committed
172
173
174
175
176
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}
#endif
177

178
    } else {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
179

Matteo Quintiliani's avatar
Matteo Quintiliani committed
180
181
	nmxp_log_init(nmxp_log_stdout, nmxp_log_stderr);

182
183
184
185
186
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}

187
188
	/* List available channels on server */
	if(params.flag_listchannels) {
189

190
	    nmxp_getMetaChannelList(params.hostname, params.portnumberdap, NMXP_DATA_TIMESERIES, params.flag_request_channelinfo);
191
	    return 1;
192

193
194
195
196
	} else if(params.flag_listchannelsnaqs) {

	    channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
	    nmxp_chan_print_channelList(channelList);
197
	    return 1;
198

199
200
	}
    }
201

202
203
204
    nmxp_log(NMXP_LOG_SET, params.verbose_level);
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "verbose_level %d\n", params.verbose_level);

205
206
    /* Get list of available channels and get a subset list of params.channels */
    channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
207
    channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
208
209
210

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

216
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CHANNEL, "Init channelListSeq.\n");
217
218
219
220
221
222

	/* 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
223
	    channelListSeq[i_chan].last_time_call_raw_stream = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
224
	    channelListSeq[i_chan].x_1 = 0;
225
	    channelListSeq[i_chan].after_start_time = DEFAULT_BUFFERED_TIME;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
226
	    nmxp_raw_stream_init(&(channelListSeq[i_chan].raw_stream_buffer), params.max_tolerable_latency, params.timeoutrecv);
227
228
	}

229
230
231
232
	if(params.statefile) {
	    load_channel_states(channelList_subset, channelListSeq);
	}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
233
#ifdef HAVE_LIBMSEED
234
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Init mini-SEED record list.\n");
235
236

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

239
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Init mini-SEED record for %s\n", channelList_subset->channel[i_chan].name);
240
241
242
243

	    msr_list_chan[i_chan] = msr_init(NULL);

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

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

248
		strcpy(msr_list_chan[i_chan]->network, NETCODE_OR_CURRENT_NETWORK);
249
250
251
252
253
254
255
		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 {
256
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL, "Channels %s error in format!\n");
257
258
259
		return 1;
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
260
261
	}
#endif
262

263
264
265
266
267
268
269
270
    }

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

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

273
    /* TODO condition starting DAP or PDS */
274
    if( (params.start_time != 0.0   &&   params.end_time != 0.0)
275
276
	    || params.delay > 0
	    ) {
277

Matteo Quintiliani's avatar
Matteo Quintiliani committed
278
	if(params.delay > 0) {
279
	    params.start_time = ((double) (time(NULL) - params.delay - span_interval) / 10.0) * 10.0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
280
281
282
	    params.end_time = params.start_time + span_interval;
	}

283

284
285
286
	/* ************************************************************** */
	/* Start subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************** */
287

288
289
	/* DAP Step 1: Open a socket */
	if( (naqssock = nmxp_openSocket(params.hostname, params.portnumberdap)) == NMXP_SOCKET_ERROR) {
290
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error opening socket!\n");
291
292
	    return 1;
	}
293

294
295
	/* DAP Step 2: Read connection time */
	if(nmxp_readConnectionTime(naqssock, &connection_time) != NMXP_SOCKET_OK) {
296
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error reading connection time from server!\n");
297
298
	    return 1;
	}
299

300
301
	/* DAP Step 3: Send a ConnectRequest */
	if(nmxp_sendConnectRequest(naqssock, params.datas_username, params.datas_password, connection_time) != NMXP_SOCKET_OK) {
302
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error sending connect request!\n");
303
304
305
306
307
	    return 1;
	}

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

312
313
314
315
	exitdapcondition = 1;

	while(exitdapcondition) {

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

318
319
320
	/* Start loop for sending requests */
	i_chan=0;
	request_SOCKET_OK = NMXP_SOCKET_OK;
321

322
	while(request_SOCKET_OK == NMXP_SOCKET_OK  &&  i_chan < channelList_subset->number) {
323

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

327
	    if(request_SOCKET_OK == NMXP_SOCKET_OK) {
328

329
330
331
332
333
		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);

334
335
		if(params.flag_writefile) {
		    /* Open output file */
336
337
338
339
340
341
342
343
344
345
346
347
348
		    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);
		    }
349

350
351
		    outfile = fopen(filename, "w");
		    if(!outfile) {
352
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!", filename);
353
		    }
354
355
356
		}

#ifdef HAVE_LIBMSEED
357
358
		if(params.flag_writeseed) {
		    /* Open output Mini-SEED file */
359
360
361
362
363
364
365
366
367
368
369
370
371
		    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);
		    }
372

373
374
		    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
		    if(!data_seed.outfile_mseed) {
375
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!", data_seed.filename_mseed);
376
377
378
		    }
		}
#endif
379

380
381
382
		if(params.flag_writefile  &&  outfile) {
		    /* Compute SNCL line */

383
		    /* Separate station_code_old_way and channel_code_old_way */
384
		    if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[i_chan].name, station_code, channel_code, network_code)) {
385
386
387
			/* Write SNCL line */
			fprintf(outfile, "%s.%s.%s.%s\n",
				station_code,
388
				NETCODE_OR_CURRENT_NETWORK,
389
390
				channel_code,
				(params.location)? params.location : "");
391
		    }
392
393
394

		}

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

399
		while(ret == NMXP_SOCKET_OK   &&    type != NMXP_MSG_READY) {
400

401
		    /* Process a packet and return value in NMXP_DATA_PROCESS structure */
402
		    pd = nmxp_processCompressedData(buffer, length, channelList_subset, NETCODE_OR_CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
403
		    nmxp_data_trim(pd, params.start_time, params.end_time, 0);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
404
405

		    /* Log contents of last packet */
406
407
408
		    if(params.flag_logdata) {
			nmxp_data_log(pd);
		    }
409

410
		    /* Set cur_chan */
411
		    cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
412
413

		    /* Management of gaps */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
414
		    if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
415
416
			channelListSeq[cur_chan].significant = 1;
		    } else {
417
			if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
418
419
			    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
420
				nmxp_data_to_str(str_pd_time, pd->time);
421
				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);
422
			    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
423
424
			}
		    }
425
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
426
			channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
427
428
		    }

429
#ifdef HAVE_LIBMSEED
430
431
		    /* Write Mini-SEED record */
		    if(params.flag_writeseed) {
432
			nmxptool_write_miniseed(pd);
433
		    }
434
#endif
435

436
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
437
		    /* Send data to SeedLink Server */
438
		    if(params.flag_slink) {
439
			nmxptool_send_raw_depoch(pd);
440
		    }
441
442
#endif

443
444
445
		    if(params.flag_writefile  &&  outfile) {
			/* Write buffer to the output file */
			if(outfile && buffer && length > 0) {
446
			    int32_t length_int = length;
447
448
449
450
451
			    nmxp_data_swap_4b((int32_t *) &length_int);
			    fwrite(&length_int, sizeof(length_int), 1, outfile);
			    fwrite(buffer, length, 1, outfile);
			}
		    }
452

Matteo Quintiliani's avatar
Matteo Quintiliani committed
453
454
455
456
457
		    /* 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
458
459
460
		    if(pd->buffer) {
			free(pd->buffer);
			pd->buffer = NULL;
461
		    }
462
463

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

468
469
470
		if(params.flag_writefile  &&  outfile) {
		    /* Close output file */
		    fclose(outfile);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
471
		    outfile = NULL;
472
473
		}

474
475
476
477
#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
478
		    data_seed.outfile_mseed = NULL;
479
480
		}
#endif
481
482

	    }
483
484
485
	    i_chan++;
	}
	/* DAP Step 7: Repeat steps 5 and 6 for each data request */
486

Matteo Quintiliani's avatar
Matteo Quintiliani committed
487
	if(params.delay > 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
488
489
	    time_to_sleep = (params.end_time - params.start_time) - (time(NULL) - (params.start_time + params.delay + span_interval));
	    if(time_to_sleep >= 0) {
490
		nmxp_sleep(time_to_sleep);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
491
	    } else {
492
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "time to sleep %d sec.\n", time_to_sleep);
493
		nmxp_sleep(3);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
494
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
495
496
497
498
499
500
	    params.start_time = params.end_time;
	    params.end_time = params.start_time + span_interval;
	} else {
	    exitdapcondition = 0;
	}

501

Matteo Quintiliani's avatar
Matteo Quintiliani committed
502
    } /* END while(exitdapcondition) */
503

504
505
506
507
508
509
510
511
512
513
514
	/* 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 */
	/* ************************************************************ */


515

Matteo Quintiliani's avatar
Matteo Quintiliani committed
516
    } else {
517

518
519
	if(params.stc == -1) {

520

521
522
523
524
	    if(params.flag_logdata) {
		p_func_pd[n_func_pd++] = nmxptool_print_seq_no;
	    }

525
526
527
528
529
530
531
532
533
534
535
536
537
#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
538
539
540
541
542
543
544

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

545
	}
546

547
548
549
550
551
552
553
554
555
	/* ************************************************************* */
	/* 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;
556
557
	}

558
559
560
561
562
563
564
565
566
567
568
569
570
	/* 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 */
571
	channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
572
573
574


	/* PDS Step 4: Send a Request Pending (optional) */
575
576


577
578
579
580
581
582
	/* 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
583
584
585
586
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed) {
	    /* Open output Mini-SEED file */
	    sprintf(data_seed.filename_mseed, "%s.realtime.miniseed",
587
		    CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
588
589
590

	    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
	    if(!data_seed.outfile_mseed) {
591
		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
592
	    } else {
593
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Opened file %s!\n", data_seed.filename_mseed);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
594
595
596
597
	    }
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
598
599
600
	// TODO
	exitpdscondition = 1;

Matteo Quintiliani's avatar
Matteo Quintiliani committed
601
602
603
604
605
606
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_attach();
	}
#endif

607
	skip_current_packet = 0;
608
	
Matteo Quintiliani's avatar
Matteo Quintiliani committed
609
	while(exitpdscondition) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
610

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

614
	    if(recv_errno == 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
615
616
617
		// TODO
		exitpdscondition = 1;
	    } else {
618
		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
619
620
		exitpdscondition = 0;
	    }
621

622
623
624
625
626
	    if(pd) {
		/* Set cur_chan */
		cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
627
	    /* Log contents of last packet */
628
629
630
	    if(params.flag_logdata) {
		nmxp_data_log(pd);
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
631

632
	    skip_current_packet = 0;
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
	    if(pd &&
		(params.statefile  ||  params.buffered_time)
	      )	{
		if(params.statefile && channelListSeq[cur_chan].after_start_time > 0.0) {
		    cur_after_start_time = channelListSeq[cur_chan].after_start_time;
		} else if(params.buffered_time) {
		    cur_after_start_time = params.buffered_time;
		} else {
		    cur_after_start_time = DEFAULT_BUFFERED_TIME;
		}
		char cur_after_start_time_str[1024];
		nmxp_data_to_str(cur_after_start_time_str, cur_after_start_time);
		nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_PACKETMAN, "cur_chan %d, cur_after_start_time %f, cur_after_start_time_str %s\n", cur_chan, cur_after_start_time, cur_after_start_time_str);
		if(pd->time + ((double) pd->nSamp / (double) pd->sampRate) >= cur_after_start_time) {
		    if(pd->time < cur_after_start_time) {
			int first_nsample_to_remove = (cur_after_start_time - pd->time) * (double) pd->sampRate;
649
650
651
652
			/* 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;
653
			    pd->time = cur_after_start_time;
654
655
656
657
658
659
660
661
662
663
664
665
666
			    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) {

667
668
	    /* Manage Raw Stream */
	    if(params.stc == -1) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
669
670
671
672
673
674
675
676
677

		/* 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
678
		    exitpdscondition = 1;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
679
680
681
682
683
		    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) {
684
			    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_DOD, "Timeout for channel %s (%d sec.)\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
685
686
687
688
689
690
691
692
				    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++;
		    }
		}

693
	    } else {
694

Matteo Quintiliani's avatar
Matteo Quintiliani committed
695
	    if(pd) {
696
697
698
699
		/* Management of gaps */
		if(!channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].significant = 1;
		} else {
700
		    if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
701
702
			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
703
			    nmxp_data_to_str(str_pd_time, pd->time);
704
			    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);
705
			}
706
		    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
707
		}
708
709
710
		if(channelListSeq[cur_chan].significant && pd->nSamp > 0) {
		    channelListSeq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
		}
711

Matteo Quintiliani's avatar
Matteo Quintiliani committed
712
713

#ifdef HAVE_LIBMSEED
714
715
716
717
		/* Write Mini-SEED record */
		if(params.flag_writeseed) {
		    nmxptool_write_miniseed(pd);
		}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
718
719
#endif

720
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
721
722
723
724
		/* Send data to SeedLink Server */
		if(params.flag_slink) {
		    nmxptool_send_raw_depoch(pd);
		}
725
#endif
726
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
727
	    }
728
	    } /* End skip_current_packet condition */
729

Matteo Quintiliani's avatar
Matteo Quintiliani committed
730
	    if(pd) {
731
732
733
734
735
736
737
738
739
		/* 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
740
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
741

Matteo Quintiliani's avatar
Matteo Quintiliani committed
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
#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

757
	} /* End main PDS loop */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
758
759
760
	
	/* Flush raw data stream for each channel */
	flushing_raw_data_stream();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
761
	save_channel_states();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
762

Matteo Quintiliani's avatar
Matteo Quintiliani committed
763
764
765
766
767
768
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_detach();
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
769
770
771
772
773
774
775
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	    /* Close output Mini-SEED file */
	    fclose(data_seed.outfile_mseed);
	}
#endif

776
777
778
779
780
781
782
783
784
785
786

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

787
788


789
    }
790

791
792
793
794
795
796
797
798
799
800
#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

801
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
802
	    nmxp_raw_stream_free(&(channelListSeq[i_chan].raw_stream_buffer));
803
804
	}

805
806
807
808
809
810
811
812
813
	if(channelListSeq) {
	    free(channelListSeq);
	}

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

814
    return 0;
815
} /* End MAIN */
816
817


Matteo Quintiliani's avatar
Matteo Quintiliani committed
818
static void save_channel_states() {
819
820
821
822
    int to_cur_chan;
    char last_time_str[30];
    char raw_last_sample_time_str[30];
    char state_line_str[1000];
823
    FILE *fstatefile = NULL;
824

825
    if(params.statefile) {
826
	fstatefile = fopen(params.statefile, "w");
827
	if(fstatefile == NULL) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
828
829
830
	    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);
831
	}
832

833
834
835
836
837
838
	/* 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);
839
	    sprintf(state_line_str, "%s %s %s",
840
		    channelList_subset->channel[to_cur_chan].name,
841
842
		    last_time_str,
		    raw_last_sample_time_str
843
844
845
		   );
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CHANNEL, "%s\n", state_line_str);
	    if(fstatefile) {
846
		fprintf(fstatefile, "%s\n", state_line_str);
847
848
		if( (channelListSeq[to_cur_chan].last_time != 0) || (channelListSeq[to_cur_chan].raw_stream_buffer.last_sample_time != -1.0) ) {
		    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "%s\n", state_line_str);
849
850
		} else {
		    /* Do nothing */
851
		}
852
853
854
	    }
	    to_cur_chan++;
	}
855
	if(fstatefile) {
856
	    fclose(fstatefile);
857
858
859
860
	}
    }
}

861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
void load_channel_states(NMXP_CHAN_LIST_NET *chan_list, NMXPTOOL_CHAN_SEQ *chan_list_seq) {
    FILE *fstatefile = NULL;
#define MAXSIZE_LINE 2048
    char line[MAXSIZE_LINE];
    char s_chan[128];
    char s_noraw_time_s[128];
    char s_rawtime_s[128];
    double s_noraw_time_f_calc, s_rawtime_f_calc;
    int cur_chan;
    int n_scanf;
    NMXP_TM_T tmp_tmt;

    if(params.statefile) {
	fstatefile = fopen(params.statefile, "r");
	if(fstatefile == NULL) {
	    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, "Loading channel states from %s!\n", params.statefile);
	    while(fgets(line, MAXSIZE_LINE, fstatefile) != NULL) {
		s_chan[0] = 0;
		s_noraw_time_s[0] = 0;
		s_rawtime_s[0] = 0;
		n_scanf = sscanf(line, "%s %s %s", s_chan, s_noraw_time_s, s_rawtime_s); 

		s_noraw_time_f_calc = DEFAULT_BUFFERED_TIME;
	       	s_rawtime_f_calc = DEFAULT_BUFFERED_TIME;
		if(n_scanf == 3) {
		    if(nmxp_data_parse_date(s_noraw_time_s, &tmp_tmt) == -1) {
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "Error parsing %s\n", s_noraw_time_s); 
		    } else {
			s_noraw_time_f_calc = nmxp_data_tm_to_time(&tmp_tmt);
		    }
		    if(nmxp_data_parse_date(s_rawtime_s, &tmp_tmt) == -1) {
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "Error parsing %s\n", s_rawtime_s); 
		    } else {
			s_rawtime_f_calc = nmxp_data_tm_to_time(&tmp_tmt);
		    }
		}
		nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_PACKETMAN, "%d %-14s %16.4f %s %16.4f %s\n", n_scanf, s_chan, s_noraw_time_f_calc, s_noraw_time_s, s_rawtime_f_calc, s_rawtime_s); 
		cur_chan = 0;
		while(cur_chan < chan_list->number  &&  strcasecmp(s_chan, chan_list->channel[cur_chan].name) != 0) {
		    cur_chan++;
		}
		if(cur_chan < chan_list->number) {
		    if( s_rawtime_f_calc != DEFAULT_BUFFERED_TIME  && s_rawtime_f_calc != 0.0 ) {
			chan_list_seq[cur_chan].after_start_time = s_rawtime_f_calc;
			nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "For channel %s starting from %s.\n", s_chan, s_rawtime_s); 
		    } else if( s_noraw_time_f_calc != DEFAULT_BUFFERED_TIME ) {
			chan_list_seq[cur_chan].after_start_time = s_noraw_time_f_calc;
			nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "For channel %s starting from %s.\n", s_chan, s_noraw_time_s); 
		    } else {
			nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "For channel %s there is not valid start_time.\n", s_chan); 
		    }
		}
	    }
	    fclose(fstatefile);
	}
    }
}

921

Matteo Quintiliani's avatar
Matteo Quintiliani committed
922
923
924
925
926
927
928
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) {
929
	    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Flushing data for channel %s\n",
Matteo Quintiliani's avatar
Matteo Quintiliani committed
930
931
932
933
934
935
		    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++;
	}
    }
}
936

Matteo Quintiliani's avatar
Matteo Quintiliani committed
937
#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
938
939
/* Do any needed cleanup and exit */
static void clientShutdown(int sig) {
940

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
943
    flushing_raw_data_stream();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
944
    save_channel_states();
Matteo Quintiliani's avatar
Matteo Quintiliani committed
945

Matteo Quintiliani's avatar
Matteo Quintiliani committed
946
947
948
949
950
    if(params.flag_writefile  &&  outfile) {
	/* Close output file */
	fclose(outfile);
    }

951
952
953
954
955
956
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_detach();
	}
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
957
958
959
960
961
962
963
#ifdef HAVE_LIBMSEED
    if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	/* Close output Mini-SEED file */
	fclose(data_seed.outfile_mseed);
    }
#endif

964

Matteo Quintiliani's avatar
Matteo Quintiliani committed
965
966
967
968
969
970
    /* PDS Step 7: Send Terminate Subscription */
    nmxp_sendTerminateSubscription(naqssock, NMXP_SHUTDOWN_NORMAL, "Good Bye!");

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

971

Matteo Quintiliani's avatar
Matteo Quintiliani committed
972
973
974

    /* Free the complete channel list */
    if(channelList) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
975
	free(channelList);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
976
	channelList = NULL;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
977
    }
978

979
980
    int i_chan = 0;

981
982
983
984
985
986
987
988
989
990
#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

991
    for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
992
	nmxp_raw_stream_free(&(channelListSeq[i_chan].raw_stream_buffer));
993
994
    }

995
996
997
998
999
    if(channelListSeq) {
	free(channelListSeq);
    }

    /* This has to be the last */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1000
1001
1002
1003
1004
1005
    if(channelList_subset == NULL) {
	free(channelList_subset);
    }

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1007
1008
1009
1010

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1012
1013
#endif /* HAVE_WINDOWS_H */

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1014
1015
1016



1017
#ifdef HAVE_LIBMSEED
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1018
1019
1020
1021
1022
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) {

1023
	ret = nmxp_data_msr_pack(pd, &data_seed, msr_list_chan[cur_chan]);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1024
1025

    } else {
1026
	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
1027
1028
1029
    }
    return ret;
}
1030
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1031

1032
1033
int nmxptool_print_seq_no(NMXP_DATA_PROCESS *pd) {
    int ret = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1034
1035
    char str_time[200];
    nmxp_data_to_str(str_time, pd->time);
1036

1037
    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "Process %s.%s.%s %2d %d %d %s %dpts lat. %.1fs\n",