nmxp_data.c 28.4 KB
Newer Older
1 2
/*! \file
 *
Matteo Quintiliani's avatar
Matteo Quintiliani committed
3
 * \brief Data for Nanometrics Protocol Library
4 5 6 7 8 9
 *
 * Author:
 * 	Matteo Quintiliani
 * 	Istituto Nazionale di Geofisica e Vulcanologia - Italy
 *	quintiliani@ingv.it
 *
10
 * $Id: nmxp_data.c,v 1.70 2009-08-31 12:16:41 mtheo Exp $
Matteo Quintiliani's avatar
Matteo Quintiliani committed
11
 *
12 13 14 15
 */

#include "nmxp_data.h"
#include "nmxp_log.h"
16
#include "nmxp_memory.h"
17 18 19 20

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
21
#include <errno.h>
22
#include <sys/stat.h>
23 24 25 26 27 28
#include <unistd.h>

#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif

29

Matteo Quintiliani's avatar
Matteo Quintiliani committed
30 31 32
#include "config.h"

#ifdef HAVE_LIBMSEED
33
#include <libmseed.h>
Matteo Quintiliani's avatar
Matteo Quintiliani committed
34
#endif
35

36 37 38 39
/*
For a portable version of timegm(), set the TZ environment variable  to
UTC, call mktime() and restore the value of TZ.  Something like
*/
40
#ifndef HAVE_TIMEGM
41 42 43

time_t my_timegm (struct tm *tm) {
    time_t ret;
44 45 46 47
    /*TODO stefano avoid static*/
    static char first_time = 1;
    char *tz;

48
#ifndef HAVE_SETENV
Matteo Quintiliani's avatar
Matteo Quintiliani committed
49
#ifndef HAVE_UNDERSCORE_TIMEZONE
50 51 52 53 54
#warning Computation of packet latencies could be wrong if local time is not equal to UTC.
    if(first_time) {
	    first_time = 0;
	    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY, "Computation of packet latencies could be wrong if local time is not equal to UTC.\n");
    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
55
#endif
56
#endif
57

58
    ret = mktime(tm);
59

60
#ifdef HAVE_SETENV
61 62 63
    if(first_time) {
	first_time = 0;
	tz = getenv("TZ");
64
	setenv("TZ", tz, 1);
65 66
	tzset();
    }
67
#endif
68

69
#ifdef HAVE_UNDERSCORE_TIMEZONE
70 71 72
    ret -= _timezone;
#endif

73 74 75 76 77 78
    return ret;
}

#endif


79
int nmxp_data_init(NMXP_DATA_PROCESS *pd) {
80
    pd->key = -1;
81
    pd->network[0] = 0;
82 83
    pd->station[0] = 0;
    pd->channel[0] = 0;
84 85
    pd->packet_type = -1;
    pd->x0 = -1;
86
    pd->xn = -1;
87
    pd->x0n_significant = 0;
88
    pd->oldest_seq_no = -1;
89 90 91 92 93 94 95 96 97
    pd->seq_no = -1;
    pd->time = -1.0;
    pd->pDataPtr = NULL;
    pd->nSamp = 0;
    pd->sampRate = -1;
    return 0;
}


98
int nmxp_data_unpack_bundle (int32_t *outdata, unsigned char *indata, int32_t *prev)
99
{         
100 101 102 103 104
	int32_t nsamples = 0;
	int32_t d4[4];
	int16_t d2[2];
	int32_t cb[4];  
	int32_t i, j, k=0;
105
	unsigned char cbits;
106
	/* TOREMOVE int my_order = get_my_wordorder(); */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
107
	int my_host_is_bigendian = nmxp_data_bigendianhost();
108 109 110 111 112 113 114 115 116 117 118 119

	cbits = (unsigned char)indata[0];
	if (cbits == 9) return (-1);
	++indata;

	/* Get the compression bits for the bundle. */
	for (i=0,j=6; j>=0; i++,j-=2) {
		cb[i] = (cbits>>j) & 3;
	}       

	for (j=0; j<4; j++) {
		/*
120
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "cb[%d]=%d\n", j, cb[j]);
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
		*/
		switch (cb[j]) 
		{   
			case 0:       /* not used     */
				k=0;
				break;       
			case 1:       /* 4 byte diffs */
				d4[0] = (signed char)indata[0];
				d4[1] = (signed char)indata[1];
				d4[2] = (signed char)indata[2];
				d4[3] = (signed char)indata[3];
				k=4;
				break;
			case 2:       /* 2 16-bit diffs */
				memcpy (&d2[0],indata,2);
				memcpy (&d2[1],indata+2,2);
137 138 139 140
				/* TOREMOVE if (my_order != SEED_LITTLE_ENDIAN) { */
				if (my_host_is_bigendian) {
					nmxp_data_swap_2b (&d2[0]);
					nmxp_data_swap_2b (&d2[1]);
141 142 143 144 145 146 147
				}
				d4[0] = d2[0];
				d4[1] = d2[1];
				k=2;
				break;
			case 3:       /* 1 32-bit diff */
				memcpy (&d4[0],indata,4);
148 149 150
				/* TOREMOVE if (my_order != SEED_LITTLE_ENDIAN) { */
				if (my_host_is_bigendian) {
					nmxp_data_swap_4b (&d4[0]);
151 152 153 154 155 156 157 158
				}
				k=1;
				break;
		}
		indata += 4;

		for (i=0; i<k; i++) {
			*outdata = *prev + d4[i];
159
			/* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "val = %d, diff[%d] = %d, *prev = %d\n",
160 161
				*outdata, i, d4[i], *prev);
				*/
162 163 164 165 166 167 168 169 170 171
			*prev = *outdata;

			outdata++;
			++nsamples;
		}
	}
	return (nsamples);
}


172
int nmxp_data_to_str(char *out_str, double time_d) {
173
    time_t time_t_start_time;
174
    struct tm tm_start_time;
175 176 177 178 179 180

    if(time_d > 0.0) {
	    time_t_start_time = (time_t) time_d;
    } else {
	    time_t_start_time = 0;
    }
181 182 183

    gmtime_r(&time_t_start_time, &tm_start_time);

184
    snprintf(out_str, NMXP_DATA_MAX_SIZE_DATE, "%04d.%03d,%02d:%02d:%02d.%04d",
185
	    tm_start_time.tm_year + 1900,
186
	    /*
187 188
	    tm_start_time.tm_mon + 1,
	    tm_start_time.tm_mday,
189
	    */
190 191 192 193
	    tm_start_time.tm_yday + 1,
	    tm_start_time.tm_hour,
	    tm_start_time.tm_min,
	    tm_start_time.tm_sec,
194
	    (time_t_start_time == 0)? 0 : (int) (  ((time_d - (double) time_t_start_time)) * 10000.0 )
195
	   );
196 197
    
    return 0;
198 199
}

200 201
int nmxp_data_year_from_epoch(double time_d) {
    time_t time_t_start_time;
202
    struct tm tm_start_time;
203 204 205 206 207 208

    if(time_d > 0.0) {
	    time_t_start_time = (time_t) time_d;
    } else {
	    time_t_start_time = 0;
    }
209 210 211
    /*Use reentrant to be trhead safe*/
    gmtime_r(&time_t_start_time,&tm_start_time);    
    return tm_start_time.tm_year + 1900;
212 213 214 215 216
}


int nmxp_data_yday_from_epoch(double time_d) {
    time_t time_t_start_time;
217
    struct tm tm_start_time;
218 219 220 221 222

    if(time_d > 0.0) {
	    time_t_start_time = (time_t) time_d;
    } else {
	    time_t_start_time = 0;
223 224 225 226
    } 
    /*Use reentrant to be trhead safe*/
    gmtime_r(&time_t_start_time,&tm_start_time);    
    return tm_start_time.tm_yday + 1;
227
}
228

229
int nmxp_data_trim(NMXP_DATA_PROCESS *pd, double trim_start_time, double trim_end_time, unsigned char exclude_bitmap) {
230 231 232 233
    int ret = 0;
    double first_time, last_time;
    int first_nsamples_to_remove = 0;
    int last_nsamples_to_remove = 0;
234 235
    int32_t new_nSamp = 0;
    int32_t i;
236 237 238


    if(pd) {
239
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmxp_data_trim(pd, %.4f, %.4f, %d)\n", trim_start_time, trim_end_time, exclude_bitmap);
240 241
	first_time = pd->time;
	last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
242 243 244 245
	if(first_time <= trim_start_time &&  trim_start_time <= last_time) {
	    first_nsamples_to_remove = (int) ( ((trim_start_time - first_time) * (double) pd->sampRate) + 0.5 );
	    if((exclude_bitmap & NMXP_DATA_TRIM_EXCLUDE_FIRST)) {
		first_nsamples_to_remove++;
246
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Excluded the first sample!\n");
247
	    }
248
	}
249 250 251 252
	if(first_time <= trim_end_time  &&  trim_end_time <= last_time) {
	    last_nsamples_to_remove = (int) ( ((last_time - trim_end_time) * (double) pd->sampRate) + 0.5 );
	    if((exclude_bitmap & NMXP_DATA_TRIM_EXCLUDE_LAST)) {
		last_nsamples_to_remove++;
253
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Excluded the last sample!\n");
254
	    }
255 256
	}

257 258 259 260 261 262
	if( (first_time < trim_start_time  &&  last_time < trim_start_time) ||
		(first_time > trim_end_time  &&  last_time > trim_end_time) ) {
	    first_nsamples_to_remove = pd->nSamp;
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Excluded all samples!\n");
	}

263
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "first_time=%.2f last_time=%.2f trim_start_time=%.2f trim_end_time=%.2f\n",
264
		first_time, last_time, trim_start_time, trim_end_time);
265
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "first_nsamples_to_remove=%d last_nsamples_to_remove=%d pd->nSamp=%d\n",
266 267 268 269 270 271 272 273 274 275
		first_nsamples_to_remove,
		last_nsamples_to_remove,
		pd->nSamp);

	if(first_nsamples_to_remove > 0 || last_nsamples_to_remove > 0) {

	    new_nSamp = pd->nSamp - (first_nsamples_to_remove + last_nsamples_to_remove);

	    if(new_nSamp > 0) {

276 277 278 279 280 281 282 283
		if(first_nsamples_to_remove > 0) {
		    pd->x0 = pd->pDataPtr[first_nsamples_to_remove];
		}

		if(last_nsamples_to_remove > 0) {
		    pd->xn = pd->pDataPtr[pd->nSamp - last_nsamples_to_remove];
		}

284
		for(i=0; i < pd->nSamp - first_nsamples_to_remove; i++) {
285 286 287 288 289 290 291 292 293 294
		    pd->pDataPtr[i] = pd->pDataPtr[first_nsamples_to_remove + i];
		}
		pd->nSamp = new_nSamp;
		pd->time += ((double) first_nsamples_to_remove / (double) pd->sampRate);

		ret = 1;


	    } else if(new_nSamp == 0) {
		if(pd->pDataPtr) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
295 296
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmxp_data_trim() nSamp = %d for %s.%s.%s.\n",
			    new_nSamp, NMXP_LOG_STR(pd->network), NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel));
297 298
		}
		pd->nSamp = 0;
299 300
		pd->x0 = -1;
		pd->xn = -1;
301 302
		ret = 1;
	    } else {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
303 304
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Error in nmxp_data_trim() nSamp = %d for %s.%s.%s.\n",
			    new_nSamp, NMXP_LOG_STR(pd->network), NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel));
305 306 307 308 309 310
	    }

	} else {
	    ret = 2;
	}
    } else {
311
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "nmxp_data_trim() is called with pd = NULL\n");
312 313 314
    }

    if(ret == 1) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
315 316
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmxp_data_trim() trimmed data! (Output %d samples for %s.%s.%s)\n",
		pd->nSamp, NMXP_LOG_STR(pd->network), NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel));
317 318
    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
319 320
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmxp_data_trim() %s.%s.%s exit ret=%d\n",
	    NMXP_LOG_STR(pd->network), NMXP_LOG_STR(pd->station), NMXP_LOG_STR(pd->channel), ret);
321 322 323 324

    return ret;
}

325
time_t nmxp_data_gmtime_now() {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
326 327
    time_t time_now;
    time(&time_now);
328 329 330 331 332 333
    return time_now;
}

double nmxp_data_latency(NMXP_DATA_PROCESS *pd) {
    double latency = 0.0;
    time_t time_now = nmxp_data_gmtime_now();
334 335 336 337 338 339 340 341 342
    
    if(pd) {
	latency = ((double) time_now) - (pd->time + ((double) pd->nSamp / (double) pd->sampRate));
    }

    return latency;
}


343
int nmxp_data_log(NMXP_DATA_PROCESS *pd, int flag_sample) {
344

345
    char str_start[NMXP_DATA_MAX_SIZE_DATE], str_end[NMXP_DATA_MAX_SIZE_DATE];
346
    int i;
347 348 349

    str_start[0] = 0;
    str_end[0] = 0;
350
    
351 352 353 354
    if(pd) {
	nmxp_data_to_str(str_start, pd->time);
	nmxp_data_to_str(str_end, pd->time + ((double) pd->nSamp / (double) pd->sampRate));

355 356
	/* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "%12d %5s.%3s rate=%03d (%s - %s) [%d, %d] pts=%04d (%d, %d, %d, %d) lat=%.1f len=%d\n", */
	/* printf("%10d %5s.%3s 03dHz (%s - %s) lat=%.1fs [%d, %d] pts=%04d (%d, %d, %d, %d) len=%d\n", */
357
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "%s.%s.%3s %3dHz (%s - %s) lat %.1fs [%d, %d] (%d) %4dpts (%d, %d, %d, %d, %d)\n",
358
		/* pd->key, */
359 360 361
		NMXP_LOG_STR(pd->network),
		(strlen(pd->station) == 0)? "XXXX" : NMXP_LOG_STR(pd->station),
		(strlen(pd->channel) == 0)? "XXX" : NMXP_LOG_STR(pd->channel),
362
		pd->sampRate,
363 364
		NMXP_LOG_STR(str_start),
		NMXP_LOG_STR(str_end),
365
		nmxp_data_latency(pd),
366 367 368 369 370 371 372 373
		pd->packet_type,
		pd->seq_no,
		pd->oldest_seq_no,
		pd->nSamp,
		pd->x0,
		(pd->pDataPtr == NULL)? 0 : pd->pDataPtr[0],
		(pd->pDataPtr == NULL || pd->nSamp < 1)? 0 : pd->pDataPtr[pd->nSamp-1],
		pd->xn,
374
		pd->x0n_significant
375
	      );
376 377

	if(pd->pDataPtr  &&  flag_sample != 0  &&  pd->nSamp > 0) {
378
	    for(i=0; i < pd->nSamp; i++) {
379
		nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "%6d ", pd->pDataPtr[i]);
380
		if((i + 1) % 20 == 0) {
381
		    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\n");
382 383
		}
	    }
384
	    nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "\n");
385
	}
386

387
    } else {
388
	nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_PACKETMAN, "Pointer to NMXP_DATA_PROCESS is NULL!\n");
389 390 391
    }

    return 0;
392 393
}

394

395
int nmxp_data_parse_date(const char *pstr_date, NMXP_TM_T *ret_tmt) {
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
/* Input formats: 
 *     <date>,<time> | <date>
 *
 * where:
 *     <date> = yyyy/mm/dd | yyy.jjj
 *     <time> = hh:mm:ss | hh:mm
 *
 *     yyyy = year
 *     mm   = month       (1-12)
 *     dd   = day         (1-31)
 *     jjj  = day-of-year (1-365)
 *     hh   = hour        (0-23)
 *     mm   = minute      (0-59)
 *     ss   = second      (0-59)
 */

    int ret = 0;

414 415 416
    char str_tt[20];
    int k;

417 418 419 420 421 422 423
#define MAX_LENGTH_STR_MESSAGE 30
    char str_date[MAX_LENGTH_STR_MESSAGE] = "NO DATE";

#define MAX_LENGTH_ERR_MESSAGE 500
    char err_message[MAX_LENGTH_ERR_MESSAGE] = "NO MESSAGE";

    char *pEnd = NULL;
424
    int32_t app;
425 426 427
    int state;
    int flag_finished = 0;

428
    time_t time_now;
429
    struct tm tm_now;
430 431

    int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Matteo Quintiliani's avatar
Matteo Quintiliani committed
432
    int m, d, day_sum, jday;
433 434


435
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "Date to validate '%s'\n", NMXP_LOG_STR(pstr_date));
436 437 438 439 440 441
	
    strncpy(str_date, pstr_date, MAX_LENGTH_STR_MESSAGE);
    pEnd = str_date;
    app = strtol(str_date, &pEnd, 10);
    state = 0;
    if(  errno == EINVAL ||  errno == ERANGE ) {
442
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_DATE, "%s\n", NMXP_LOG_STR(strerror(errno)));
443 444 445 446 447 448 449 450 451 452
	ret = -1;
    }

    if(pEnd[0] != 0  &&  ret != -1) {
	ret = 0;
    } else {
	strncpy(err_message, "Error parsing year!", MAX_LENGTH_ERR_MESSAGE);
	ret = -1;
    }

453
    /* initialize ret_tmt */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
454
    time(&time_now);
455
    gmtime_r(&time_now,&tm_now);
456

457 458 459
    ret_tmt->t.tm_sec = 0 ;
    ret_tmt->t.tm_min = 0;
    ret_tmt->t.tm_hour = 0;
460 461 462 463 464 465
    ret_tmt->t.tm_mday = tm_now.tm_mday;
    ret_tmt->t.tm_mon = tm_now.tm_mon;
    ret_tmt->t.tm_year = tm_now.tm_year;
    ret_tmt->t.tm_wday = tm_now.tm_wday;
    ret_tmt->t.tm_yday = tm_now.tm_yday;
    ret_tmt->t.tm_isdst = tm_now.tm_isdst;
466
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
467
    ret_tmt->t.tm_gmtoff = tm_now.tm_gmtoff;
468
#endif
469
    ret_tmt->d = 0;
470 471 472 473 474 475 476 477 478 479

    
    /* loop for parsing by a finite state machine */
    while( 
	    !flag_finished
	    && ret == 0
	    &&  errno != EINVAL
	    &&  errno != ERANGE
	    ) {

480 481
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "state=%d value=%d flag_finished=%d ret=%d pEnd[0]=%c [%d]  (%s)\n",
	    state, app, flag_finished, ret, (pEnd[0]==0)? '_' : pEnd[0], pEnd[0], NMXP_LOG_STR(pEnd));
482 483 484 485

	/* switch on state */
	switch(state) {
	    case 0: /* Parse year */
486
		ret_tmt->t.tm_year = app - 1900;
487 488 489 490 491 492 493 494 495 496 497
		if(pEnd[0] == '/') {
		    state = 1; /* Month */
		} else if(pEnd[0] == '.') {
		    state = 3; /* Julian Day */
		} else {
		    strncpy(err_message, "Wrong separator after year!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

	    case 1: /* Parse month */
498
		ret_tmt->t.tm_mon = app - 1;
499 500 501 502 503 504 505 506 507
		if(pEnd[0] == '/')
		    state = 2; /* Day of month */
		else {
		    strncpy(err_message, "Wrong separator after month!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

	    case 2: /* Parse day of month */
508
		ret_tmt->t.tm_mday = app;
509 510 511 512 513 514 515 516 517 518 519
		if(pEnd[0] == 0) {
		    flag_finished = 1;
		} else if(pEnd[0] == ',') {
		    state = 4; /* Hour */
		} else {
			strncpy(err_message, "Wrong separator after day of month!", MAX_LENGTH_ERR_MESSAGE);
			ret = -1;
		    }
		break;

	    case 3: /* Parse Julian Day */
520
		ret_tmt->t.tm_yday = app - 1;
521

Matteo Quintiliani's avatar
Matteo Quintiliani committed
522 523
		jday=app;

524
		if(NMXP_DATA_IS_LEAP(ret_tmt->t.tm_year)) {
525 526 527 528 529 530 531 532 533 534
		    month_days[1]++;
		}

		m=0;
		day_sum = 0;
		while(month_days[m] < (jday - day_sum)) {
		    day_sum += month_days[m++];
		}
		d = jday-day_sum;

535 536
		ret_tmt->t.tm_mon = m;
		ret_tmt->t.tm_mday = d;
537

538
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "Month %d Day %d\n", m, d);
539 540 541 542 543 544 545 546 547 548 549 550

		if(pEnd[0] == 0) {
		    flag_finished = 1;
		} else if(pEnd[0] == ',') {
		    state = 4; /* Hour */
		} else {
		    strncpy(err_message, "Wrong separator after julian day!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

	    case 4: /* Parse hour */
551
		ret_tmt->t.tm_hour = app;
552 553 554 555 556 557 558 559 560
		if(pEnd[0] == ':') {
		    state = 5; /* Minute */
		} else {
		    strncpy(err_message, "Wrong separator after hour!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

	    case 5: /* Parse minute */
561
		ret_tmt->t.tm_min = app;
562 563 564 565 566 567 568 569 570 571 572
		if(pEnd[0] == 0) {
		    flag_finished = 1;
		} else if(pEnd[0] == ':') {
		    state = 6; /* Second */
		} else {
		    strncpy(err_message, "Wrong separator after minute!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

	    case 6: /* Parse second */
573
		ret_tmt->t.tm_sec = app;
574 575
		if(pEnd[0] == 0) {
		    flag_finished = 1;
576 577
		} else if(pEnd[0] == '.') {
		    state = 7; /* ten thousandth of second */
578 579 580 581 582 583
		} else {
		    strncpy(err_message, "Error parsing after second!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

584 585 586 587 588 589 590 591 592 593
	    case 7: /* Parse ten thousandth of second */
		ret_tmt->d = app;
		if(pEnd[0] == 0) {
		    flag_finished = 1;
		} else {
		    strncpy(err_message, "Error parsing after ten thousandth of second!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

594 595 596 597 598 599 600
	    default : /* NOT DEFINED */
		snprintf(err_message, MAX_LENGTH_ERR_MESSAGE, "State %d not defined!", state);
		ret = -1;
		break;
	}
	if(pEnd[0] != 0  && !flag_finished  &&  ret == 0) {
	    pEnd[0] = ' '; /* overwrite separator with space */
601
	    if(state == 7) {
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
		pEnd++;
		str_tt[0] = '1';
		str_tt[1] = 0;
		if(pEnd[0] == 0 || strlen(pEnd) > 4) {
		    strncpy(err_message, "Error parsing ten thousandth of second!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		} else {
		    strncat(str_tt, pEnd, 20);
		    k=0;
		    while(k<5) {
			if(str_tt[k] == 0) {
			    str_tt[k] = '0';
			}
			k++;
		    }
617 618
		    str_tt[k] = 0;
		    pEnd = str_tt;
619 620
		}
	    }
621 622 623 624
	    app = strtol(pEnd, &pEnd, 10);
	    if(state == 7) {
		    app -= 10000;
	    }
625
	    if(  errno == EINVAL ||  errno == ERANGE ) {
626
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_DATE, "%s\n", NMXP_LOG_STR(strerror(errno)));
627 628 629 630 631
		ret = -1;
	    }
	}
    }

632 633
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "FINAL: state=%d value=%d flag_finished=%d ret=%d pEnd[0]=%c [%d]  (%s)\n",
	    state, app, flag_finished, ret, (pEnd[0]==0)? '_' : pEnd[0], pEnd[0], NMXP_LOG_STR(pEnd));
634 635 636 637 638 639 640

    if(!flag_finished && (ret == 0)) {
	strncpy(err_message, "Date incomplete!", MAX_LENGTH_ERR_MESSAGE);
	ret = -1;
    }

    if(ret == -1) {
641 642
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_DATE, "in date '%s' %s\n",
		NMXP_LOG_STR(pstr_date), NMXP_LOG_STR(err_message));
643
    } else {
644
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "Date '%s' has been validate! %04d/%02d/%02d %02d:%02d:%02d.%04d\n",
645
		NMXP_LOG_STR(pstr_date),
646 647 648 649 650 651 652
		ret_tmt->t.tm_year,
		ret_tmt->t.tm_mon,
		ret_tmt->t.tm_mday,
		ret_tmt->t.tm_hour,
		ret_tmt->t.tm_min,
		ret_tmt->t.tm_sec,
		ret_tmt->d
653 654 655 656 657 658
		);
    }

    return ret;
}

659

660 661
double nmxp_data_tm_to_time(NMXP_TM_T *tmt) {
    double ret_d = 0.0;
662
    
663
#ifdef HAVE_TIMEGM
664
    ret_d = timegm(&(tmt->t));
665
#else
666
    ret_d = my_timegm(&(tmt->t));
667
#endif
668

669 670 671
    ret_d += ((double) tmt->d / 10000.0 );

    return ret_d;
672
}
673

674 675 676 677 678 679

#ifdef HAVE_GETCWD
/* TODO */
#endif

char *nmxp_data_gnu_getcwd () {
680
    size_t size = NMXP_DATA_MAX_SIZE_FILENAME;
681 682
    while (1)
    {
683
	char *buffer = (char *) NMXP_MEM_MALLOC(size);
684 685
	if (getcwd (buffer, size) == buffer)
	    return buffer;
686
	NMXP_MEM_FREE (buffer);
687 688 689 690
	if (errno != ERANGE)
	    return NULL;
	size *= 2;
    }
691 692
}

693

694 695 696 697 698 699 700 701 702 703 704 705 706
int nmxp_data_dir_exists (char *dirname) {
    int ret = 0;
    char *cur_dir = NULL;

    if(dirname) {
	cur_dir = nmxp_data_gnu_getcwd();
	if(chdir(dirname) == -1) {
	    /* ERROR */
	} else {
	    ret = 1;
	}
	if(cur_dir) {
	    chdir(cur_dir);
707
	    NMXP_MEM_FREE(cur_dir);
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
	}
    }

    return ret;
}


char *nmxp_data_dir_abspath (char *dirname) {
    char *ret = NULL;
    char *cur_dir = NULL;

    if(dirname) {
	cur_dir = nmxp_data_gnu_getcwd();
	if(chdir(dirname) == -1) {
	    /* ERROR */
	} else {
	    ret = nmxp_data_gnu_getcwd();
	}
	if(cur_dir) {
	    chdir(cur_dir);
728
	    NMXP_MEM_FREE(cur_dir);
729 730 731 732 733 734
	}
    }

    return ret;
}

735 736 737 738 739 740 741 742 743 744
#ifdef HAVE_MKDIR
/* TODO */
#endif

#ifdef HAVE_WINDOWS_H
const char nmxp_data_sepdir = '\\';
#else
const char nmxp_data_sepdir = '/';
#endif

745 746 747

int nmxp_data_mkdir(const char *dirname) {
    int ret = 0;
748 749 750
#ifndef HAVE_WINDOWS_H
    mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
#endif
751 752 753 754 755 756 757 758 759 760 761 762
#ifndef HAVE_WINDOWS_H
    ret=mkdir(dirname, mode);
#else
    ret=mkdir(dirname);
#endif
    return ret;
}


int nmxp_data_mkdirp(const char *filename) {
    char *cur_dir = NULL;
    char *dir = NULL;
763 764 765
    int i, l;
    int	error=0;

766 767
    if(!filename)
	return -1;
768
    dir = NMXP_MEM_STRDUP(filename);
769 770 771 772
    if(!dir)
	return -1;

    cur_dir = nmxp_data_gnu_getcwd();
773 774 775 776 777 778 779 780

    l = strlen(dir);
    i = 0;
    while(i < l  &&  error != -1) {
	if(dir[i] == nmxp_data_sepdir  &&  i > 0) {
	    dir[i] = 0;
	    /* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "trying to create %s...\n", dir); */
	    if(chdir(dir) == -1) {
781
		error=nmxp_data_mkdir(dir);
782 783 784 785 786 787
	    }
	    dir[i] = nmxp_data_sepdir;
	}
	i++;
    }
    if(error != -1) {
788
	error=nmxp_data_mkdir(dir);
789 790
    }

791
    NMXP_MEM_FREE(dir);
792 793 794

    if(cur_dir) {
	chdir(cur_dir);
795
	NMXP_MEM_FREE(cur_dir);
796
    }
797 798 799 800
    return error;
}


Matteo Quintiliani's avatar
Matteo Quintiliani committed
801 802
#ifdef HAVE_LIBMSEED

803 804
int nmxp_data_seed_init(NMXP_DATA_SEED *data_seed, char *outdirseed, char *default_network, NMXP_DATA_SEED_TYPEWRITE type_writeseed) {
    int i;
805
    char *dirname = NULL;
806 807

    if(outdirseed) {
808 809
	dirname = nmxp_data_dir_abspath(outdirseed);
	strncpy(data_seed->outdirseed, dirname, NMXP_DATA_MAX_SIZE_FILENAME);
810
    } else {
811 812 813 814
	dirname = nmxp_data_gnu_getcwd();
	strncpy(data_seed->outdirseed, dirname, NMXP_DATA_MAX_SIZE_FILENAME);
    }
    if(dirname) {
815
	NMXP_MEM_FREE(dirname);
816
	dirname = NULL;
817 818 819 820 821 822 823
    }
    strncpy(data_seed->default_network, default_network, 5);
    data_seed->type_writeseed = type_writeseed;

    data_seed->n_open_files = 0;
    data_seed->last_open_file = -1;
    data_seed->cur_open_file = -1;
824
    data_seed->err_general = 0;
825
    for(i=0; i < NMXP_DATA_MAX_NUM_OPENED_FILE; i++) {
826
	data_seed->err_outfile_mseed[i] = 0;
827 828 829 830 831 832 833 834
	data_seed->outfile_mseed[i] = NULL;
	data_seed->filename_mseed[i][0] = 0;
    }
    data_seed->pd = NULL;

    return 0;
}

835 836

int nmxp_data_seed_fopen(NMXP_DATA_SEED *data_seed) {
837 838
    int i;
    int found;
839
    int err = 0;
840 841 842 843 844
    char dirseedchan[NMXP_DATA_MAX_SIZE_FILENAME];
    char filename_mseed[NMXP_DATA_MAX_SIZE_FILENAME];
    char filename_mseed_fullpath[NMXP_DATA_MAX_SIZE_FILENAME];

    nmxp_data_get_filename_ms(data_seed, dirseedchan, filename_mseed);
845

846
    if(filename_mseed) {
847 848 849
	found=0;
	i=0;
	while(i < data_seed->n_open_files  &&  !found) {
850
	    if( strcmp(filename_mseed, data_seed->filename_mseed[i]) == 0) {
851 852 853 854 855 856 857 858 859 860 861 862
		found = 1;
	    } else {
		i++;
	    }
	}

	if(found) {
	    data_seed->cur_open_file = i;
	    /* nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Curr  [%3d/%3d] %s\n", data_seed->cur_open_file, data_seed->n_open_files,
		    data_seed->filename_mseed[data_seed->cur_open_file]); */
	} else {

863 864 865 866
	    if(!nmxp_data_dir_exists(dirseedchan)) {
		/* nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Directory %s does not exist!\n", dirseedchan); */
		if(nmxp_data_mkdirp(dirseedchan) == -1) {
		    err++;
867
		    data_seed->err_general++;
868 869 870 871 872
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Directory %s has not been created!\n", dirseedchan);
		} else {
		    /* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Directory %s created!\n", dirseedchan); */
		    if(!nmxp_data_dir_exists(dirseedchan)) {
			err++;
873
			data_seed->err_general++;
874 875 876 877 878
			nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Directory %s should be created but it does not exist!\n", dirseedchan);
		    }
		}
	    } else {
		/* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_ANY, "Directory %s exists!\n", dirseedchan); */
879 880
	    }

881
	    if(err==0) {
882 883 884 885 886
		int app;
		/* data_seed->last_open_file = (data_seed->last_open_file + 1) % NMXP_DATA_MAX_NUM_OPENED_FILE; */
		app = (data_seed->last_open_file + 1) % NMXP_DATA_MAX_NUM_OPENED_FILE;
		nmxp_data_seed_fclose(data_seed, app);
		strncpy(data_seed->filename_mseed[app], filename_mseed, NMXP_DATA_MAX_SIZE_FILENAME);
887 888
		snprintf(filename_mseed_fullpath, NMXP_DATA_MAX_SIZE_FILENAME, "%s%c%s",
			dirseedchan, nmxp_data_sepdir,
889
			data_seed->filename_mseed[app]);
890

891 892 893 894 895 896 897 898 899 900
		data_seed->outfile_mseed[app] = fopen(filename_mseed_fullpath, "a+");

		if(data_seed->outfile_mseed[app] == NULL) {
		    err++;
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Error opening file %s\n", filename_mseed_fullpath);
		} else {

		    if(data_seed->n_open_files < NMXP_DATA_MAX_NUM_OPENED_FILE) {
			data_seed->n_open_files++;
		    }
901

902 903 904
		    data_seed->last_open_file = app;
		    data_seed->cur_open_file = data_seed->last_open_file;
		}
905
	    }
906 907

	    /* nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Open  [%3d/%3d] %s\n", data_seed->cur_open_file, data_seed->n_open_files,
908
	       data_seed->filename_mseed[data_seed->cur_open_file]); */
909 910 911 912
	}

    }

913
    return err;
914 915
}

916

917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
int nmxp_data_seed_fclose(NMXP_DATA_SEED *data_seed, int i) {

    if(i >= 0  &&  i < NMXP_DATA_MAX_NUM_OPENED_FILE) {
	if(data_seed->outfile_mseed[i]) {
	    /* nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Close [%3d/%3d] %s\n", i, data_seed->n_open_files, data_seed->filename_mseed[i]); */
	    fclose(data_seed->outfile_mseed[i]);
	    data_seed->outfile_mseed[i] = NULL;
	    data_seed->filename_mseed[i][0] = 0;
	}
    }

    return 0;
}

int nmxp_data_seed_fclose_all(NMXP_DATA_SEED *data_seed) {
    int i;
    for(i=0; i < NMXP_DATA_MAX_NUM_OPENED_FILE; i++) {
	nmxp_data_seed_fclose(data_seed, i);
    }
    data_seed->n_open_files = 0;
    data_seed->last_open_file = -1;
    data_seed->cur_open_file = -1;
    return 0;
}

#define NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK ( ( (data_seed->pd) && (data_seed->pd->network[0] != 0) )? data_seed->pd->network : data_seed->default_network )
int nmxp_data_get_filename_ms(NMXP_DATA_SEED *data_seed, char *dirseedchan, char *filenameseed) {
    int ret = 0;
    
    dirseedchan[0] = 0;
    filenameseed[0] = 0;
    if(data_seed->type_writeseed == NMXP_TYPE_WRITESEED_SDS) {
	snprintf(dirseedchan, NMXP_DATA_MAX_SIZE_FILENAME, "%s%c%d%c%s%c%s%c%s.D", data_seed->outdirseed, nmxp_data_sepdir,
		nmxp_data_year_from_epoch(data_seed->pd->time),
		nmxp_data_sepdir,
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
		nmxp_data_sepdir,
		data_seed->pd->station,
		nmxp_data_sepdir,
		data_seed->pd->channel);
	snprintf(filenameseed, NMXP_DATA_MAX_SIZE_FILENAME, "%s.%s..%s.D.%d.%03d",
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
		data_seed->pd->station,
		data_seed->pd->channel,
		nmxp_data_year_from_epoch(data_seed->pd->time),
		nmxp_data_yday_from_epoch(data_seed->pd->time));
    } else if(data_seed->type_writeseed == NMXP_TYPE_WRITESEED_BUD) {
	snprintf(dirseedchan, NMXP_DATA_MAX_SIZE_FILENAME, "%s%c%s%c%s", data_seed->outdirseed,
		nmxp_data_sepdir,
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
		nmxp_data_sepdir,
		data_seed->pd->station);
	snprintf(filenameseed, NMXP_DATA_MAX_SIZE_FILENAME, "%s.%s..%s.%d.%03d",
		data_seed->pd->station,
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
		data_seed->pd->channel,
		nmxp_data_year_from_epoch(data_seed->pd->time),
		nmxp_data_yday_from_epoch(data_seed->pd->time));
    }

    return ret;
}


981
/* Private function for writing mini-seed records */
982 983 984 985 986 987 988 989 990 991 992
static void nmxp_data_msr_write_handler (char *record, int reclen, void *pdata_seed) {
    int err = 0;
    NMXP_DATA_SEED *data_seed = pdata_seed;

    if(data_seed->pd == NULL) {
	err++;
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "pd is NULL in nmxp_data_msr_write_handler()!\n");
    }

    if(err==0) {

993 994 995 996 997 998 999 1000
	err = nmxp_data_seed_fopen(data_seed);

	if(err==0) {
	    if( data_seed->outfile_mseed[data_seed->cur_open_file] ) {
		if ( fwrite(record, reclen, 1, data_seed->outfile_mseed[data_seed->cur_open_file]) != 1 ) {
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN,
			    "Error writing %s to output file\n", data_seed->filename_mseed[data_seed->cur_open_file]);
		}
1001
	    }
1002 1003
	}
    }
1004
}
1005

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1006

1007
int nmxp_data_msr_pack(NMXP_DATA_PROCESS *pd, NMXP_DATA_SEED *data_seed, void *pmsr) {
1008 1009
    int ret =0;

1010
    MSRecord *msr = pmsr;
1011 1012
    int psamples;
    int precords;
1013
    flag verbose = 0;
1014

1015
    int *pDataDest = NULL;
1016

1017
    if(pd) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1018
    if(pd->nSamp > 0) {
1019

1020
	/* Populate MSRecord values */
1021

1022 1023
	/* TODO */
	/* msr->starttime = ms_seedtimestr2hptime ("2004,350,00:00:00.00"); */
1024 1025
	msr->starttime = MS_EPOCH2HPTIME(pd->time);
	msr->samprate = pd->sampRate;
1026

1027
	/* msr->byteorder = 0; */         /* big endian byte order */
1028
	msr->byteorder = nmxp_data_bigendianhost ();
1029

1030
	msr->sequence_number = pd->seq_no % 1000000;
1031

1032
	msr->sampletype = 'i';      /* declare type to be 32-bit integers */
1033

1034
	msr->numsamples = pd->nSamp;
1035
	msr->datasamples = NMXP_MEM_MALLOC (sizeof(int) * (msr->numsamples)); 
1036 1037
	memcpy(msr->datasamples, pd->pDataPtr, sizeof(int) * pd->nSamp); /* pointer to 32-bit integer data samples */

1038
	pDataDest = msr->datasamples;
1039

1040
	/* msr_print(msr, 2); */
1041

1042 1043
	data_seed->pd = pd;

1044
	/* Pack the record(s) */
1045 1046 1047
	precords = msr_pack (msr, &nmxp_data_msr_write_handler, data_seed, &psamples, 1, verbose);

	data_seed->pd = NULL;
1048

1049
	if ( precords == -1 ) {
1050 1051
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN,
		    "Cannot pack records %s.%s.%s\n", pd->network, pd->station, pd->channel);
1052
	} else {
1053 1054 1055
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN,
		    "Packed %d samples into %d records for %s.%s.%s x0=%d xn=%d\n",
		    psamples, precords, pd->network, pd->station, pd->channel, pDataDest[0], pDataDest[msr->numsamples-1]);
1056
	}
1057 1058

    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
1059
    }
1060 1061 1062

    return ret;
}
1063

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1064 1065
#endif

1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097


void nmxp_data_swap_2b (int16_t *in) {
    unsigned char *p = (unsigned char *)in;
    unsigned char tmp;
    tmp = *p;
    *p = *(p+1);    
    *(p+1) = tmp;
}   


void nmxp_data_swap_3b (unsigned char *in) {
    unsigned char *p = (unsigned char *)in;
    unsigned char tmp;
    tmp = *p;
    *p = *(p+2);    
    *(p+2) = tmp;
}   


void nmxp_data_swap_4b (int32_t *in) {
    unsigned char *p = (unsigned char *)in;
    unsigned char tmp;
    tmp = *p;
    *p = *(p+3);
    *(p+3) = tmp;
    tmp = *(p+1);
    *(p+1) = *(p+2);
    *(p+2) = tmp;
}


1098
void nmxp_data_swap_8b (double *in) {
1099 1100
    unsigned char *p = (unsigned char *)in;
    unsigned char tmp;
1101 1102 1103 1104
    if(sizeof(double) != 8) {
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY,
		"nmxp_data_swap_8b() argument is not 8 bytes length!\n");
    }
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
    tmp = *p;
    *p = *(p+7);
    *(p+7) = tmp;
    tmp = *(p+1);
    *(p+1) = *(p+6);
    *(p+6) = tmp;
    tmp = *(p+2);
    *(p+2) = *(p+5);
    *(p+5) = tmp;
    tmp = *(p+3);
    *(p+3) = *(p+4);
    *(p+4) = tmp;
}

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1119 1120 1121 1122 1123

int nmxp_data_bigendianhost () {
    int16_t host = 1;
    return !(*((int8_t *)(&host)));
}