nmxptool.c 12.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <nmxp.h>

#include "nmxptool_getoptlong.h"

#include "config.h"

11
12
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_H
#include "seedlink_plugin.h"
13
14
#endif

Matteo Quintiliani's avatar
Matteo Quintiliani committed
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
typedef struct {
    int significant;
    double last_time;
    int prev_xn;
} NMXP_CHAN_SUPPORT;


static void clientShutdown(int sig);
static void clientDummyHandler(int sig);


/* 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;
#ifdef HAVE_LIBMSEED
/* Mini-SEED variables */
NMXP_DATA_SEED data_seed;
NMXP_CHAN_SUPPORT *channelListSupport = NULL;
#endif

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

int main (int argc, char **argv) {
    uint32_t connection_time;
    int request_SOCKET_OK;
    int i_chan;

    NMXP_MSG_SERVER type;
    void *buffer;
    uint32_t length;
    int ret;

    char filename[500];
    char *station_code = NULL, *channel_code = NULL;

    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
59
60
61
62
63
64
65
66
#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);
67

Matteo Quintiliani's avatar
Matteo Quintiliani committed
68
69
70
71
72
73
74
75
76
77
78
79
    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 */
80
81
82
83
84
85
86
87
88
89
90
91
    nmxp_log(-1, 0);

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

    /* Check consistency of params */
    if(nmxptool_check_params(&params) != 0) {
	return 1;
    }

92
93
94
95
    if(params.flag_verbose) {
	nmxp_log(-1, 2);
    }

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    /* List available channels on server */
    if(params.flag_listchannels) {

	channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
	nmxp_chan_print_channelList(channelList);

	return 1;
    }

    /* 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
113
114
    } else {
	nmxp_chan_print_channelList(channelList_subset);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
115
116
117
118
119
120
121
122
123
124

#ifdef HAVE_LIBMSEED
	/* init channelListSupport */
	channelListSupport = (NMXP_CHAN_SUPPORT *) malloc(sizeof(NMXP_CHAN_SUPPORT) * channelList_subset->number);
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
	    channelListSupport[i_chan].significant = 0;
	    channelListSupport[i_chan].last_time = 0.0;
	    channelListSupport[i_chan].prev_xn = 0;
	}
#endif
125
126
127
128
129
130
131
132
    }

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

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

135

136
137
    /* TODO condition starting DAP */
    if(params.start_time != 0   &&   params.end_time != 0) {
138

139
140
141
	/* ************************************************************** */
	/* Start subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************** */
142

143
144
145
146
147
	/* 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;
	}
148

149
150
151
152
153
	/* 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;
	}
154

155
156
157
158
159
160
161
162
163
164
165
	/* 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;
	}
166

167
168
169
	/* Start loop for sending requests */
	i_chan=0;
	request_SOCKET_OK = NMXP_SOCKET_OK;
170

171
	while(request_SOCKET_OK == NMXP_SOCKET_OK  &&  i_chan < channelList_subset->number) {
172

173
174
	    /* DAP Step 5: Send Data Request */
	    request_SOCKET_OK = nmxp_sendDataRequest(naqssock, channelList_subset->channel[i_chan].key, params.start_time, params.end_time);
175

176
	    if(request_SOCKET_OK == NMXP_SOCKET_OK) {
177

178
179
		if(params.flag_writefile) {
		    /* Open output file */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
180
181
182
183
184
		    sprintf(filename, "%s.%s.%d.%d.%d.nmx",
			    (params.network)? params.network : DEFAULT_NETWORK,
			    channelList_subset->channel[i_chan].name,
			    channelList_subset->channel[i_chan].key,
			    params.start_time, params.end_time);
185

186
187
188
189
		    outfile = fopen(filename, "w");
		    if(!outfile) {
			nmxp_log(1, 0, "Can not to open file %s!", filename);
		    }
190
191
192
		}

#ifdef HAVE_LIBMSEED
193
194
		if(params.flag_writeseed) {
		    /* Open output Mini-SEED file */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
195
196
197
198
199
200
		    sprintf(data_seed.filename_mseed, "%s.%s.%d.%d.%d.miniseed",
			    (params.network)? params.network : DEFAULT_NETWORK,
			    channelList_subset->channel[i_chan].name,
			    channelList_subset->channel[i_chan].key,
			    params.start_time,
			    params.end_time);
201

202
203
204
205
206
207
		    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
208

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
		if(params.flag_writefile  &&  outfile) {
		    /* Compute SNCL line */

		    /* Separate station_code and channel_code */
		    station_code = NULL;
		    channel_code = NULL;

		    station_code = strdup(channelList_subset->channel[i_chan].name);
		    if ( (channel_code = strchr(station_code, '.')) == NULL ) {
			nmxp_log(1,0, "Channel name not in STA.CHAN format: %s\n", station_code);
		    }     
		    if(channel_code) {
			*channel_code++ = '\0'; 
		    }     

		    if(station_code) {
			free(station_code);
		    }
227

228
229
		    /* Write SNCL line */
		    fprintf(outfile, "%s.%s.%s.%s\n", station_code, (params.network)? params.network : DEFAULT_NETWORK, channel_code, (params.location)? params.location : "");
230
231
		}

232
233
234
		/* 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);
235

236
		while(ret == NMXP_SOCKET_OK   &&    type != NMXP_MSG_READY) {
237

238
		    /* Process a packet and return value in NMXP_DATA_PROCESS structure */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
239
240
241
242
		    pd = nmxp_processCompressedData(buffer, length, channelList_subset);

		    /* Log contents of last packet */
		    nmxp_data_log(pd);
243
244

#ifdef HAVE_LIBMSEED
245
246
		    /* Write Mini-SEED record */
		    if(params.flag_writeseed) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
247
			nmxp_data_msr_pack(pd, &data_seed, NULL);
248
		    }
249
250
#endif

251
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
252
253
254
255
256
		    /* Send data to SeedLink Server */
		    if(params.flag_writeseedlink) {
			/* TODO Set values */
			const int usec_correction = 0;
			const int timing_quality = 100;
257

258
259
260
			send_raw_depoch(pd->station, pd->channel, pd->time, usec_correction, timing_quality,
				pd->pDataPtr, pd->nSamp);
		    }
261
262
#endif

263
264
265
266
267
268
269
270
271
		    if(params.flag_writefile  &&  outfile) {
			/* Write buffer to the output file */
			if(outfile && buffer && length > 0) {
			    int length_int = length;
			    nmxp_data_swap_4b((int32_t *) &length_int);
			    fwrite(&length_int, sizeof(length_int), 1, outfile);
			    fwrite(buffer, length, 1, outfile);
			}
		    }
272

Matteo Quintiliani's avatar
Matteo Quintiliani committed
273
274
275
		    if(pd->buffer) {
			free(pd->buffer);
			pd->buffer = NULL;
276
		    }
277
278
279
280

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

283
284
285
		if(params.flag_writefile  &&  outfile) {
		    /* Close output file */
		    fclose(outfile);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
286
		    outfile = NULL;
287
288
		}

289
290
291
292
#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
293
		    data_seed.outfile_mseed = NULL;
294
295
		}
#endif
296
297

	    }
298
299
300
	    i_chan++;
	}
	/* DAP Step 7: Repeat steps 5 and 6 for each data request */
301

302
303
304
305
306
307
308
309
310
311
312
	/* 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 */
	/* ************************************************************ */

    } else {
313

314
315
316
317
318
319
320
321
322
	/* ************************************************************* */
	/* 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;
323
324
	}

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
	/* 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) */
342
343


344
345
346
347
348
349
	/* 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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed) {
	    /* Open output Mini-SEED file */
	    sprintf(data_seed.filename_mseed, "%s.realtime.miniseed",
		    (params.network)? params.network : DEFAULT_NETWORK);

	    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

365
366
	while(1) {
	    /* Process Compressed or Decompressed Data */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
	    pd = nmxp_receiveData(naqssock, channelList_subset);

	    /* Log contents of last packet */
	    nmxp_data_log(pd);


#ifdef HAVE_LIBMSEED
	    /* Write Mini-SEED record */
	    if(params.flag_writeseed) {
		int *pprev_xn = NULL;
		
		if( (i_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset)) != -1) {
		    if(channelListSupport[i_chan].significant) {
			pprev_xn = &(channelListSupport[i_chan].prev_xn);
		    }

		    nmxp_data_msr_pack(pd, &data_seed, NULL);

		    /* First time */
		    if(!channelListSupport[i_chan].significant) {
			channelListSupport[i_chan].significant = 1;
			channelListSupport[i_chan].prev_xn = pd->pDataPtr[pd->nSamp-1];
		    }

		    channelListSupport[i_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
		} else {
		    nmxp_log(1, 0, "Key %d not found in channelList_subset!\n", pd->key);
		}
	    }
#endif

	    if(pd->buffer) {
		free(pd->buffer);
		pd->buffer = NULL;
	    }

	}

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

	if(channelList_subset) {
	    free(channelList_subset);
417
418
419
420
421
422
423
424
425
426
427
428
429
	}

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

    }
430
431
432
433
434
435
436
437
438


    return 0;
}





Matteo Quintiliani's avatar
Matteo Quintiliani committed
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/* Do any needed cleanup and exit */
static void clientShutdown(int sig) {
    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

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

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

    if(channelList == NULL) {
	free(channelList);
    }
    if(channelList_subset == NULL) {
	free(channelList_subset);
    }
    if(channelListSupport == NULL) {
	free(channelListSupport);
    }

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
474
475
476
477

/* Empty signal handler routine */
static void clientDummyHandler(int sig) {
}