nmxp_data.c 32.9 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.77 2010-09-02 10:02:12 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
#include <unistd.h>
24
#include <math.h>
25 26 27 28 29

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

30

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

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

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

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

49
#ifndef HAVE_SETENV
Matteo Quintiliani's avatar
Matteo Quintiliani committed
50
#ifndef HAVE_UNDERSCORE_TIMEZONE
51 52 53 54 55
#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
56
#endif
57
#endif
58

59
    ret = mktime(tm);
60

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

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

74 75 76 77 78 79
    return ret;
}

#endif


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


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

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

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

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


175
int nmxp_data_to_str(char *out_str, double time_d) {
176
    time_t time_t_start_time;
177
    struct tm tm_start_time;
178 179 180 181 182 183

    if(time_d > 0.0) {
	    time_t_start_time = (time_t) time_d;
    } else {
	    time_t_start_time = 0;
    }
184 185 186

    gmtime_r(&time_t_start_time, &tm_start_time);

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

203 204
int nmxp_data_year_from_epoch(double time_d) {
    time_t time_t_start_time;
205
    struct tm tm_start_time;
206 207 208 209 210 211

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


int nmxp_data_yday_from_epoch(double time_d) {
    time_t time_t_start_time;
220
    struct tm tm_start_time;
221 222 223 224 225

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

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


    if(pd) {
242
	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);
243 244
	first_time = pd->time;
	last_time = pd->time + ((double) pd->nSamp / (double) pd->sampRate);
245 246 247 248
	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++;
249
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Excluded the first sample!\n");
250
	    }
251
	}
252 253 254 255
	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++;
256
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Excluded the last sample!\n");
257
	    }
258 259
	}

260 261 262 263 264 265
	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");
	}

266
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "first_time=%.2f last_time=%.2f trim_start_time=%.2f trim_end_time=%.2f\n",
267
		first_time, last_time, trim_start_time, trim_end_time);
268
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "first_nsamples_to_remove=%d last_nsamples_to_remove=%d pd->nSamp=%d\n",
269 270 271 272 273 274 275 276 277 278
		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) {

279 280 281 282 283 284 285 286
		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];
		}

287
		for(i=0; i < pd->nSamp - first_nsamples_to_remove; i++) {
288 289 290 291 292 293 294 295 296 297
		    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
298 299
		    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));
300 301
		}
		pd->nSamp = 0;
302 303
		pd->x0 = -1;
		pd->xn = -1;
304 305
		ret = 1;
	    } else {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
306 307
		    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));
308 309 310 311 312 313
	    }

	} else {
	    ret = 2;
	}
    } else {
314
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "nmxp_data_trim() is called with pd = NULL\n");
315 316 317
    }

    if(ret == 1) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
318 319
	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));
320 321
    }

Matteo Quintiliani's avatar
Matteo Quintiliani committed
322 323
    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);
324 325 326 327

    return ret;
}

328
time_t nmxp_data_gmtime_now() {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
329 330
    time_t time_now;
    time(&time_now);
331 332 333 334 335 336
    return time_now;
}

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

    return latency;
}


346
int nmxp_data_log(NMXP_DATA_PROCESS *pd, int flag_sample) {
347

348
    char str_start[NMXP_DATA_MAX_SIZE_DATE], str_end[NMXP_DATA_MAX_SIZE_DATE];
349
    int i;
350 351 352

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

358 359
	/* 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", */
360
	nmxp_log(NMXP_LOG_NORM_NO, NMXP_LOG_D_ANY, "%s.%s.%3s.%2s %3dHz (%s - %s) lat %.1fs [%d, %d] (%d) %4dpts (%d, %d, %d, %d, %d)\n",
361
		/* pd->key, */
362 363 364
		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),
365
		(strlen(pd->location) == 0)? "XX" : NMXP_LOG_STR(pd->location),
366
		pd->sampRate,
367 368
		NMXP_LOG_STR(str_start),
		NMXP_LOG_STR(str_end),
369
		nmxp_data_latency(pd),
370 371 372 373 374 375 376 377
		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,
378
		pd->x0n_significant
379
	      );
380 381

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

391
    } else {
392
	nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_PACKETMAN, "Pointer to NMXP_DATA_PROCESS is NULL!\n");
393 394 395
    }

    return 0;
396 397
}

398

399
int nmxp_data_parse_date(const char *pstr_date, NMXP_TM_T *ret_tmt) {
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
/* 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;

418 419 420
    char str_tt[20];
    int k;

421 422 423 424 425 426 427
#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;
428
    int32_t app;
429 430 431
    int state;
    int flag_finished = 0;

432
    time_t time_now;
433
    struct tm tm_now;
434 435

    int month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Matteo Quintiliani's avatar
Matteo Quintiliani committed
436
    int m, d, day_sum, jday;
437 438


439
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "Date to validate '%s'\n", NMXP_LOG_STR(pstr_date));
440 441 442 443 444 445
	
    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 ) {
446
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_DATE, "%s\n", NMXP_LOG_STR(strerror(errno)));
447 448 449 450 451 452 453 454 455 456
	ret = -1;
    }

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

457
    /* initialize ret_tmt */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
458
    time(&time_now);
459
    gmtime_r(&time_now,&tm_now);
460

461 462 463
    ret_tmt->t.tm_sec = 0 ;
    ret_tmt->t.tm_min = 0;
    ret_tmt->t.tm_hour = 0;
464 465 466 467 468 469
    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;
470
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
471
    ret_tmt->t.tm_gmtoff = tm_now.tm_gmtoff;
472
#endif
473
    ret_tmt->d = 0;
474 475 476 477 478 479 480 481 482 483

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

484 485
    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));
486 487 488 489

	/* switch on state */
	switch(state) {
	    case 0: /* Parse year */
490
		ret_tmt->t.tm_year = app - 1900;
491 492 493 494 495 496 497 498 499 500 501
		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 */
502
		ret_tmt->t.tm_mon = app - 1;
503 504 505 506 507 508 509 510 511
		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 */
512
		ret_tmt->t.tm_mday = app;
513 514 515 516 517 518 519 520 521 522 523
		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 */
524
		ret_tmt->t.tm_yday = app - 1;
525

Matteo Quintiliani's avatar
Matteo Quintiliani committed
526 527
		jday=app;

528
		if(NMXP_DATA_IS_LEAP(ret_tmt->t.tm_year)) {
529 530 531 532 533 534 535 536 537 538
		    month_days[1]++;
		}

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

539 540
		ret_tmt->t.tm_mon = m;
		ret_tmt->t.tm_mday = d;
541

542
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "Month %d Day %d\n", m, d);
543 544 545 546 547 548 549 550 551 552 553 554

		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 */
555
		ret_tmt->t.tm_hour = app;
556 557 558 559 560 561 562 563 564
		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 */
565
		ret_tmt->t.tm_min = app;
566 567 568 569 570 571 572 573 574 575 576
		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 */
577
		ret_tmt->t.tm_sec = app;
578 579
		if(pEnd[0] == 0) {
		    flag_finished = 1;
580 581
		} else if(pEnd[0] == '.') {
		    state = 7; /* ten thousandth of second */
582 583 584 585 586 587
		} else {
		    strncpy(err_message, "Error parsing after second!", MAX_LENGTH_ERR_MESSAGE);
		    ret = -1;
		}
		break;

588 589 590 591 592 593 594 595 596 597
	    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;

598 599 600 601 602 603 604
	    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 */
605
	    if(state == 7) {
606 607 608 609 610 611 612
		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 {
613
		    strncat(str_tt, pEnd, 20 - strlen(str_tt));
614 615 616 617 618 619 620
		    k=0;
		    while(k<5) {
			if(str_tt[k] == 0) {
			    str_tt[k] = '0';
			}
			k++;
		    }
621 622
		    str_tt[k] = 0;
		    pEnd = str_tt;
623 624
		}
	    }
625 626 627 628
	    app = strtol(pEnd, &pEnd, 10);
	    if(state == 7) {
		    app -= 10000;
	    }
629
	    if(  errno == EINVAL ||  errno == ERANGE ) {
630
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_DATE, "%s\n", NMXP_LOG_STR(strerror(errno)));
631 632 633 634 635
		ret = -1;
	    }
	}
    }

636 637
    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));
638 639 640 641 642 643 644

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

    if(ret == -1) {
645 646
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_DATE, "in date '%s' %s\n",
		NMXP_LOG_STR(pstr_date), NMXP_LOG_STR(err_message));
647
    } else {
648
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_DATE, "Date '%s' has been validate! %04d/%02d/%02d %02d:%02d:%02d.%04d\n",
649
		NMXP_LOG_STR(pstr_date),
650 651 652 653 654 655 656
		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
657 658 659 660 661 662
		);
    }

    return ret;
}

663

664 665
double nmxp_data_tm_to_time(NMXP_TM_T *tmt) {
    double ret_d = 0.0;
666
    
667
#ifdef HAVE_TIMEGM
668
    ret_d = timegm(&(tmt->t));
669
#else
670
    ret_d = my_timegm(&(tmt->t));
671
#endif
672

673 674 675
    ret_d += ((double) tmt->d / 10000.0 );

    return ret_d;
676
}
677

678 679 680 681 682 683

#ifdef HAVE_GETCWD
/* TODO */
#endif

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

697

698 699 700 701 702 703 704 705 706 707 708 709
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) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
710 711 712
	    if(chdir(cur_dir) == -1) {
		/* ERROR */
	    }
713
	    NMXP_MEM_FREE(cur_dir);
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
	}
    }

    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) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
733 734 735
	    if(chdir(cur_dir) == -1) {
		/* ERROR */
	    }
736
	    NMXP_MEM_FREE(cur_dir);
737 738 739 740 741 742
	}
    }

    return ret;
}

743 744 745 746 747 748 749 750 751 752
#ifdef HAVE_MKDIR
/* TODO */
#endif

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

753 754 755

int nmxp_data_mkdir(const char *dirname) {
    int ret = 0;
756 757 758
#ifndef HAVE_WINDOWS_H
    mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
#endif
759 760 761 762 763 764 765 766 767 768 769 770
#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;
771 772 773
    int i, l;
    int	error=0;

774 775
    if(!filename)
	return -1;
776
    dir = NMXP_MEM_STRDUP(filename);
777 778 779 780
    if(!dir)
	return -1;

    cur_dir = nmxp_data_gnu_getcwd();
781 782 783 784 785 786 787 788

    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) {
789
		error=nmxp_data_mkdir(dir);
790 791 792 793 794 795
	    }
	    dir[i] = nmxp_data_sepdir;
	}
	i++;
    }
    if(error != -1) {
796
	error=nmxp_data_mkdir(dir);
797 798
    }

799
    NMXP_MEM_FREE(dir);
800 801

    if(cur_dir) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
802 803 804
	if(chdir(cur_dir) == -1) {
	    /* ERROR */
	}
805
	NMXP_MEM_FREE(cur_dir);
806
    }
807 808 809 810
    return error;
}


Matteo Quintiliani's avatar
Matteo Quintiliani committed
811 812
#ifdef HAVE_LIBMSEED

813 814
int nmxp_data_seed_init(NMXP_DATA_SEED *data_seed, char *outdirseed, char *default_network, NMXP_DATA_SEED_TYPEWRITE type_writeseed) {
    int i;
815
    char *dirname = NULL;
816 817

    if(outdirseed) {
818 819
	dirname = nmxp_data_dir_abspath(outdirseed);
	strncpy(data_seed->outdirseed, dirname, NMXP_DATA_MAX_SIZE_FILENAME);
820
    } else {
821 822 823 824
	dirname = nmxp_data_gnu_getcwd();
	strncpy(data_seed->outdirseed, dirname, NMXP_DATA_MAX_SIZE_FILENAME);
    }
    if(dirname) {
825
	NMXP_MEM_FREE(dirname);
826
	dirname = NULL;
827 828 829 830 831 832 833
    }
    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;
834
    data_seed->err_general = 0;
835
    for(i=0; i < NMXP_DATA_MAX_NUM_OPENED_FILE; i++) {
836
	data_seed->err_outfile_mseed[i] = 0;
837 838 839
	data_seed->outfile_mseed[i] = NULL;
	data_seed->filename_mseed[i][0] = 0;
    }
840 841

    data_seed->pmsr = NULL;
842 843 844 845

    return 0;
}

846 847

int nmxp_data_seed_fopen(NMXP_DATA_SEED *data_seed) {
848 849
    int i;
    int found;
850
    int err = 0;
851 852 853 854
    char dirseedchan[NMXP_DATA_MAX_SIZE_FILENAME];
    char filename_mseed[NMXP_DATA_MAX_SIZE_FILENAME];
    char filename_mseed_fullpath[NMXP_DATA_MAX_SIZE_FILENAME];

855
    filename_mseed[0] = 0;
856
    nmxp_data_get_filename_ms(data_seed, dirseedchan, filename_mseed);
857
    if(strlen(filename_mseed)) {
858 859 860
	found=0;
	i=0;
	while(i < data_seed->n_open_files  &&  !found) {
861
	    if( strcmp(filename_mseed, data_seed->filename_mseed[i]) == 0) {
862 863 864 865 866 867 868 869 870 871 872 873
		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 {

874 875 876 877
	    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++;
878
		    data_seed->err_general++;
879 880 881 882 883
		    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++;
884
			data_seed->err_general++;
885 886 887 888 889
			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); */
890 891
	    }

892
	    if(err==0) {
893 894 895 896 897
		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);
898 899
		snprintf(filename_mseed_fullpath, NMXP_DATA_MAX_SIZE_FILENAME, "%s%c%s",
			dirseedchan, nmxp_data_sepdir,
900
			data_seed->filename_mseed[app]);
901

902 903 904 905 906 907 908 909 910 911
		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++;
		    }
912

913 914 915
		    data_seed->last_open_file = app;
		    data_seed->cur_open_file = data_seed->last_open_file;
		}
916
	    }
917 918

	    /* nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "Open  [%3d/%3d] %s\n", data_seed->cur_open_file, data_seed->n_open_files,
919
	       data_seed->filename_mseed[data_seed->cur_open_file]); */
920 921 922 923
	}

    }

924
    return err;
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
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;
}

953
#define NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK ( ( (msr) && (msr->network[0] != 0) )? msr->network : data_seed->default_network )
954 955
int nmxp_data_get_filename_ms(NMXP_DATA_SEED *data_seed, char *dirseedchan, char *filenameseed) {
    int ret = 0;
956
    MSRecord *msr = data_seed->pmsr;
957 958 959 960 961
    
    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,
962
		nmxp_data_year_from_epoch(MS_HPTIME2EPOCH(msr->starttime)),
963 964 965
		nmxp_data_sepdir,
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
		nmxp_data_sepdir,
966
		msr->station,
967
		nmxp_data_sepdir,
968
		msr->channel);
969
	snprintf(filenameseed, NMXP_DATA_MAX_SIZE_FILENAME, "%s.%s.%s.%s.D.%d.%03d",
970
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
971
		msr->station,
972
		(msr->location[0] == 0)? "" : msr->location,
973 974 975
		msr->channel,
		nmxp_data_year_from_epoch(MS_HPTIME2EPOCH(msr->starttime)),
		nmxp_data_yday_from_epoch(MS_HPTIME2EPOCH(msr->starttime)));
976 977 978 979 980
    } 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,
981
		msr->station);
982
	snprintf(filenameseed, NMXP_DATA_MAX_SIZE_FILENAME, "%s.%s.%s.%s.%d.%03d",
983
		msr->station,
984
		NMXP_DATA_NETCODE_OR_DEFAULT_NETWORK,
985
		(msr->location[0] == 0)? "" : msr->location,
986 987 988
		msr->channel,
		nmxp_data_year_from_epoch(MS_HPTIME2EPOCH(msr->starttime)),
		nmxp_data_yday_from_epoch(MS_HPTIME2EPOCH(msr->starttime)));
989 990 991 992 993 994
    }

    return ret;
}


995
/* Private function for writing mini-seed records */
996 997 998
static void nmxp_data_msr_write_handler (char *record, int reclen, void *pdata_seed) {
    int err = 0;
    NMXP_DATA_SEED *data_seed = pdata_seed;
999
    MSRecord *msr = data_seed->pmsr;
1000

1001
    if(msr == NULL) {
1002
	err++;
1003
	nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_EXTRA, "msr is NULL in nmxp_data_msr_write_handler()!\n");
1004 1005 1006 1007
    }

    if(err==0) {

1008 1009 1010 1011 1012 1013 1014 1015
	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]);
		}
1016
	    }
1017 1018
	}
    }
1019
}
1020

Matteo Quintiliani's avatar
Matteo Quintiliani committed
1021

1022
int nmxp_data_msr_pack(NMXP_DATA_PROCESS *pd, NMXP_DATA_SEED *data_seed, void *pmsr) {
1023 1024
    int ret =0;

1025
    MSRecord *msr = pmsr;
1026
    int64_t psamples;
1027
    int precords;
1028
    flag verbose = 0;
1029 1030 1031
    int i;
    int *newdatasamples = NULL;
    int *ptrdatasamples = NULL;
1032
    double gap_overlap;
1033
    double expected_next_time;
1034 1035
    char str_time1[200];
    char str_time2[200];
1036

1037 1038
    /* Set pointer to the current miniseed record buffer */
    data_seed->pmsr = pmsr;
1039

1040 1041 1042
    /* Populate MSRecord values */
    msr->byteorder = nmxp_data_bigendianhost ();
    msr->sampletype = 'i';      /* declare type to be 32-bit integers */
1043

1044
    if(pd) {
1045

1046
	msr->dataquality = pd->quality_indicator;
1047
	msr->samprate = pd->sampRate;
1048
	/* msr->sequence_number = pd->seq_no % 1000000; */
1049

1050 1051 1052 1053 1054 1055 1056 1057 1058
	/* Set starttime,  datasamples and numsamples */
	if(msr->datasamples == NULL) {
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN,
		    "New datasamples for %s.%s.%s (%d)\n",
		    msr->network, msr->station, msr->channel, pd->nSamp);
	    msr->starttime = MS_EPOCH2HPTIME(pd->time);
	    msr->datasamples = NMXP_MEM_MALLOC (sizeof(int) * (pd->nSamp)); 
	    memcpy(msr->datasamples, pd->pDataPtr, sizeof(int) * pd->nSamp); /* pointer to 32-bit integer data samples */
	    msr->numsamples = pd->nSamp;
1059

1060
	} else {
1061

1062 1063
	    expected_next_time = (double) MS_HPTIME2EPOCH(msr->starttime) + ( (double) msr->numsamples * ( 1.0 / (double) msr->samprate ) );
	    gap_overlap = pd->time - expected_next_time;
1064

1065
	    /* Check if data is contiguous */
1066
	    if( fabs(gap_overlap) < fabs( 1.0 / (2.0 * (double) msr->samprate) ) ) {
1067

1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
		/* Add samples */
		nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN,
			"Add datasamples for %s.%s.%s (%d)\n",
			msr->network, msr->station, msr->channel, pd->nSamp);
		newdatasamples = NMXP_MEM_MALLOC (sizeof(int) * (msr->numsamples + pd->nSamp)); 
		memcpy(newdatasamples, msr->datasamples, sizeof(int) * msr->numsamples); /* pointer to 32-bit integer data samples */
		memcpy(newdatasamples + msr->numsamples, pd->pDataPtr, sizeof(int) * pd->nSamp); /* pointer to 32-bit integer data samples */
		msr->numsamples += pd->nSamp;
		NMXP_MEM_FREE(msr->datasamples);
		msr->datasamples = newdatasamples;
		newdatasamples = NULL;
1079

1080
	    } else {
1081

1082 1083 1084
		/* Gap or Overlap, then flush remaining samples and go on */

		nmxp_data_to_str(str_time1, expected_next_time);
1085 1086 1087 1088 1089 1090 1091
		nmxp_data_to_str(str_time2, pd->time);

		nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_ANY,
			"Gap %.2f sec. for %s.%s.%s from %s to %s saving mini-SEED records.\n",
			gap_overlap,
			msr->network, msr->station, msr->channel, NMXP_LOG_STR(str_time1), NMXP_LOG_STR(str_time2));

1092
		/* Pack the record(s) flushing data */
1093
		precords = msr_pack (msr, &nmxp_data_msr_write_handler, data_seed, &psamples, 1, verbose);
1094

1095 1096 1097 1098 1099 1100 1101 1102
		if ( precords == -1 ) {
		    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN,
			    "Cannot pack records %s.%s.%s\n", msr->network, msr->station, msr->channel);
		} else {
		    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN,
			    "Packed forced %d samples into %d records for %s.%s.%s\n",
			    psamples, precords, msr->network, msr->station, msr->channel);
		}
1103

1104 1105 1106 1107
		if(msr->datasamples) {
		    NMXP_MEM_FREE(msr->datasamples);
		    msr->datasamples = NULL;
		}
1108

1109 1110 1111 1112
		msr->starttime = MS_EPOCH2HPTIME(pd->time);
		msr->datasamples = NMXP_MEM_MALLOC (sizeof(int) * (pd->nSamp)); 
		memcpy(msr->datasamples, pd->pDataPtr, sizeof(int) * pd->nSamp); /* pointer to 32-bit integer data samples */
		msr->numsamples = pd->nSamp;
1113

1114
	    }
1115

1116
	}
1117

1118 1119
	/* Pack the record(s) without flushing data if it is not necessary */
	precords = msr_pack (msr, &nmxp_data_msr_write_handler, data_seed, &psamples, 0, verbose);
1120

1121
	if ( precords == -1 ) {
1122
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN,
1123
		    "Cannot pack records %s.%s.%s\n", msr->network, msr->station, msr->channel);
1124
	} else {
1125
	    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN,
1126 1127 1128 1129 1130
		    "Packed %d samples into %d records for %s.%s.%s\n",
		    psamples, precords, msr->network, msr->station, msr->channel);

	    if(psamples > 0) {

1131 1132
		msr->starttime += ( (double) psamples * ( 1.0 / (double) msr->samprate ) );

1133 1134 1135 1136 1137 1138
		if(psamples == msr->numsamples) {
		    /* Remove all samples allocated */
		    NMXP_MEM_FREE(msr->datasamples);
		    msr->datasamples = NULL;
		    msr->numsamples = 0;
		} else if(psamples < msr->numsamples) {