nmxptool.c 44 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.166 2008-04-01 05:47:38 mtheo Exp $
11
 *
Matteo Quintiliani's avatar
Matteo Quintiliani committed
12 13
 */

14 15
#include "config.h"

16 17 18
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
19
#include <errno.h>
20
#include <signal.h>
21 22

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

24 25 26 27
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif

28
#include "nmxptool_getoptlong.h"
29 30

#ifdef HAVE_EARTHWORMOBJS
31
#include "nmxptool_ew.h"
32
#endif
33

34 35 36
#ifdef HAVE_LIBMSEED
#include <libmseed.h>
#endif
37

38 39
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_H
#include "seedlink_plugin.h"
40 41
#endif

42 43
#define TIMES_FLOW_EXIT 100

44 45
#define DAP_CONDITION(params_struct) ( params_struct.start_time != 0.0 || params_struct.delay > 0 )

46 47 48
#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
49
#define GAP_TOLLERANCE 0.001
50

51 52 53
typedef struct {
    int significant;
    double last_time;
54
    time_t last_time_call_raw_stream;
55
    int32_t x_1;
56
    double after_start_time;
57
    NMXP_RAW_STREAM_DATA raw_stream_buffer;
58 59
} NMXPTOOL_CHAN_SEQ;

60

61 62
static void ShutdownHandler(int sig);
static void AlarmHandler(int sig);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
63

64
static void save_channel_states(NMXP_CHAN_LIST_NET *chan_list, NMXPTOOL_CHAN_SEQ *chan_list_seq);
65
void load_channel_states(NMXP_CHAN_LIST_NET *chan_list, NMXPTOOL_CHAN_SEQ *chan_list_seq);
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
int nmxptool_log_miniseed(const char *s);
int nmxptool_logerr_miniseed(const char *s);
72 73
#endif

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

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

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


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

95 96 97 98 99 100 101

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

102
int sigcondition = 0;
103

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
114
    int span_interval = 10;
115 116
    int time_to_sleep = 0;

117 118 119
    char str_start_time[200] = "";
    char str_end_time[200] = "";
    char str_pd_time[200] = "";
120 121

    NMXP_MSG_SERVER type;
122
    void *buffer = NULL;
123
    int32_t length;
124 125
    int ret;

126
    int pd_null_count = 0;
127
    int timeoutrecv_warning = 300; /* 5 minutes */
128

129 130
    int times_flow = 0;

131 132
    int recv_errno = 0;

133 134
    char filename[500] = "";
    char station_code[20] = "", channel_code[20] = "", network_code[20] = "";
135

Matteo Quintiliani's avatar
Matteo Quintiliani committed
136
    char cur_after_start_time_str[1024];
137 138
    double cur_after_start_time = DEFAULT_BUFFERED_TIME;
    int skip_current_packet = 0;
139

140
    double default_start_time = 0.0;
141
    char start_time_str[30], end_time_str[30], default_start_time_str[30];
142

143
    NMXP_DATA_PROCESS *pd = NULL;
144

145
#ifndef HAVE_WINDOWS_H
Matteo Quintiliani's avatar
Matteo Quintiliani committed
146 147 148
    /* Signal handling, use POSIX calls with standardized semantics */
    struct sigaction sa;

149
    sa.sa_handler = AlarmHandler;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
150 151 152
    sa.sa_flags = SA_RESTART;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);
153

154
    sa.sa_handler = ShutdownHandler;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
155 156 157 158 159 160 161
    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); 
162
#else
163
    /*
164
    signal(SIGALRM, AlarmHandler);
165
    */
166 167

    signal(SIGINT, ShutdownHandler);
168
    /*
169
    signal(SIGQUIT, ShutdownHandler);
170
    */
171 172
    signal(SIGTERM, ShutdownHandler);

173
    /*
174 175
    signal(SIGHUP, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
176
    */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
177 178 179
#endif

    /* Default is normal output */
180
    nmxp_log(NMXP_LOG_SET, NMXP_LOG_D_NULL);
181 182 183 184 185 186

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

187
    if(params.ew_configuration_file) {
188 189

#ifdef HAVE_EARTHWORMOBJS
190

191 192
	nmxp_log_init(nmxptool_ew_logit_msg, nmxptool_ew_logit_err);

193
	nmxptool_ew_configure(argv, &params);
194

195 196 197 198
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}
199

200
#endif
201

202
    } else {
203

204 205
	nmxp_log_init(nmxp_log_stdout, nmxp_log_stderr);

206 207 208 209 210
	/* Check consistency of params */
	if(nmxptool_check_params(&params) != 0) {
	    return 1;
	}

211 212
	/* List available channels on server */
	if(params.flag_listchannels) {
213

214 215
	    nmxp_meta_chan_print(nmxp_getMetaChannelList(params.hostname, params.portnumberdap, NMXP_DATA_TIMESERIES, params.flag_request_channelinfo, params.datas_username, params.datas_password, &channelList));

216
	    return 1;
217

218 219 220 221
	} else if(params.flag_listchannelsnaqs) {

	    channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
	    nmxp_chan_print_channelList(channelList);
222
	    return 1;
223

224 225
	}
    }
226

227
    nmxp_log(NMXP_LOG_SET, params.verbose_level);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
228 229 230
    if(params.verbose_level != DEFAULT_VERBOSE_LEVEL) {
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "verbose_level %d\n", params.verbose_level);
    }
231

232 233
    nmxptool_log_params(&params);

234
    NMXP_MEM_PRINT_PTR;
235

236 237
#ifdef HAVE_LIBMSEED
    if(params.flag_writeseed) {
238
	ms_loginit((void*)&nmxptool_log_miniseed, NULL, (void*)&nmxptool_logerr_miniseed, "error: ");
239 240 241 242 243 244
	/* Init mini-SEED variables */
	nmxp_data_seed_init(&data_seed);
    }
#endif


245
    /* Get list of available channels and get a subset list of params.channels */
246
    if( DAP_CONDITION(params) ) {
247
	/* From DataServer */
248 249 250 251
	if(!nmxp_getMetaChannelList(params.hostname, params.portnumberdap, NMXP_DATA_TIMESERIES,
		    params.flag_request_channelinfo, params.datas_username, params.datas_password, &channelList)) {
	    return -1;
	}
252 253 254 255 256
    } else {
	/* From NaqsServer */
	channelList = nmxp_getAvailableChannelList(params.hostname, params.portnumberpds, NMXP_DATA_TIMESERIES);
    }

257 258 259 260 261
    if(!channelList) {
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL, "Channel list has not been received!\n");
	return 1;
    }

262
    channelList_subset = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
263 264 265
    
    /* Free the complete channel list */
    if(channelList) {
266
	NMXP_MEM_FREE(channelList);
267 268
	channelList = NULL;
    }
269 270 271

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

277
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CHANNEL, "Init channelList_Seq.\n");
278

279
	/* init channelList_Seq */
280
	channelList_Seq = (NMXPTOOL_CHAN_SEQ *) NMXP_MEM_MALLOC(sizeof(NMXPTOOL_CHAN_SEQ) * channelList_subset->number);
281
	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
282 283 284 285 286 287
	    channelList_Seq[i_chan].significant = 0;
	    channelList_Seq[i_chan].last_time = 0.0;
	    channelList_Seq[i_chan].last_time_call_raw_stream = 0;
	    channelList_Seq[i_chan].x_1 = 0;
	    channelList_Seq[i_chan].after_start_time = DEFAULT_BUFFERED_TIME;
	    nmxp_raw_stream_init(&(channelList_Seq[i_chan].raw_stream_buffer), params.max_tolerable_latency, params.timeoutrecv);
288 289
	}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
290
#ifdef HAVE_LIBMSEED
291 292
	if(params.flag_writeseed) {
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Init mini-SEED record list.\n");
293

294 295
	    /* Init mini-SEED record list */
	    for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
296

297 298
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA,
			"Init mini-SEED record for %s\n", NMXP_LOG_STR(channelList_subset->channel[i_chan].name));
299

300
		msr_list_chan[i_chan] = msr_init(NULL);
301

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

305 306
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "%s.%s.%s\n",
			    NMXP_LOG_STR(NETCODE_OR_CURRENT_NETWORK), NMXP_LOG_STR(station_code), NMXP_LOG_STR(channel_code));
307

308 309 310
		    strcpy(msr_list_chan[i_chan]->network, NETCODE_OR_CURRENT_NETWORK);
		    strcpy(msr_list_chan[i_chan]->station, station_code);
		    strcpy(msr_list_chan[i_chan]->channel, channel_code);
311

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

315 316 317 318 319
		} else {
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANNEL,
			    "Channels %s error in format!\n", NMXP_LOG_STR(channelList_subset->channel[i_chan].name));
		    return 1;
		}
320

321
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
322 323
	}
#endif
324

325 326
    }

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
#ifdef HAVE_EARTHWORMOBJS
    if(params.ew_configuration_file) {
	nmxptool_ew_attach();
    }
#endif

    if(params.stc == -1) {

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

#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

353 354
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
355
	    p_func_pd[n_func_pd++] = nmxptool_ew_nmx2ew;
356 357 358
	}
#endif

359 360 361
    }


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

364 365
    times_flow = 0;

366
    while(times_flow < 2  &&  recv_errno == 0 && !sigcondition) {
367

368 369 370 371
	if(params.statefile) {
	    load_channel_states(channelList_subset, channelList_Seq);
	}

372 373 374 375 376 377 378 379 380 381 382
	if(times_flow == 0) {
	    if(params.statefile) {
		params.interval = DEFAULT_INTERVAL_INFINITE;
	    }
	} else if(times_flow == 1) {
	    params.start_time = 0.0;
	    params.end_time = 0.0;
	    params.interval = DEFAULT_INTERVAL_NO_VALUE;

	}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
383
    /* Condition for starting DAP or PDS */
384 385
    if( DAP_CONDITION(params) ||
	    (times_flow == 0  &&  params.statefile && params.max_data_to_retrieve > 0 && params.interval == DEFAULT_INTERVAL_INFINITE) ) {
386 387

	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "Begin DAP Flow.\n");
388

389 390 391 392 393 394 395
	if(params.interval > 0  ||  params.interval == DEFAULT_INTERVAL_INFINITE) {
	    if(params.interval > 0) {
		params.end_time = params.start_time + params.interval;
	    } else {
		params.end_time = nmxp_data_gmtime_now();
	    }
	} else if(params.delay > 0) {
396
	    params.start_time = ((double) (time(NULL) - params.delay - span_interval) / 10.0) * 10.0;
397 398 399
	    params.end_time = params.start_time + span_interval;
	}

400

401 402 403
	/* ************************************************************** */
	/* Start subscription protocol "DATA ACCESS PROTOCOL" version 1.0 */
	/* ************************************************************** */
404

405 406
	/* DAP Step 1: Open a socket */
	if( (naqssock = nmxp_openSocket(params.hostname, params.portnumberdap)) == NMXP_SOCKET_ERROR) {
407
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error opening socket!\n");
408 409
	    return 1;
	}
410

411 412
	/* DAP Step 2: Read connection time */
	if(nmxp_readConnectionTime(naqssock, &connection_time) != NMXP_SOCKET_OK) {
413
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error reading connection time from server!\n");
414 415
	    return 1;
	}
416

417 418
	/* DAP Step 3: Send a ConnectRequest */
	if(nmxp_sendConnectRequest(naqssock, params.datas_username, params.datas_password, connection_time) != NMXP_SOCKET_OK) {
419
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error sending connect request!\n");
420 421 422 423 424
	    return 1;
	}

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

429 430
	exitdapcondition = 1;

431
	default_start_time = (params.start_time > 0.0)? params.start_time : nmxp_data_gmtime_now() - params.max_data_to_retrieve;
432

433
	while(exitdapcondition  &&  !sigcondition) {
434

435
	    /* Start loop for sending requests */
436
	    request_chan=0;
437
	    request_SOCKET_OK = NMXP_SOCKET_OK;
438

439
	    /* For each channel */
440
	    while(request_SOCKET_OK == NMXP_SOCKET_OK  &&  request_chan < channelList_subset->number  &&  exitdapcondition && !sigcondition) {
441

442
		if(params.statefile) {
443 444
		    if(channelList_Seq[request_chan].after_start_time > 0) {
			params.start_time = channelList_Seq[request_chan].after_start_time;
445
			if(params.end_time - params.start_time > params.max_data_to_retrieve) {
446
			    nmxp_data_to_str(start_time_str, params.start_time);
447
			    nmxp_data_to_str(default_start_time_str, params.end_time - params.max_data_to_retrieve);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
448
			    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "%s start_time changed from %s to %s\n",
449 450 451
				    NMXP_LOG_STR(channelList_subset->channel[request_chan].name),
				    NMXP_LOG_STR(start_time_str),
				    NMXP_LOG_STR(default_start_time_str));
452
			    params.start_time = params.end_time - params.max_data_to_retrieve;
453
			}
454 455 456
		    } else {
			params.start_time = default_start_time;
		    }
457 458
		    channelList_Seq[request_chan].last_time = params.start_time;
		    channelList_Seq[request_chan].significant = 1;
459

460
		}
461

462 463
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "nmxp_sendDataRequest %d %s (%d)\n",
			channelList_subset->channel[request_chan].key,
464 465
			NMXP_LOG_STR(channelList_subset->channel[request_chan].name),
			request_chan);
466

467 468 469
		nmxp_data_to_str(start_time_str, params.start_time);
		nmxp_data_to_str(end_time_str, params.end_time);
		nmxp_data_to_str(default_start_time_str, default_start_time);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
470
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "%s start_time = %s - end_time = %s - (default_start_time = %s)\n",
471 472 473 474
			NMXP_LOG_STR(channelList_subset->channel[request_chan].name),
			NMXP_LOG_STR(start_time_str),
			NMXP_LOG_STR(end_time_str),
			NMXP_LOG_STR(default_start_time_str));
475

476
		/* DAP Step 5: Send Data Request */
477
		request_SOCKET_OK = nmxp_sendDataRequest(naqssock, channelList_subset->channel[request_chan].key, (int32_t) params.start_time, (int32_t) (params.end_time + 1.0));
478

479
		if(request_SOCKET_OK == NMXP_SOCKET_OK) {
480

481 482 483 484
		    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);
485

486 487
		    if(params.flag_writefile) {
			/* Open output file */
488
			if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[request_chan].name, station_code, channel_code, network_code)) {
489 490 491 492 493 494 495 496
			    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",
497
				    channelList_subset->channel[request_chan].name,
498 499 500
				    str_start_time,
				    str_end_time);
			}
501

502 503
			outfile = fopen(filename, "w");
			if(!outfile) {
504 505
			    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!",
				    NMXP_LOG_STR(filename));
506
			}
507
		    }
508 509

#ifdef HAVE_LIBMSEED
510 511
		    if(params.flag_writeseed) {
			/* Open output Mini-SEED file */
512
			if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[request_chan].name, station_code, channel_code, network_code)) {
513 514 515 516 517 518 519 520
			    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",
521
				    channelList_subset->channel[request_chan].name,
522 523 524
				    str_start_time,
				    str_end_time);
			}
525

526 527
			data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
			if(!data_seed.outfile_mseed) {
528 529
			    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!",
				    NMXP_LOG_STR(data_seed.filename_mseed));
530
			}
531 532
		    }
#endif
533

534 535 536 537
		    if(params.flag_writefile  &&  outfile) {
			/* Compute SNCL line */

			/* Separate station_code_old_way and channel_code_old_way */
538
			if(nmxp_chan_cpy_sta_chan(channelList_subset->channel[request_chan].name, station_code, channel_code, network_code)) {
539 540 541 542 543 544 545
			    /* Write SNCL line */
			    fprintf(outfile, "%s.%s.%s.%s\n",
				    station_code,
				    NETCODE_OR_CURRENT_NETWORK,
				    channel_code,
				    (params.location)? params.location : "");
			}
546

547
		    }
548

549 550
		    /* DAP Step 6: Receive Data until receiving a Ready message */
		    ret = nmxp_receiveMessage(naqssock, &type, &buffer, &length, 0, &recv_errno);
551

552 553
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "ret = %d, type = %d, length = %d, recv_errno = %d\n",
			    ret, type, length, recv_errno);
554

555
		    while(ret == NMXP_SOCKET_OK   &&    type != NMXP_MSG_READY) {
556

557 558 559
			/* Process a packet and return value in NMXP_DATA_PROCESS structure */
			pd = nmxp_processCompressedData(buffer, length, channelList_subset, NETCODE_OR_CURRENT_NETWORK);
			nmxp_data_trim(pd, params.start_time, params.end_time, 0);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
560

561 562 563
			/* To prevent to manage a packet with zero sample after nmxp_data_trim() */
			if(pd->nSamp > 0) {

564 565
			/* Log contents of last packet */
			if(params.flag_logdata) {
566
			    nmxp_data_log(pd, params.flag_logsample);
567
			}
568

569 570
			/* Set cur_chan */
			cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
571 572 573 574 575

			/* It is not the channel I have requested or error from nmxp_chan_lookupKeyIndex() */
			if(request_chan != cur_chan  &&  cur_chan != -1) {
			    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "request_chan != cur_chan  %d != %d! (%d, %s) (%d, %s.%s.%s)\n",
				    request_chan, cur_chan,
576 577 578
				    channelList_subset->channel[request_chan].key,
				    NMXP_LOG_STR(channelList_subset->channel[request_chan].name),
				    pd->key, NMXP_LOG_STR(pd->network), NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel));
579
			} else {
580

581
			/* Management of gaps */
582 583
			if(!channelList_Seq[cur_chan].significant && pd->nSamp > 0) {
			    channelList_Seq[cur_chan].significant = 1;
584
			} else {
585 586 587
			    if(channelList_Seq[cur_chan].significant && pd->nSamp > 0) {
				if(nmxptool_check_and_log_gap(pd->time, channelList_Seq[cur_chan].last_time, GAP_TOLLERANCE, pd->station, pd->channel)) {
				    channelList_Seq[cur_chan].x_1 = 0;
588
				    nmxp_data_to_str(str_pd_time, pd->time);
589 590
				    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_EXTRA, "%s.%s x0 set to zero at %s!\n",
					    NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel), NMXP_LOG_STR(str_pd_time));
591
				}
592
			    }
593
			}
594 595
			if(channelList_Seq[cur_chan].significant && pd->nSamp > 0) {
			    channelList_Seq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
596
			}
597

598
#ifdef HAVE_LIBMSEED
599 600 601 602
			/* Write Mini-SEED record */
			if(params.flag_writeseed) {
			    nmxptool_write_miniseed(pd);
			}
603
#endif
604

605
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
606 607 608 609
			/* Send data to SeedLink Server */
			if(params.flag_slink) {
			    nmxptool_send_raw_depoch(pd);
			}
610 611
#endif

612 613 614 615 616 617
#ifdef HAVE_EARTHWORMOBJS
			if(params.ew_configuration_file) {
			    nmxptool_ew_nmx2ew(pd);
			}
#endif

618 619 620 621 622 623 624 625
			if(params.flag_writefile  &&  outfile) {
			    /* Write buffer to the output file */
			    if(outfile && buffer && length > 0) {
				int32_t length_int = length;
				nmxp_data_swap_4b((int32_t *) &length_int);
				fwrite(&length_int, sizeof(length_int), 1, outfile);
				fwrite(buffer, length, 1, outfile);
			    }
626
			}
627

628 629 630
			/* Store x_1 */
			channelList_Seq[cur_chan].x_1 = pd->pDataPtr[pd->nSamp-1];

631 632
			}

633 634
			} else {
			    /* TODO: nSamp <= 0 */
635
			}
636

637

638 639
			/* Free pd->buffer */
			if(pd->buffer) {
640
			    NMXP_MEM_FREE(pd->buffer);
641 642
			    pd->buffer = NULL;
			}
643

644 645
			/* Receive Data */
			ret = nmxp_receiveMessage(naqssock, &type, &buffer, &length, 0, &recv_errno);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
646
			/* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "ret = %d, type = %d\n", ret, type); */
647
		    }
648

649 650 651 652 653
		    if(params.flag_writefile  &&  outfile) {
			/* Close output file */
			fclose(outfile);
			outfile = NULL;
		    }
654

655
#ifdef HAVE_LIBMSEED
656 657 658 659 660
		    if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
			/* Close output Mini-SEED file */
			fclose(data_seed.outfile_mseed);
			data_seed.outfile_mseed = NULL;
		    }
661
#endif
662

663 664
		} else {
		    /* TODO: error message */
665
		}
666
		request_chan++;
667 668 669 670 671 672 673

#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");
674
			nmxptool_ew_send_error(NMXPTOOL_EW_ERR_TERMREQ, NULL);
675 676 677 678 679 680 681 682 683 684
			exitdapcondition = 0;
			times_flow = TIMES_FLOW_EXIT;
		    }

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

		}
#endif

685
	    }
686
	    /* DAP Step 7: Repeat steps 5 and 6 for each data request */
687

688 689 690 691 692 693 694 695 696 697
	    if(params.delay > 0) {
		time_to_sleep = (params.end_time - params.start_time) - (time(NULL) - (params.start_time + params.delay + span_interval));
		if(time_to_sleep >= 0) {
		    nmxp_sleep(time_to_sleep);
		} else {
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "time to sleep %d sec.\n", time_to_sleep);
		    nmxp_sleep(3);
		}
		params.start_time = params.end_time;
		params.end_time = params.start_time + span_interval;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
698
	    } else {
699
		exitdapcondition = 0;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
700
	    }
701

702
	} /* END while(exitdapcondition) */
703

704 705 706 707 708 709 710 711 712 713
	/* 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 */
	/* ************************************************************ */

714
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "End DAP Flow.\n");
715

Matteo Quintiliani's avatar
Matteo Quintiliani committed
716
    } else {
717

718 719
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "Begin PDS Flow.\n");

720 721 722 723 724 725 726 727 728
	/* ************************************************************* */
	/* 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;
729 730
	}

731 732 733 734 735 736 737 738 739 740 741
	/* 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;
	}
742 743
	/* Get a subset of channel from arguments, in respect to the step 3 of PDS */
	channelList_subset_waste = nmxp_chan_subset(channelList, NMXP_DATA_TIMESERIES, params.channels, CURRENT_NETWORK);
744

745 746
	/* Free the complete channel list */
	if(channelList) {
747
	    NMXP_MEM_FREE(channelList);
748 749 750
	    channelList = NULL;
	}

751 752
	/* TODO check if channelList_subset_waste is equal to channelList_subset and free */
	if(channelList_subset_waste) {
753
	    NMXP_MEM_FREE(channelList_subset_waste);
754 755 756
	    channelList_subset_waste = NULL;
	}
	
757
	/* PDS Step 4: Send a Request Pending (optional) */
758

759 760
	/* PDS Step 5: Send AddChannels */
	/* Request Data */
761
	nmxp_sendAddTimeSeriesChannel(naqssock, channelList_subset, params.stc, params.rate,
762
		(params.flag_buffered)? NMXP_BUFFER_YES : NMXP_BUFFER_NO, params.n_channel, params.usec, 1);
763 764 765

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

Matteo Quintiliani's avatar
Matteo Quintiliani committed
766 767 768 769
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed) {
	    /* Open output Mini-SEED file */
	    sprintf(data_seed.filename_mseed, "%s.realtime.miniseed",
770
		    CURRENT_NETWORK);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
771 772 773

	    data_seed.outfile_mseed = fopen(data_seed.filename_mseed, "w");
	    if(!data_seed.outfile_mseed) {
774 775
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Can not to open file %s!",
			NMXP_LOG_STR(data_seed.filename_mseed));
Matteo Quintiliani's avatar
Matteo Quintiliani committed
776
	    } else {
777 778
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_EXTRA, "Opened file %s!\n",
			NMXP_LOG_STR(data_seed.filename_mseed));
Matteo Quintiliani's avatar
Matteo Quintiliani committed
779 780 781 782
	    }
	}
#endif

783
	/* TODO*/
Matteo Quintiliani's avatar
Matteo Quintiliani committed
784 785
	exitpdscondition = 1;

786
	skip_current_packet = 0;
787

788
	while(exitpdscondition && !sigcondition) {
789

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

793 794 795 796 797 798 799 800 801 802 803
	    if(!pd) {
		pd_null_count++;
		if((pd_null_count * params.timeoutrecv) >= timeoutrecv_warning) {
		    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Received %d times a null packet. (%d sec.)\n",
			    pd_null_count, pd_null_count * params.timeoutrecv);
		    pd_null_count = 0;
		}
	    } else {
		pd_null_count = 0;
	    }

804
	    if(recv_errno == 0) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
805 806
		exitpdscondition = 1;
	    } else {
807 808 809 810 811 812
#ifdef HAVE_WINDOWS_H
		if(recv_errno == WSAEWOULDBLOCK  ||  recv_errno == WSAETIMEDOUT)
#else
		if(recv_errno == EWOULDBLOCK)
#endif
		{
813 814
		    exitpdscondition = 1;
		} else {
815 816
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error receiving data. pd=%p recv_errno=%d\n",
			    pd, recv_errno);
817 818

#ifdef HAVE_EARTHWORMOBJS
819
		    if(params.ew_configuration_file) {
820
			nmxptool_ew_send_error(NMXPTOOL_EW_ERR_RECVDATA, nmxp_strerror(recv_errno));
821
		    }
822
#endif
823 824
		    exitpdscondition = 0;
		}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
825
	    }
826

827 828 829
	    if(pd) {
		/* Set cur_chan */
		cur_chan = nmxp_chan_lookupKeyIndex(pd->key, channelList_subset);
830
		if(cur_chan == -1) {
831 832
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "Key %d not found in channelList_subset!\n",
			    pd->key);
833
		}
834 835
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
836
	    /* Log contents of last packet */
837
	    if(params.flag_logdata) {
838
		nmxp_data_log(pd, params.flag_logsample);
839
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
840

841
	    skip_current_packet = 0;
842
	    if(pd &&
843 844
		    (params.statefile  ||  params.buffered_time) &&
		    ( params.timeoutrecv <= 0 )
845
	      )	{
846 847
		if(params.statefile && channelList_Seq[cur_chan].after_start_time > 0.0) {
		    cur_after_start_time = channelList_Seq[cur_chan].after_start_time;
848 849 850 851 852 853
		} else if(params.buffered_time) {
		    cur_after_start_time = params.buffered_time;
		} else {
		    cur_after_start_time = DEFAULT_BUFFERED_TIME;
		}
		nmxp_data_to_str(cur_after_start_time_str, cur_after_start_time);
854 855
		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, NMXP_LOG_STR(cur_after_start_time_str));
856 857 858
		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;
859 860 861 862
			/* 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;
863
			    pd->time = cur_after_start_time;
864 865 866 867 868 869 870 871 872 873 874
			    pd->pDataPtr += first_nsample_to_remove;
			    pd->x0 = pd->pDataPtr[0];
			} else {
			    skip_current_packet = 1;
			}
		    }
		} else {
		    skip_current_packet = 1;
		}
	    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
875
	    if(!skip_current_packet) {
876

877 878
		/* Manage Raw Stream */
		if(params.stc == -1) {
879

880 881
		    /* cur_char is computed only for pd != NULL */
		    if(pd) {
882 883
			nmxp_raw_stream_manage(&(channelList_Seq[cur_chan].raw_stream_buffer), pd, p_func_pd, n_func_pd);
			channelList_Seq[cur_chan].last_time_call_raw_stream = nmxp_data_gmtime_now();
884
		    }
885

886 887 888 889
		    /* Check timeout for other channels */
		    if(params.timeoutrecv > 0) {
			to_cur_chan = 0;
			while(to_cur_chan < channelList_subset->number) {
890 891
			    timeout_for_channel = nmxp_data_gmtime_now() - channelList_Seq[to_cur_chan].last_time_call_raw_stream;
			    if(channelList_Seq[to_cur_chan].last_time_call_raw_stream != 0
892 893
				    && timeout_for_channel >= params.timeoutrecv) {
				nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_DOD, "Timeout for channel %s (%d sec.)\n",
894
					NMXP_LOG_STR(channelList_subset->channel[to_cur_chan].name), timeout_for_channel);
895 896
				nmxp_raw_stream_manage(&(channelList_Seq[to_cur_chan].raw_stream_buffer), NULL, p_func_pd, n_func_pd);
				channelList_Seq[to_cur_chan].last_time_call_raw_stream = nmxp_data_gmtime_now();
897 898
			    }
			    to_cur_chan++;
899 900
			}
		    }
901 902

		} else {
903 904 905

		    if(pd) {
			/* Management of gaps */
906 907
			if(!channelList_Seq[cur_chan].significant && pd->nSamp > 0) {
			    channelList_Seq[cur_chan].significant = 1;
908
			} else {
909 910 911
			    if(channelList_Seq[cur_chan].significant && pd->nSamp > 0) {
				if(nmxptool_check_and_log_gap(pd->time, channelList_Seq[cur_chan].last_time, GAP_TOLLERANCE, pd->station, pd->channel)) {
				    channelList_Seq[cur_chan].x_1 = 0;
912
				    nmxp_data_to_str(str_pd_time, pd->time);
913 914
				    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_EXTRA, "%s.%s x0 set to zero at %s!\n",
					    NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel), NMXP_LOG_STR(str_pd_time));
915 916 917
				}
			    }
			}
918 919
			if(channelList_Seq[cur_chan].significant && pd->nSamp > 0) {
			    channelList_Seq[cur_chan].last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
920
			}
921

Matteo Quintiliani's avatar
Matteo Quintiliani committed
922 923

#ifdef HAVE_LIBMSEED
924 925 926 927
			/* Write Mini-SEED record */
			if(params.flag_writeseed) {
			    nmxptool_write_miniseed(pd);
			}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
928 929
#endif

930
#ifdef HAVE___SRC_SEEDLINK_PLUGIN_C
931 932 933 934
			/* Send data to SeedLink Server */
			if(params.flag_slink) {
			    nmxptool_send_raw_depoch(pd);
			}
935
#endif
936 937
		    }
		}
938
	    } /* End skip_current_packet condition */
939

940
	    if(pd) {
941 942
		/* Store x_1 */
		if(pd->nSamp > 0) {
943
		    channelList_Seq[cur_chan].x_1 = pd->pDataPtr[pd->nSamp-1];
944 945 946
		}
		/* Free pd->buffer */
		if(pd->buffer) {
947
		    NMXP_MEM_FREE(pd->buffer);
948 949
		    pd->buffer = NULL;
		}
950
	    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
951

952 953 954 955 956 957
#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");
958
		    nmxptool_ew_send_error(NMXPTOOL_EW_ERR_TERMREQ, NULL);
959
		    exitpdscondition = 0;
960
		    times_flow = TIMES_FLOW_EXIT;
961 962 963 964 965 966 967
		}

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

	    }
#endif
968
	    nmxp_sendAddTimeSeriesChannel(naqssock, channelList_subset, params.stc, params.rate,
969
		    (params.flag_buffered)? NMXP_BUFFER_YES : NMXP_BUFFER_NO, params.n_channel, params.usec, 0);
970

971
	} /* End main PDS loop */
972

Matteo Quintiliani's avatar
Matteo Quintiliani committed
973 974
	/* Flush raw data stream for each channel */
	flushing_raw_data_stream();
975

Matteo Quintiliani's avatar
Matteo Quintiliani committed
976 977 978 979 980 981 982
#ifdef HAVE_LIBMSEED
	if(params.flag_writeseed  &&  data_seed.outfile_mseed) {
	    /* Close output Mini-SEED file */
	    fclose(data_seed.outfile_mseed);
	}
#endif

983 984 985 986 987 988 989 990 991 992 993

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

994 995 996
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "End PDS Flow.\n");

    }
997

998 999
    if(times_flow != TIMES_FLOW_EXIT
	    &&  params.interval == DEFAULT_INTERVAL_INFINITE) {
1000 1001
	times_flow++;
    } else {
1002
	times_flow = TIMES_FLOW_EXIT;
1003
    }
1004

1005 1006 1007 1008
    if(params.statefile) {
	save_channel_states(channelList_subset, channelList_Seq);
    }

1009
    } /* End times_flow loop */
1010

1011 1012 1013 1014 1015 1016
#ifdef HAVE_EARTHWORMOBJS
	if(params.ew_configuration_file) {
	    nmxptool_ew_detach();
	}
#endif

1017
#ifdef HAVE_LIBMSEED
1018 1019 1020 1021 1022 1023 1024
	if(params.flag_writeseed) {
	    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]));
		    }
		}
1025 1026 1027 1028
	    }
	}
#endif

1029
    NMXP_MEM_PRINT_PTR;
1030

1031 1032 1033 1034 1035
    if(channelList_Seq  &&  channelList_subset) {

	for(i_chan = 0; i_chan < channelList_subset->number; i_chan++) {
	    nmxp_raw_stream_free(&(channelList_Seq[i_chan].raw_stream_buffer));
	}
1036

1037
	NMXP_MEM_FREE(channelList_Seq);
1038
	channelList_Seq = NULL;
1039
    }
1040

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1041
    /* This has to be the last */
1042
    if(channelList_subset) {
1043
	NMXP_MEM_FREE(channelList_subset);
1044
	channelList_subset = NULL;
1045
    }
1046

1047 1048
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "return code %d\n", sigcondition);

1049
    NMXP_MEM_PRINT_PTR;
1050

1051
    return sigcondition;
1052
} /* End MAIN */
1053 1054


1055 1056
#define MAX_LEN_FILENAME 4096

1057
static void save_channel_states(NMXP_CHAN_LIST_NET *chan_list, NMXPTOOL_CHAN_SEQ *chan_list_seq) {
1058 1059 1060 1061
    int to_cur_chan;
    char last_time_str[30];
    char raw_last_sample_time_str[30];
    char state_line_str[1000];
1062
    FILE *fstatefile = NULL;
1063
    char statefilefilename[MAX_LEN_FILENAME] = "";
1064

1065
    if(chan_list == NULL  ||  chan_list_seq == NULL) {
1066
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANSTATE, "save_channel_states() channel lists are NULL!\n");
1067 1068 1069
	return;
    }

1070
    if(params.statefile) {
1071 1072 1073
	strncpy(statefilefilename, params.statefile, MAX_LEN_FILENAME);
	strncat(statefilefilename, NMXP_STR_STATE_EXT, MAX_LEN_FILENAME);
	fstatefile = fopen(statefilefilename, "w");
1074
	if(fstatefile == NULL) {
1075
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CHANSTATE, "Unable to write channel states into %s!\n",
1076
		    NMXP_LOG_STR(statefilefilename));
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1077
	} else {
1078
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CHANSTATE, "Writing channel states into %s!\n",
1079
		    NMXP_LOG_STR(statefilefilename));
1080
	}
1081

1082
	/* Save state for each channel */
1083
	/* if(params.stc == -1)*/
1084
	to_cur_chan = 0;
1085 1086 1087
	while(to_cur_chan < chan_list->number) {
	    nmxp_data_to_str(last_time_str, chan_list_seq[to_cur_chan].last_time);
	    nmxp_data_to_str(raw_last_sample_time_str, chan_list_seq[to_cur_chan].raw_stream_buffer.last_sample_time);