Initial commit based on common repo commit ffeb9c9b
This commit is contained in:
		
							
								
								
									
										1
									
								
								libs/3rd-party/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libs/3rd-party/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
subdirs(mseed)
 | 
			
		||||
							
								
								
									
										7
									
								
								libs/3rd-party/mseed/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								libs/3rd-party/mseed/CMakeLists.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
SET(LIB_NAME mseed)
 | 
			
		||||
FILE(GLOB SOURCES "*.cpp" "*.c" "*.h")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ADD_LIBRARY(${LIB_NAME} STATIC ${SOURCES})
 | 
			
		||||
SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES COMPILE_FLAGS -fPIC)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1183
									
								
								libs/3rd-party/mseed/fileutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1183
									
								
								libs/3rd-party/mseed/fileutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1407
									
								
								libs/3rd-party/mseed/genutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1407
									
								
								libs/3rd-party/mseed/genutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										150
									
								
								libs/3rd-party/mseed/gswap.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								libs/3rd-party/mseed/gswap.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * gswap.c:
 | 
			
		||||
 *
 | 
			
		||||
 * Functions for generalized, in-pace byte swapping between LSBF and
 | 
			
		||||
 * MSBF byte orders.
 | 
			
		||||
 *
 | 
			
		||||
 * Some standard integer types are needed, namely uint8_t and
 | 
			
		||||
 * uint32_t, (these are normally declared by including inttypes.h or
 | 
			
		||||
 * stdint.h).  Each function expects it's input to be a void pointer
 | 
			
		||||
 * to a quantity of the appropriate size.
 | 
			
		||||
 *
 | 
			
		||||
 * There are two versions of most routines, one that works on
 | 
			
		||||
 * quantities regardless of alignment (gswapX) and one that works on
 | 
			
		||||
 * memory aligned quantities (gswapXa).  The memory aligned versions
 | 
			
		||||
 * (gswapXa) are much faster than the other versions (gswapX), but the
 | 
			
		||||
 * memory *must* be aligned.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by Chad Trabant,
 | 
			
		||||
 *   IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 * Version: 2010.006
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "lmplatform.h"
 | 
			
		||||
 | 
			
		||||
/* Swap routines that work on any (aligned or not) quantities */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap2 ( void *data2 )
 | 
			
		||||
{
 | 
			
		||||
  uint8_t temp;
 | 
			
		||||
  
 | 
			
		||||
  union
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t  c[2];
 | 
			
		||||
  } dat;
 | 
			
		||||
  
 | 
			
		||||
  memcpy( &dat, data2, 2 );
 | 
			
		||||
  temp     = dat.c[0];
 | 
			
		||||
  dat.c[0] = dat.c[1];
 | 
			
		||||
  dat.c[1] = temp;
 | 
			
		||||
  memcpy( data2, &dat, 2 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap3 ( void *data3 )
 | 
			
		||||
{
 | 
			
		||||
  uint8_t temp;
 | 
			
		||||
  
 | 
			
		||||
  union
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t  c[3];
 | 
			
		||||
  } dat;
 | 
			
		||||
  
 | 
			
		||||
  memcpy( &dat, data3, 3 );
 | 
			
		||||
  temp     = dat.c[0];
 | 
			
		||||
  dat.c[0] = dat.c[2];
 | 
			
		||||
  dat.c[2] = temp;
 | 
			
		||||
  memcpy( data3, &dat, 3 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap4 ( void *data4 )
 | 
			
		||||
{
 | 
			
		||||
  uint8_t temp;
 | 
			
		||||
 | 
			
		||||
  union {
 | 
			
		||||
    uint8_t c[4];
 | 
			
		||||
  } dat;
 | 
			
		||||
  
 | 
			
		||||
  memcpy( &dat, data4, 4 );
 | 
			
		||||
  temp     = dat.c[0];
 | 
			
		||||
  dat.c[0] = dat.c[3];
 | 
			
		||||
  dat.c[3] = temp;
 | 
			
		||||
  temp     = dat.c[1];
 | 
			
		||||
  dat.c[1] = dat.c[2];
 | 
			
		||||
  dat.c[2] = temp;
 | 
			
		||||
  memcpy( data4, &dat, 4 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap8 ( void *data8 )
 | 
			
		||||
{
 | 
			
		||||
  uint8_t temp;
 | 
			
		||||
  
 | 
			
		||||
  union
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t   c[8];
 | 
			
		||||
  } dat;
 | 
			
		||||
  
 | 
			
		||||
  memcpy( &dat, data8, 8 );
 | 
			
		||||
  temp     = dat.c[0];
 | 
			
		||||
  dat.c[0] = dat.c[7];
 | 
			
		||||
  dat.c[7] = temp;
 | 
			
		||||
  
 | 
			
		||||
  temp     = dat.c[1];
 | 
			
		||||
  dat.c[1] = dat.c[6];
 | 
			
		||||
  dat.c[6] = temp;
 | 
			
		||||
  
 | 
			
		||||
  temp     = dat.c[2];
 | 
			
		||||
  dat.c[2] = dat.c[5];
 | 
			
		||||
  dat.c[5] = temp;
 | 
			
		||||
  
 | 
			
		||||
  temp     = dat.c[3];
 | 
			
		||||
  dat.c[3] = dat.c[4];
 | 
			
		||||
  dat.c[4] = temp;
 | 
			
		||||
  memcpy( data8, &dat, 8 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Swap routines that work on memory aligned quantities */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap2a ( void *data2 )
 | 
			
		||||
{
 | 
			
		||||
  uint16_t *data = data2;
 | 
			
		||||
  
 | 
			
		||||
  *data=(((*data>>8)&0xff) | ((*data&0xff)<<8));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap4a ( void *data4 )
 | 
			
		||||
{
 | 
			
		||||
  uint32_t *data = data4;
 | 
			
		||||
  
 | 
			
		||||
  *data=(((*data>>24)&0xff) | ((*data&0xff)<<24) |
 | 
			
		||||
	 ((*data>>8)&0xff00) | ((*data&0xff00)<<8));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ms_gswap8a ( void *data8 )
 | 
			
		||||
{
 | 
			
		||||
  uint32_t *data4 = data8;
 | 
			
		||||
  uint32_t h0, h1;
 | 
			
		||||
  
 | 
			
		||||
  h0 = data4[0];
 | 
			
		||||
  h0 = (((h0>>24)&0xff) | ((h0&0xff)<<24) |
 | 
			
		||||
	((h0>>8)&0xff00) | ((h0&0xff00)<<8));
 | 
			
		||||
  
 | 
			
		||||
  h1 = data4[1];
 | 
			
		||||
  h1 = (((h1>>24)&0xff) | ((h1&0xff)<<24) |
 | 
			
		||||
	((h1>>8)&0xff00) | ((h1&0xff00)<<8));
 | 
			
		||||
  
 | 
			
		||||
  data4[0] = h1;
 | 
			
		||||
  data4[1] = h0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								libs/3rd-party/mseed/libmseed.def
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								libs/3rd-party/mseed/libmseed.def
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
			
		||||
LIBRARY libmseed.dll
 | 
			
		||||
EXPORTS
 | 
			
		||||
   msr_parse
 | 
			
		||||
   msr_parse_selection
 | 
			
		||||
   msr_unpack
 | 
			
		||||
   msr_pack
 | 
			
		||||
   msr_pack_header
 | 
			
		||||
   msr_init
 | 
			
		||||
   msr_free
 | 
			
		||||
   msr_free_blktchain
 | 
			
		||||
   msr_addblockette
 | 
			
		||||
   msr_normalize_header
 | 
			
		||||
   msr_duplicate
 | 
			
		||||
   msr_samprate
 | 
			
		||||
   msr_nomsamprate
 | 
			
		||||
   msr_starttime
 | 
			
		||||
   msr_starttime_uc
 | 
			
		||||
   msr_endtime
 | 
			
		||||
   msr_srcname
 | 
			
		||||
   msr_print
 | 
			
		||||
   msr_host_latency
 | 
			
		||||
   ms_detect
 | 
			
		||||
   ms_parse_raw
 | 
			
		||||
   mst_init
 | 
			
		||||
   mst_free
 | 
			
		||||
   mst_initgroup
 | 
			
		||||
   mst_freegroup
 | 
			
		||||
   mst_findmatch
 | 
			
		||||
   mst_findadjacent
 | 
			
		||||
   mst_addmsr
 | 
			
		||||
   mst_addspan
 | 
			
		||||
   mst_addmsrtogroup
 | 
			
		||||
   mst_addtracetogroup
 | 
			
		||||
   mst_groupheal
 | 
			
		||||
   mst_groupsort
 | 
			
		||||
   mst_srcname
 | 
			
		||||
   mst_printtracelist
 | 
			
		||||
   mst_printsynclist
 | 
			
		||||
   mst_printgaplist
 | 
			
		||||
   mst_pack
 | 
			
		||||
   mst_packgroup
 | 
			
		||||
   mstl_init
 | 
			
		||||
   mstl_free
 | 
			
		||||
   mstl_addmsr
 | 
			
		||||
   mstl_printtracelist
 | 
			
		||||
   mstl_printsynclist
 | 
			
		||||
   mstl_printgaplist
 | 
			
		||||
   ms_readmsr
 | 
			
		||||
   ms_readmsr_r
 | 
			
		||||
   ms_readmsr_main
 | 
			
		||||
   ms_readtraces
 | 
			
		||||
   ms_readtraces_timewin
 | 
			
		||||
   ms_readtraces_selection
 | 
			
		||||
   ms_readtracelist
 | 
			
		||||
   ms_readtracelist_timewin
 | 
			
		||||
   ms_readtracelist_selection
 | 
			
		||||
   msr_writemseed
 | 
			
		||||
   mst_writemseed
 | 
			
		||||
   mst_writemseedgroup
 | 
			
		||||
   ms_recsrcname
 | 
			
		||||
   ms_splitsrcname
 | 
			
		||||
   ms_strncpclean
 | 
			
		||||
   ms_strncpopen
 | 
			
		||||
   ms_doy2md
 | 
			
		||||
   ms_md2doy
 | 
			
		||||
   ms_btime2hptime
 | 
			
		||||
   ms_btime2isotimestr
 | 
			
		||||
   ms_btime2mdtimestr
 | 
			
		||||
   ms_btime2seedtimestr
 | 
			
		||||
   ms_hptime2btime
 | 
			
		||||
   ms_hptime2isotimestr
 | 
			
		||||
   ms_hptime2mdtimestr
 | 
			
		||||
   ms_hptime2seedtimestr
 | 
			
		||||
   ms_time2hptime
 | 
			
		||||
   ms_seedtimestr2hptime
 | 
			
		||||
   ms_timestr2hptime
 | 
			
		||||
   ms_nomsamprate
 | 
			
		||||
   ms_genfactmult
 | 
			
		||||
   ms_ratapprox
 | 
			
		||||
   ms_bigendianhost
 | 
			
		||||
   ms_dabs
 | 
			
		||||
   ms_samplesize
 | 
			
		||||
   ms_encodingstr
 | 
			
		||||
   ms_blktdesc
 | 
			
		||||
   ms_blktlen
 | 
			
		||||
   ms_errorstr
 | 
			
		||||
   ms_log
 | 
			
		||||
   ms_log_l
 | 
			
		||||
   ms_loginit
 | 
			
		||||
   ms_loginit_l
 | 
			
		||||
   ms_matchselect
 | 
			
		||||
   msr_matchselect
 | 
			
		||||
   ms_addselect
 | 
			
		||||
   ms_addselect_comp
 | 
			
		||||
   ms_readselectionsfile
 | 
			
		||||
   ms_freeselections
 | 
			
		||||
   ms_printselections
 | 
			
		||||
   ms_gswap2
 | 
			
		||||
   ms_gswap3
 | 
			
		||||
   ms_gswap4
 | 
			
		||||
   ms_gswap8
 | 
			
		||||
   ms_gswap2a
 | 
			
		||||
   ms_gswap4a
 | 
			
		||||
   ms_gswap8a
 | 
			
		||||
   msr_unpack_steim2
 | 
			
		||||
   msr_unpack_steim1
 | 
			
		||||
							
								
								
									
										735
									
								
								libs/3rd-party/mseed/libmseed.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										735
									
								
								libs/3rd-party/mseed/libmseed.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,735 @@
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * libmseed.h:
 | 
			
		||||
 * 
 | 
			
		||||
 * Interface declarations for the Mini-SEED library (libmseed).
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Library General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Library General Public License (GNU-LGPL) for more details.  The
 | 
			
		||||
 * GNU-LGPL and further information can be found here:
 | 
			
		||||
 * http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * Written by Chad Trabant
 | 
			
		||||
 * IRIS Data Management Center
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef LIBMSEED_H
 | 
			
		||||
#define LIBMSEED_H 1
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "lmplatform.h"
 | 
			
		||||
 | 
			
		||||
#define LIBMSEED_VERSION "2.13"
 | 
			
		||||
#define LIBMSEED_RELEASE "2014.234"
 | 
			
		||||
 | 
			
		||||
#define MINRECLEN   128      /* Minimum Mini-SEED record length, 2^7 bytes */
 | 
			
		||||
                             /* Note: the SEED specification minimum is 256 */
 | 
			
		||||
#define MAXRECLEN   1048576  /* Maximum Mini-SEED record length, 2^20 bytes */
 | 
			
		||||
 | 
			
		||||
/* SEED data encoding types */
 | 
			
		||||
#define DE_ASCII       0
 | 
			
		||||
#define DE_INT16       1
 | 
			
		||||
#define DE_INT32       3
 | 
			
		||||
#define DE_FLOAT32     4
 | 
			
		||||
#define DE_FLOAT64     5
 | 
			
		||||
#define DE_STEIM1      10
 | 
			
		||||
#define DE_STEIM2      11
 | 
			
		||||
#define DE_GEOSCOPE24  12
 | 
			
		||||
#define DE_GEOSCOPE163 13
 | 
			
		||||
#define DE_GEOSCOPE164 14
 | 
			
		||||
#define DE_CDSN        16
 | 
			
		||||
#define DE_SRO         30
 | 
			
		||||
#define DE_DWWSSN      32
 | 
			
		||||
 | 
			
		||||
/* Library return and error code values, error values should always be negative */
 | 
			
		||||
#define MS_ENDOFFILE        1        /* End of file reached return value */
 | 
			
		||||
#define MS_NOERROR          0        /* No error */
 | 
			
		||||
#define MS_GENERROR        -1        /* Generic unspecified error */
 | 
			
		||||
#define MS_NOTSEED         -2        /* Data not SEED */
 | 
			
		||||
#define MS_WRONGLENGTH     -3        /* Length of data read was not correct */
 | 
			
		||||
#define MS_OUTOFRANGE      -4        /* SEED record length out of range */
 | 
			
		||||
#define MS_UNKNOWNFORMAT   -5        /* Unknown data encoding format */
 | 
			
		||||
#define MS_STBADCOMPFLAG   -6        /* Steim, invalid compression flag(s) */
 | 
			
		||||
 | 
			
		||||
/* Define the high precision time tick interval as 1/modulus seconds */
 | 
			
		||||
/* Default modulus of 1000000 defines tick interval as a microsecond */
 | 
			
		||||
#define HPTMODULUS 1000000
 | 
			
		||||
 | 
			
		||||
/* Error code for routines that normally return a high precision time.
 | 
			
		||||
 * The time value corresponds to '1902/1/1 00:00:00.000000' with the
 | 
			
		||||
 * default HPTMODULUS */
 | 
			
		||||
#define HPTERROR -2145916800000000LL
 | 
			
		||||
 | 
			
		||||
/* Macros to scale between Unix/POSIX epoch time & high precision time */
 | 
			
		||||
#define MS_EPOCH2HPTIME(X) X * (hptime_t) HPTMODULUS
 | 
			
		||||
#define MS_HPTIME2EPOCH(X) X / HPTMODULUS
 | 
			
		||||
 | 
			
		||||
/* Macro to test a character for data record indicators */
 | 
			
		||||
#define MS_ISDATAINDICATOR(X) (X=='D' || X=='R' || X=='Q' || X=='M')
 | 
			
		||||
 | 
			
		||||
/* Macro to test default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 */
 | 
			
		||||
#define MS_ISRATETOLERABLE(A,B) (ms_dabs (1.0 - (A / B)) < 0.0001)
 | 
			
		||||
 | 
			
		||||
/* Macro to test for sane year and day values, used primarily to
 | 
			
		||||
 * determine if byte order swapping is needed.
 | 
			
		||||
 * 
 | 
			
		||||
 * Year : between 1900 and 2100
 | 
			
		||||
 * Day  : between 1 and 366
 | 
			
		||||
 *
 | 
			
		||||
 * This test is non-unique (non-deterministic) for days 1, 256 and 257
 | 
			
		||||
 * in the year 2056 because the swapped values are also within range.
 | 
			
		||||
 */
 | 
			
		||||
#define MS_ISVALIDYEARDAY(Y,D) (Y >= 1900 && Y <= 2100 && D >= 1 && D <= 366)
 | 
			
		||||
 | 
			
		||||
/* Macro to test memory for a SEED data record signature by checking
 | 
			
		||||
 * SEED data record header values at known byte offsets to determine
 | 
			
		||||
 * if the memory contains a valid record.
 | 
			
		||||
 * 
 | 
			
		||||
 * Offset = Value
 | 
			
		||||
 * [0-5]  = Digits, spaces or NULL, SEED sequence number
 | 
			
		||||
 *     6  = Data record quality indicator
 | 
			
		||||
 *     7  = Space or NULL [not valid SEED]
 | 
			
		||||
 *     24 = Start hour (0-23)
 | 
			
		||||
 *     25 = Start minute (0-59)
 | 
			
		||||
 *     26 = Start second (0-60)
 | 
			
		||||
 *
 | 
			
		||||
 * Usage:
 | 
			
		||||
 *   MS_ISVALIDHEADER ((char *)X)  X buffer must contain at least 27 bytes
 | 
			
		||||
 */
 | 
			
		||||
#define MS_ISVALIDHEADER(X) (                                           \
 | 
			
		||||
  (isdigit ((unsigned char) *(X)) || *(X) == ' ' || !*(X) ) &&		\
 | 
			
		||||
  (isdigit ((unsigned char) *(X+1)) || *(X+1) == ' ' || !*(X+1) ) &&	\
 | 
			
		||||
  (isdigit ((unsigned char) *(X+2)) || *(X+2) == ' ' || !*(X+2) ) &&	\
 | 
			
		||||
  (isdigit ((unsigned char) *(X+3)) || *(X+3) == ' ' || !*(X+3) ) &&	\
 | 
			
		||||
  (isdigit ((unsigned char) *(X+4)) || *(X+4) == ' ' || !*(X+4) ) &&	\
 | 
			
		||||
  (isdigit ((unsigned char) *(X+5)) || *(X+5) == ' ' || !*(X+5) ) &&	\
 | 
			
		||||
  MS_ISDATAINDICATOR(*(X+6)) &&						\
 | 
			
		||||
  (*(X+7) == ' ' || *(X+7) == '\0') &&					\
 | 
			
		||||
  (int)(*(X+24)) >= 0 && (int)(*(X+24)) <= 23 &&			\
 | 
			
		||||
  (int)(*(X+25)) >= 0 && (int)(*(X+25)) <= 59 &&			\
 | 
			
		||||
  (int)(*(X+26)) >= 0 && (int)(*(X+26)) <= 60)
 | 
			
		||||
 | 
			
		||||
/* Macro to test memory for a blank/noise SEED data record signature
 | 
			
		||||
 * by checking for a valid SEED sequence number and padding characters
 | 
			
		||||
 * to determine if the memory contains a valid blank/noise record.
 | 
			
		||||
 * 
 | 
			
		||||
 * Offset = Value
 | 
			
		||||
 * [0-5]  = Digits or NULL, SEED sequence number
 | 
			
		||||
 * [6-47] = Space character (ASCII 32), remainder of fixed header
 | 
			
		||||
 *
 | 
			
		||||
 * Usage:
 | 
			
		||||
 *   MS_ISVALIDBLANK ((char *)X)  X buffer must contain at least 27 bytes
 | 
			
		||||
 */
 | 
			
		||||
#define MS_ISVALIDBLANK(X) ((isdigit ((unsigned char) *(X)) || !*(X) ) &&     \
 | 
			
		||||
			    (isdigit ((unsigned char) *(X+1)) || !*(X+1) ) && \
 | 
			
		||||
			    (isdigit ((unsigned char) *(X+2)) || !*(X+2) ) && \
 | 
			
		||||
			    (isdigit ((unsigned char) *(X+3)) || !*(X+3) ) && \
 | 
			
		||||
			    (isdigit ((unsigned char) *(X+4)) || !*(X+4) ) && \
 | 
			
		||||
			    (isdigit ((unsigned char) *(X+5)) || !*(X+5) ) && \
 | 
			
		||||
			    (*(X+6)==' ')&&(*(X+7)==' ')&&(*(X+8)==' ') &&    \
 | 
			
		||||
			    (*(X+9)==' ')&&(*(X+10)==' ')&&(*(X+11)==' ') &&  \
 | 
			
		||||
			    (*(X+12)==' ')&&(*(X+13)==' ')&&(*(X+14)==' ') && \
 | 
			
		||||
			    (*(X+15)==' ')&&(*(X+16)==' ')&&(*(X+17)==' ') && \
 | 
			
		||||
			    (*(X+18)==' ')&&(*(X+19)==' ')&&(*(X+20)==' ') && \
 | 
			
		||||
			    (*(X+21)==' ')&&(*(X+22)==' ')&&(*(X+23)==' ') && \
 | 
			
		||||
			    (*(X+24)==' ')&&(*(X+25)==' ')&&(*(X+26)==' ') && \
 | 
			
		||||
			    (*(X+27)==' ')&&(*(X+28)==' ')&&(*(X+29)==' ') && \
 | 
			
		||||
			    (*(X+30)==' ')&&(*(X+31)==' ')&&(*(X+32)==' ') && \
 | 
			
		||||
			    (*(X+33)==' ')&&(*(X+34)==' ')&&(*(X+35)==' ') && \
 | 
			
		||||
			    (*(X+36)==' ')&&(*(X+37)==' ')&&(*(X+38)==' ') && \
 | 
			
		||||
			    (*(X+39)==' ')&&(*(X+40)==' ')&&(*(X+41)==' ') && \
 | 
			
		||||
			    (*(X+42)==' ')&&(*(X+43)==' ')&&(*(X+44)==' ') && \
 | 
			
		||||
			    (*(X+45)==' ')&&(*(X+46)==' ')&&(*(X+47)==' ') )
 | 
			
		||||
 | 
			
		||||
/* A simple bitwise AND test to return 0 or 1 */
 | 
			
		||||
#define bit(x,y) (x&y)?1:0
 | 
			
		||||
 | 
			
		||||
/* Require a large (>= 64-bit) integer type for hptime_t */
 | 
			
		||||
typedef int64_t hptime_t;
 | 
			
		||||
 | 
			
		||||
/* A single byte flag type */
 | 
			
		||||
typedef int8_t flag;
 | 
			
		||||
 | 
			
		||||
/* SEED binary time */
 | 
			
		||||
typedef struct btime_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  year;
 | 
			
		||||
  uint16_t  day;
 | 
			
		||||
  uint8_t   hour;
 | 
			
		||||
  uint8_t   min;
 | 
			
		||||
  uint8_t   sec;
 | 
			
		||||
  uint8_t   unused;
 | 
			
		||||
  uint16_t  fract;
 | 
			
		||||
} LMP_PACKED
 | 
			
		||||
BTime;
 | 
			
		||||
 | 
			
		||||
/* Fixed section data of header */
 | 
			
		||||
struct fsdh_s
 | 
			
		||||
{
 | 
			
		||||
  char      sequence_number[6];
 | 
			
		||||
  char      dataquality;
 | 
			
		||||
  char      reserved;
 | 
			
		||||
  char      station[5];
 | 
			
		||||
  char      location[2];
 | 
			
		||||
  char      channel[3];
 | 
			
		||||
  char      network[2];
 | 
			
		||||
  BTime     start_time;
 | 
			
		||||
  uint16_t  numsamples;
 | 
			
		||||
  int16_t   samprate_fact;
 | 
			
		||||
  int16_t   samprate_mult;
 | 
			
		||||
  uint8_t   act_flags;
 | 
			
		||||
  uint8_t   io_flags;
 | 
			
		||||
  uint8_t   dq_flags;
 | 
			
		||||
  uint8_t   numblockettes;
 | 
			
		||||
  int32_t   time_correct;
 | 
			
		||||
  uint16_t  data_offset;
 | 
			
		||||
  uint16_t  blockette_offset;
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 100, Sample Rate (without header) */
 | 
			
		||||
struct blkt_100_s
 | 
			
		||||
{
 | 
			
		||||
  float     samprate;
 | 
			
		||||
  int8_t    flags;
 | 
			
		||||
  uint8_t   reserved[3];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 200, Generic Event Detection (without header) */
 | 
			
		||||
struct blkt_200_s
 | 
			
		||||
{
 | 
			
		||||
  float     amplitude;
 | 
			
		||||
  float     period;
 | 
			
		||||
  float     background_estimate;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  char      detector[24];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 201, Murdock Event Detection (without header) */
 | 
			
		||||
struct blkt_201_s
 | 
			
		||||
{
 | 
			
		||||
  float     amplitude;
 | 
			
		||||
  float     period;
 | 
			
		||||
  float     background_estimate;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  uint8_t   snr_values[6];
 | 
			
		||||
  uint8_t   loopback;
 | 
			
		||||
  uint8_t   pick_algorithm;
 | 
			
		||||
  char      detector[24];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 300, Step Calibration (without header) */
 | 
			
		||||
struct blkt_300_s
 | 
			
		||||
{
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  uint8_t   numcalibrations;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint32_t  step_duration;
 | 
			
		||||
  uint32_t  interval_duration;
 | 
			
		||||
  float     amplitude;
 | 
			
		||||
  char      input_channel[3];
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
  uint32_t  reference_amplitude;
 | 
			
		||||
  char      coupling[12];
 | 
			
		||||
  char      rolloff[12];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 310, Sine Calibration (without header) */
 | 
			
		||||
struct blkt_310_s
 | 
			
		||||
{
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  uint8_t   reserved1;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint32_t  duration;
 | 
			
		||||
  float     period;
 | 
			
		||||
  float     amplitude;
 | 
			
		||||
  char      input_channel[3];
 | 
			
		||||
  uint8_t   reserved2;
 | 
			
		||||
  uint32_t  reference_amplitude;
 | 
			
		||||
  char      coupling[12];
 | 
			
		||||
  char      rolloff[12];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 320, Pseudo-random Calibration (without header) */
 | 
			
		||||
struct blkt_320_s
 | 
			
		||||
{
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  uint8_t   reserved1;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint32_t  duration;
 | 
			
		||||
  float     ptp_amplitude;
 | 
			
		||||
  char      input_channel[3];
 | 
			
		||||
  uint8_t   reserved2;
 | 
			
		||||
  uint32_t  reference_amplitude;
 | 
			
		||||
  char      coupling[12];
 | 
			
		||||
  char      rolloff[12];
 | 
			
		||||
  char      noise_type[8];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
  
 | 
			
		||||
/* Blockette 390, Generic Calibration (without header) */
 | 
			
		||||
struct blkt_390_s
 | 
			
		||||
{
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  uint8_t   reserved1;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint32_t  duration;
 | 
			
		||||
  float     amplitude;
 | 
			
		||||
  char      input_channel[3];
 | 
			
		||||
  uint8_t   reserved2;
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 395, Calibration Abort (without header) */
 | 
			
		||||
struct blkt_395_s
 | 
			
		||||
{
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  uint8_t   reserved[2];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 400, Beam (without header) */
 | 
			
		||||
struct blkt_400_s
 | 
			
		||||
{
 | 
			
		||||
  float     azimuth;
 | 
			
		||||
  float     slowness;
 | 
			
		||||
  uint16_t  configuration;
 | 
			
		||||
  uint8_t   reserved[2];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 405, Beam Delay (without header) */
 | 
			
		||||
struct blkt_405_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  delay_values[1];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Blockette 500, Timing (without header) */
 | 
			
		||||
struct blkt_500_s
 | 
			
		||||
{
 | 
			
		||||
  float     vco_correction;
 | 
			
		||||
  BTime     time;
 | 
			
		||||
  int8_t    usec;
 | 
			
		||||
  uint8_t   reception_qual;
 | 
			
		||||
  uint32_t  exception_count;
 | 
			
		||||
  char      exception_type[16];
 | 
			
		||||
  char      clock_model[32];
 | 
			
		||||
  char      clock_status[128];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 1000, Data Only SEED (without header) */
 | 
			
		||||
struct blkt_1000_s
 | 
			
		||||
{
 | 
			
		||||
  uint8_t   encoding;
 | 
			
		||||
  uint8_t   byteorder;
 | 
			
		||||
  uint8_t   reclen;
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 1001, Data Extension (without header) */
 | 
			
		||||
struct blkt_1001_s
 | 
			
		||||
{
 | 
			
		||||
  uint8_t   timing_qual;
 | 
			
		||||
  int8_t    usec;
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
  uint8_t   framecnt;
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette 2000, Opaque Data (without header) */
 | 
			
		||||
struct blkt_2000_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  length;
 | 
			
		||||
  uint16_t  data_offset;
 | 
			
		||||
  uint32_t  recnum;
 | 
			
		||||
  uint8_t   byteorder;
 | 
			
		||||
  uint8_t   flags;
 | 
			
		||||
  uint8_t   numheaders;
 | 
			
		||||
  char      payload[1];
 | 
			
		||||
} LMP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Blockette chain link, generic linkable blockette index */
 | 
			
		||||
typedef struct blkt_link_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t            blktoffset;    /* Offset to this blockette */
 | 
			
		||||
  uint16_t            blkt_type;     /* Blockette type */
 | 
			
		||||
  uint16_t            next_blkt;     /* Offset to next blockette */
 | 
			
		||||
  void               *blktdata;      /* Blockette data */
 | 
			
		||||
  uint16_t            blktdatalen;   /* Length of blockette data in bytes */
 | 
			
		||||
  struct blkt_link_s *next;
 | 
			
		||||
}
 | 
			
		||||
BlktLink;
 | 
			
		||||
 | 
			
		||||
typedef struct StreamState_s
 | 
			
		||||
{
 | 
			
		||||
  int64_t   packedrecords;           /* Count of packed records */
 | 
			
		||||
  int64_t   packedsamples;           /* Count of packed samples */
 | 
			
		||||
  int32_t   lastintsample;           /* Value of last integer sample packed */
 | 
			
		||||
  flag      comphistory;             /* Control use of lastintsample for compression history */
 | 
			
		||||
}
 | 
			
		||||
StreamState;
 | 
			
		||||
 | 
			
		||||
typedef struct MSRecord_s {
 | 
			
		||||
  char           *record;            /* Mini-SEED record */
 | 
			
		||||
  int32_t         reclen;            /* Length of Mini-SEED record in bytes */
 | 
			
		||||
  
 | 
			
		||||
  /* Pointers to SEED data record structures */
 | 
			
		||||
  struct fsdh_s      *fsdh;          /* Fixed Section of Data Header */
 | 
			
		||||
  BlktLink           *blkts;         /* Root of blockette chain */
 | 
			
		||||
  struct blkt_100_s  *Blkt100;       /* Blockette 100, if present */
 | 
			
		||||
  struct blkt_1000_s *Blkt1000;      /* Blockette 1000, if present */
 | 
			
		||||
  struct blkt_1001_s *Blkt1001;      /* Blockette 1001, if present */
 | 
			
		||||
  
 | 
			
		||||
  /* Common header fields in accessible form */
 | 
			
		||||
  int32_t         sequence_number;   /* SEED record sequence number */
 | 
			
		||||
  char            network[11];       /* Network designation, NULL terminated */
 | 
			
		||||
  char            station[11];       /* Station designation, NULL terminated */
 | 
			
		||||
  char            location[11];      /* Location designation, NULL terminated */
 | 
			
		||||
  char            channel[11];       /* Channel designation, NULL terminated */
 | 
			
		||||
  char            dataquality;       /* Data quality indicator */
 | 
			
		||||
  hptime_t        starttime;         /* Record start time, corrected (first sample) */
 | 
			
		||||
  double          samprate;          /* Nominal sample rate (Hz) */
 | 
			
		||||
  int64_t         samplecnt;         /* Number of samples in record */
 | 
			
		||||
  int8_t          encoding;          /* Data encoding format */
 | 
			
		||||
  int8_t          byteorder;         /* Original/Final byte order of record */
 | 
			
		||||
  
 | 
			
		||||
  /* Data sample fields */
 | 
			
		||||
  void           *datasamples;       /* Data samples, 'numsamples' of type 'sampletype'*/
 | 
			
		||||
  int64_t         numsamples;        /* Number of data samples in datasamples */
 | 
			
		||||
  char            sampletype;        /* Sample type code: a, i, f, d */
 | 
			
		||||
  
 | 
			
		||||
  /* Stream oriented state information */
 | 
			
		||||
  StreamState    *ststate;           /* Stream processing state information */
 | 
			
		||||
}
 | 
			
		||||
MSRecord;
 | 
			
		||||
 | 
			
		||||
/* Container for a continuous trace, linkable */
 | 
			
		||||
typedef struct MSTrace_s {
 | 
			
		||||
  char            network[11];       /* Network designation, NULL terminated */
 | 
			
		||||
  char            station[11];       /* Station designation, NULL terminated */
 | 
			
		||||
  char            location[11];      /* Location designation, NULL terminated */
 | 
			
		||||
  char            channel[11];       /* Channel designation, NULL terminated */
 | 
			
		||||
  char            dataquality;       /* Data quality indicator */ 
 | 
			
		||||
  char            type;              /* MSTrace type code */
 | 
			
		||||
  hptime_t        starttime;         /* Time of first sample */
 | 
			
		||||
  hptime_t        endtime;           /* Time of last sample */
 | 
			
		||||
  double          samprate;          /* Nominal sample rate (Hz) */
 | 
			
		||||
  int64_t         samplecnt;         /* Number of samples in trace coverage */
 | 
			
		||||
  void           *datasamples;       /* Data samples, 'numsamples' of type 'sampletype' */
 | 
			
		||||
  int64_t         numsamples;        /* Number of data samples in datasamples */
 | 
			
		||||
  char            sampletype;        /* Sample type code: a, i, f, d */
 | 
			
		||||
  void           *prvtptr;           /* Private pointer for general use, unused by libmseed */
 | 
			
		||||
  StreamState    *ststate;           /* Stream processing state information */
 | 
			
		||||
  struct MSTrace_s *next;            /* Pointer to next trace */
 | 
			
		||||
}
 | 
			
		||||
MSTrace;
 | 
			
		||||
 | 
			
		||||
/* Container for a group (chain) of traces */
 | 
			
		||||
typedef struct MSTraceGroup_s {
 | 
			
		||||
  int32_t           numtraces;       /* Number of MSTraces in the trace chain */
 | 
			
		||||
  struct MSTrace_s *traces;          /* Root of the trace chain */
 | 
			
		||||
}
 | 
			
		||||
MSTraceGroup;
 | 
			
		||||
 | 
			
		||||
/* Container for a continuous trace segment, linkable */
 | 
			
		||||
typedef struct MSTraceSeg_s {
 | 
			
		||||
  hptime_t        starttime;         /* Time of first sample */
 | 
			
		||||
  hptime_t        endtime;           /* Time of last sample */
 | 
			
		||||
  double          samprate;          /* Nominal sample rate (Hz) */
 | 
			
		||||
  int64_t         samplecnt;         /* Number of samples in trace coverage */
 | 
			
		||||
  void           *datasamples;       /* Data samples, 'numsamples' of type 'sampletype'*/
 | 
			
		||||
  int64_t         numsamples;        /* Number of data samples in datasamples */
 | 
			
		||||
  char            sampletype;        /* Sample type code: a, i, f, d */
 | 
			
		||||
  void           *prvtptr;           /* Private pointer for general use, unused by libmseed */
 | 
			
		||||
  struct MSTraceSeg_s *prev;         /* Pointer to previous segment */
 | 
			
		||||
  struct MSTraceSeg_s *next;         /* Pointer to next segment */
 | 
			
		||||
}
 | 
			
		||||
MSTraceSeg;
 | 
			
		||||
 | 
			
		||||
/* Container for a trace ID, linkable */
 | 
			
		||||
typedef struct MSTraceID_s {
 | 
			
		||||
  char            network[11];       /* Network designation, NULL terminated */
 | 
			
		||||
  char            station[11];       /* Station designation, NULL terminated */
 | 
			
		||||
  char            location[11];      /* Location designation, NULL terminated */
 | 
			
		||||
  char            channel[11];       /* Channel designation, NULL terminated */
 | 
			
		||||
  char            dataquality;       /* Data quality indicator */
 | 
			
		||||
  char            srcname[45];       /* Source name (Net_Sta_Loc_Chan_Qual), NULL terminated */
 | 
			
		||||
  char            type;              /* Trace type code */
 | 
			
		||||
  hptime_t        earliest;          /* Time of earliest sample */
 | 
			
		||||
  hptime_t        latest;            /* Time of latest sample */
 | 
			
		||||
  void           *prvtptr;           /* Private pointer for general use, unused by libmseed */
 | 
			
		||||
  int32_t         numsegments;       /* Number of segments for this ID */
 | 
			
		||||
  struct MSTraceSeg_s *first;        /* Pointer to first of list of segments */
 | 
			
		||||
  struct MSTraceSeg_s *last;         /* Pointer to last of list of segments */
 | 
			
		||||
  struct MSTraceID_s *next;          /* Pointer to next trace */
 | 
			
		||||
}
 | 
			
		||||
MSTraceID;
 | 
			
		||||
 | 
			
		||||
/* Container for a continuous trace segment, linkable */
 | 
			
		||||
typedef struct MSTraceList_s {
 | 
			
		||||
  int32_t             numtraces;     /* Number of traces in list */
 | 
			
		||||
  struct MSTraceID_s *traces;        /* Pointer to list of traces */
 | 
			
		||||
  struct MSTraceID_s *last;          /* Pointer to last used trace in list */
 | 
			
		||||
}
 | 
			
		||||
MSTraceList;
 | 
			
		||||
 | 
			
		||||
/* Data selection structure time window definition containers */
 | 
			
		||||
typedef struct SelectTime_s {
 | 
			
		||||
  hptime_t starttime;    /* Earliest data for matching channels */
 | 
			
		||||
  hptime_t endtime;      /* Latest data for matching channels */
 | 
			
		||||
  struct SelectTime_s *next;
 | 
			
		||||
} SelectTime;
 | 
			
		||||
 | 
			
		||||
/* Data selection structure definition containers */
 | 
			
		||||
typedef struct Selections_s {
 | 
			
		||||
  char srcname[100];     /* Matching (globbing) source name: Net_Sta_Loc_Chan_Qual */
 | 
			
		||||
  struct SelectTime_s *timewindows;
 | 
			
		||||
  struct Selections_s *next;
 | 
			
		||||
} Selections;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Global variables (defined in pack.c) and macros to set/force
 | 
			
		||||
 * pack byte orders */
 | 
			
		||||
extern flag packheaderbyteorder;
 | 
			
		||||
extern flag packdatabyteorder;
 | 
			
		||||
#define MS_PACKHEADERBYTEORDER(X) (packheaderbyteorder = X);
 | 
			
		||||
#define MS_PACKDATABYTEORDER(X) (packdatabyteorder = X);
 | 
			
		||||
 | 
			
		||||
/* Global variables (defined in unpack.c) and macros to set/force
 | 
			
		||||
 * unpack byte orders */
 | 
			
		||||
extern flag unpackheaderbyteorder;
 | 
			
		||||
extern flag unpackdatabyteorder;
 | 
			
		||||
#define MS_UNPACKHEADERBYTEORDER(X) (unpackheaderbyteorder = X);
 | 
			
		||||
#define MS_UNPACKDATABYTEORDER(X) (unpackdatabyteorder = X);
 | 
			
		||||
 | 
			
		||||
/* Global variables (defined in unpack.c) and macros to set/force
 | 
			
		||||
 * encoding and fallback encoding */
 | 
			
		||||
extern int unpackencodingformat;
 | 
			
		||||
extern int unpackencodingfallback;
 | 
			
		||||
#define MS_UNPACKENCODINGFORMAT(X) (unpackencodingformat = X);
 | 
			
		||||
#define MS_UNPACKENCODINGFALLBACK(X) (unpackencodingfallback = X);
 | 
			
		||||
 | 
			
		||||
/* Mini-SEED record related functions */
 | 
			
		||||
extern int           msr_parse (char *record, int recbuflen, MSRecord **ppmsr, int reclen,
 | 
			
		||||
				flag dataflag, flag verbose);
 | 
			
		||||
 | 
			
		||||
extern int           msr_parse_selection ( char *recbuf, int recbuflen, int64_t *offset,
 | 
			
		||||
					   MSRecord **ppmsr, int reclen,
 | 
			
		||||
					   Selections *selections, flag dataflag, flag verbose );
 | 
			
		||||
 | 
			
		||||
extern int           msr_unpack (char *record, int reclen, MSRecord **ppmsr,
 | 
			
		||||
				 flag dataflag, flag verbose);
 | 
			
		||||
 | 
			
		||||
extern int           msr_pack (MSRecord *msr, void (*record_handler) (char *, int, void *),
 | 
			
		||||
		 	       void *handlerdata, int64_t *packedsamples, flag flush, flag verbose );
 | 
			
		||||
 | 
			
		||||
extern int           msr_pack_header (MSRecord *msr, flag normalize, flag verbose);
 | 
			
		||||
 | 
			
		||||
extern int           msr_unpack_data (MSRecord *msr, int swapflag, flag verbose);
 | 
			
		||||
 | 
			
		||||
extern MSRecord*     msr_init (MSRecord *msr);
 | 
			
		||||
extern void          msr_free (MSRecord **ppmsr);
 | 
			
		||||
extern void          msr_free_blktchain (MSRecord *msr);
 | 
			
		||||
extern BlktLink*     msr_addblockette (MSRecord *msr, char *blktdata, int length,
 | 
			
		||||
				       int blkttype, int chainpos);
 | 
			
		||||
extern int           msr_normalize_header (MSRecord *msr, flag verbose);
 | 
			
		||||
extern MSRecord*     msr_duplicate (MSRecord *msr, flag datadup);
 | 
			
		||||
extern double        msr_samprate (MSRecord *msr);
 | 
			
		||||
extern double        msr_nomsamprate (MSRecord *msr);
 | 
			
		||||
extern hptime_t      msr_starttime (MSRecord *msr);
 | 
			
		||||
extern hptime_t      msr_starttime_uc (MSRecord *msr);
 | 
			
		||||
extern hptime_t      msr_endtime (MSRecord *msr);
 | 
			
		||||
extern char*         msr_srcname (MSRecord *msr, char *srcname, flag quality);
 | 
			
		||||
extern void          msr_print (MSRecord *msr, flag details);
 | 
			
		||||
extern double        msr_host_latency (MSRecord *msr);
 | 
			
		||||
 | 
			
		||||
extern int           ms_detect (const char *record, int recbuflen);
 | 
			
		||||
extern int           ms_parse_raw (char *record, int maxreclen, flag details, flag swapflag);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* MSTrace related functions */
 | 
			
		||||
extern MSTrace*      mst_init (MSTrace *mst);
 | 
			
		||||
extern void          mst_free (MSTrace **ppmst);
 | 
			
		||||
extern MSTraceGroup* mst_initgroup (MSTraceGroup *mstg);
 | 
			
		||||
extern void          mst_freegroup (MSTraceGroup **ppmstg);
 | 
			
		||||
extern MSTrace*      mst_findmatch (MSTrace *startmst, char dataquality,
 | 
			
		||||
				    char *network, char *station, char *location, char *channel);
 | 
			
		||||
extern MSTrace*      mst_findadjacent (MSTraceGroup *mstg, flag *whence, char dataquality,
 | 
			
		||||
				       char *network, char *station, char *location, char *channel,
 | 
			
		||||
				       double samprate, double sampratetol,
 | 
			
		||||
				       hptime_t starttime, hptime_t endtime, double timetol);
 | 
			
		||||
extern int           mst_addmsr (MSTrace *mst, MSRecord *msr, flag whence);
 | 
			
		||||
extern int           mst_addspan (MSTrace *mst, hptime_t starttime,  hptime_t endtime,
 | 
			
		||||
				  void *datasamples, int64_t numsamples,
 | 
			
		||||
				  char sampletype, flag whence);
 | 
			
		||||
extern MSTrace*      mst_addmsrtogroup (MSTraceGroup *mstg, MSRecord *msr, flag dataquality,
 | 
			
		||||
					double timetol, double sampratetol);
 | 
			
		||||
extern MSTrace*      mst_addtracetogroup (MSTraceGroup *mstg, MSTrace *mst);
 | 
			
		||||
extern int           mst_groupheal (MSTraceGroup *mstg, double timetol, double sampratetol);
 | 
			
		||||
extern int           mst_groupsort (MSTraceGroup *mstg, flag quality);
 | 
			
		||||
extern int           mst_convertsamples (MSTrace *mst, char type, flag truncate);
 | 
			
		||||
extern char *        mst_srcname (MSTrace *mst, char *srcname, flag quality);
 | 
			
		||||
extern void          mst_printtracelist (MSTraceGroup *mstg, flag timeformat,
 | 
			
		||||
					 flag details, flag gaps);
 | 
			
		||||
extern void          mst_printsynclist ( MSTraceGroup *mstg, char *dccid, flag subsecond );
 | 
			
		||||
extern void          mst_printgaplist (MSTraceGroup *mstg, flag timeformat,
 | 
			
		||||
				       double *mingap, double *maxgap);
 | 
			
		||||
extern int           mst_pack (MSTrace *mst, void (*record_handler) (char *, int, void *),
 | 
			
		||||
			       void *handlerdata, int reclen, flag encoding, flag byteorder,
 | 
			
		||||
			       int64_t *packedsamples, flag flush, flag verbose,
 | 
			
		||||
			       MSRecord *mstemplate);
 | 
			
		||||
extern int           mst_packgroup (MSTraceGroup *mstg, void (*record_handler) (char *, int, void *),
 | 
			
		||||
				    void *handlerdata, int reclen, flag encoding, flag byteorder,
 | 
			
		||||
				    int64_t *packedsamples, flag flush, flag verbose,
 | 
			
		||||
				    MSRecord *mstemplate);
 | 
			
		||||
 | 
			
		||||
/* MSTraceList related functions */
 | 
			
		||||
extern MSTraceList * mstl_init ( MSTraceList *mstl );
 | 
			
		||||
extern void          mstl_free ( MSTraceList **ppmstl, flag freeprvtptr );
 | 
			
		||||
extern MSTraceSeg *  mstl_addmsr ( MSTraceList *mstl, MSRecord *msr, flag dataquality,
 | 
			
		||||
				   flag autoheal, double timetol, double sampratetol );
 | 
			
		||||
extern int           mstl_convertsamples ( MSTraceSeg *seg, char type, flag truncate );
 | 
			
		||||
extern void          mstl_printtracelist ( MSTraceList *mstl, flag timeformat,
 | 
			
		||||
					   flag details, flag gaps );
 | 
			
		||||
extern void          mstl_printsynclist ( MSTraceList *mstl, char *dccid, flag subsecond );
 | 
			
		||||
extern void          mstl_printgaplist (MSTraceList *mstl, flag timeformat,
 | 
			
		||||
					double *mingap, double *maxgap);
 | 
			
		||||
 | 
			
		||||
/* Reading Mini-SEED records from files */
 | 
			
		||||
typedef struct MSFileParam_s
 | 
			
		||||
{
 | 
			
		||||
  FILE *fp;
 | 
			
		||||
  char  filename[512];
 | 
			
		||||
  char *rawrec;
 | 
			
		||||
  int   readlen;
 | 
			
		||||
  int   readoffset;
 | 
			
		||||
  int   packtype;
 | 
			
		||||
  off_t packhdroffset;
 | 
			
		||||
  off_t filepos;
 | 
			
		||||
  off_t filesize;
 | 
			
		||||
  int   recordcount;
 | 
			
		||||
} MSFileParam;
 | 
			
		||||
 | 
			
		||||
extern int      ms_readmsr (MSRecord **ppmsr, const char *msfile, int reclen, off_t *fpos, int *last,
 | 
			
		||||
			    flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readmsr_r (MSFileParam **ppmsfp, MSRecord **ppmsr, const char *msfile, int reclen,
 | 
			
		||||
			      off_t *fpos, int *last, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readmsr_main (MSFileParam **ppmsfp, MSRecord **ppmsr, const char *msfile, int reclen,
 | 
			
		||||
				 off_t *fpos, int *last, flag skipnotdata, flag dataflag, Selections *selections, flag verbose);
 | 
			
		||||
extern int      ms_readtraces (MSTraceGroup **ppmstg, const char *msfile, int reclen, double timetol, double sampratetol,
 | 
			
		||||
			       flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readtraces_timewin (MSTraceGroup **ppmstg, const char *msfile, int reclen, double timetol, double sampratetol,
 | 
			
		||||
				       hptime_t starttime, hptime_t endtime, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readtraces_selection (MSTraceGroup **ppmstg, const char *msfile, int reclen, double timetol, double sampratetol,
 | 
			
		||||
					 Selections *selections, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readtracelist (MSTraceList **ppmstl, const char *msfile, int reclen, double timetol, double sampratetol,
 | 
			
		||||
				  flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readtracelist_timewin (MSTraceList **ppmstl, const char *msfile, int reclen, double timetol, double sampratetol,
 | 
			
		||||
					  hptime_t starttime, hptime_t endtime, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
extern int      ms_readtracelist_selection (MSTraceList **ppmstl, const char *msfile, int reclen, double timetol, double sampratetol,
 | 
			
		||||
					    Selections *selections, flag dataquality, flag skipnotdata, flag dataflag, flag verbose);
 | 
			
		||||
 | 
			
		||||
extern int      msr_writemseed ( MSRecord *msr, const char *msfile, flag overwrite, int reclen,
 | 
			
		||||
				 flag encoding, flag byteorder, flag verbose );
 | 
			
		||||
extern int      mst_writemseed ( MSTrace *mst, const char *msfile, flag overwrite, int reclen,
 | 
			
		||||
				 flag encoding, flag byteorder, flag verbose );
 | 
			
		||||
extern int      mst_writemseedgroup ( MSTraceGroup *mstg, const char *msfile, flag overwrite,
 | 
			
		||||
				      int reclen, flag encoding, flag byteorder, flag verbose );
 | 
			
		||||
 | 
			
		||||
/* General use functions */
 | 
			
		||||
extern char*    ms_recsrcname (char *record, char *srcname, flag quality);
 | 
			
		||||
extern int      ms_splitsrcname (char *srcname, char *net, char *sta, char *loc, char *chan, char *qual);
 | 
			
		||||
extern int      ms_strncpclean (char *dest, const char *source, int length);
 | 
			
		||||
extern int      ms_strncpcleantail (char *dest, const char *source, int length);
 | 
			
		||||
extern int      ms_strncpopen (char *dest, const char *source, int length);
 | 
			
		||||
extern int      ms_doy2md (int year, int jday, int *month, int *mday);
 | 
			
		||||
extern int      ms_md2doy (int year, int month, int mday, int *jday);
 | 
			
		||||
extern hptime_t ms_btime2hptime (BTime *btime);
 | 
			
		||||
extern char*    ms_btime2isotimestr (BTime *btime, char *isotimestr);
 | 
			
		||||
extern char*    ms_btime2mdtimestr (BTime *btime, char *mdtimestr);
 | 
			
		||||
extern char*    ms_btime2seedtimestr (BTime *btime, char *seedtimestr);
 | 
			
		||||
extern int      ms_hptime2btime (hptime_t hptime, BTime *btime);
 | 
			
		||||
extern char*    ms_hptime2isotimestr (hptime_t hptime, char *isotimestr, flag subsecond);
 | 
			
		||||
extern char*    ms_hptime2mdtimestr (hptime_t hptime, char *mdtimestr, flag subsecond);
 | 
			
		||||
extern char*    ms_hptime2seedtimestr (hptime_t hptime, char *seedtimestr, flag subsecond);
 | 
			
		||||
extern hptime_t ms_time2hptime (int year, int day, int hour, int min, int sec, int usec);
 | 
			
		||||
extern hptime_t ms_seedtimestr2hptime (char *seedtimestr);
 | 
			
		||||
extern hptime_t ms_timestr2hptime (char *timestr);
 | 
			
		||||
extern double   ms_nomsamprate (int factor, int multiplier);
 | 
			
		||||
extern int      ms_genfactmult (double samprate, int16_t *factor, int16_t *multiplier);
 | 
			
		||||
extern int      ms_ratapprox (double real, int *num, int *den, int maxval, double precision);
 | 
			
		||||
extern int      ms_bigendianhost (void);
 | 
			
		||||
extern double   ms_dabs (double val);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Lookup functions */
 | 
			
		||||
extern uint8_t  ms_samplesize (const char sampletype);
 | 
			
		||||
extern char*    ms_encodingstr (const char encoding);
 | 
			
		||||
extern char*    ms_blktdesc (uint16_t blkttype);
 | 
			
		||||
extern uint16_t ms_blktlen (uint16_t blkttype, const char *blktdata, flag swapflag);
 | 
			
		||||
extern char *   ms_errorstr (int errorcode);
 | 
			
		||||
 | 
			
		||||
/* Logging facility */
 | 
			
		||||
#define MAX_LOG_MSG_LENGTH  200      /* Maximum length of log messages */
 | 
			
		||||
 | 
			
		||||
/* Logging parameters */
 | 
			
		||||
typedef struct MSLogParam_s
 | 
			
		||||
{
 | 
			
		||||
  void (*log_print)(char*);
 | 
			
		||||
  const char *logprefix;
 | 
			
		||||
  void (*diag_print)(char*);
 | 
			
		||||
  const char *errprefix;
 | 
			
		||||
} MSLogParam;
 | 
			
		||||
 | 
			
		||||
extern int    ms_log (int level, ...);
 | 
			
		||||
extern int    ms_log_l (MSLogParam *logp, int level, ...);
 | 
			
		||||
extern void   ms_loginit (void (*log_print)(char*), const char *logprefix,
 | 
			
		||||
			  void (*diag_print)(char*), const char *errprefix);
 | 
			
		||||
extern MSLogParam *ms_loginit_l (MSLogParam *logp,
 | 
			
		||||
			         void (*log_print)(char*), const char *logprefix,
 | 
			
		||||
			         void (*diag_print)(char*), const char *errprefix);
 | 
			
		||||
 | 
			
		||||
/* Selection functions */
 | 
			
		||||
extern Selections *ms_matchselect (Selections *selections, char *srcname,
 | 
			
		||||
				   hptime_t starttime, hptime_t endtime, SelectTime **ppselecttime);
 | 
			
		||||
extern Selections *msr_matchselect (Selections *selections, MSRecord *msr, SelectTime **ppselecttime);
 | 
			
		||||
extern int      ms_addselect (Selections **ppselections, char *srcname,
 | 
			
		||||
			      hptime_t starttime, hptime_t endtime);
 | 
			
		||||
extern int      ms_addselect_comp (Selections **ppselections, char *net, char* sta, char *loc,
 | 
			
		||||
				   char *chan, char *qual, hptime_t starttime, hptime_t endtime);
 | 
			
		||||
extern int      ms_readselectionsfile (Selections **ppselections, char *filename);
 | 
			
		||||
extern void     ms_freeselections (Selections *selections);
 | 
			
		||||
extern void     ms_printselections (Selections *selections);
 | 
			
		||||
 | 
			
		||||
/* Generic byte swapping routines */
 | 
			
		||||
extern void     ms_gswap2 ( void *data2 );
 | 
			
		||||
extern void     ms_gswap3 ( void *data3 );
 | 
			
		||||
extern void     ms_gswap4 ( void *data4 );
 | 
			
		||||
extern void     ms_gswap8 ( void *data8 );
 | 
			
		||||
 | 
			
		||||
/* Generic byte swapping routines for memory aligned quantities */
 | 
			
		||||
extern void     ms_gswap2a ( void *data2 );
 | 
			
		||||
extern void     ms_gswap4a ( void *data4 );
 | 
			
		||||
extern void     ms_gswap8a ( void *data8 );
 | 
			
		||||
 | 
			
		||||
/* Byte swap macro for the BTime struct */
 | 
			
		||||
#define MS_SWAPBTIME(x) \
 | 
			
		||||
  ms_gswap2 (x.year);   \
 | 
			
		||||
  ms_gswap2 (x.day);    \
 | 
			
		||||
  ms_gswap2 (x.fract);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* LIBMSEED_H */
 | 
			
		||||
							
								
								
									
										65
									
								
								libs/3rd-party/mseed/lmplatform.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								libs/3rd-party/mseed/lmplatform.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * lmplatform.c:
 | 
			
		||||
 * 
 | 
			
		||||
 * Platform portability routines.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Library General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Library General Public License (GNU-LGPL) for more details.  The
 | 
			
		||||
 * GNU-LGPL and further information can be found here:
 | 
			
		||||
 * http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * Written by Chad Trabant, IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2010.304
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Define _LARGEFILE_SOURCE to get ftello/fseeko on some systems (Linux) */
 | 
			
		||||
#define _LARGEFILE_SOURCE 1
 | 
			
		||||
 | 
			
		||||
#include "lmplatform.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * lmp_ftello:
 | 
			
		||||
 *
 | 
			
		||||
 * Return the current file position for the specified descriptor using
 | 
			
		||||
 * the system's closest match to the POSIX ftello.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
off_t
 | 
			
		||||
lmp_ftello (FILE *stream)
 | 
			
		||||
{
 | 
			
		||||
#if defined(LMP_WIN32)
 | 
			
		||||
  return (off_t) ftell (stream);
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
  return (off_t) ftello (stream);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
}  /* End of lmp_ftello() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * lmp_fseeko:
 | 
			
		||||
 *
 | 
			
		||||
 * Seek to a specific file position for the specified descriptor using
 | 
			
		||||
 * the system's closest match to the POSIX fseeko.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
lmp_fseeko (FILE *stream, off_t offset, int whence)
 | 
			
		||||
{
 | 
			
		||||
#if defined(LMP_WIN32)
 | 
			
		||||
  return (int) fseek (stream, (long int) offset, whence);
 | 
			
		||||
  
 | 
			
		||||
#else
 | 
			
		||||
  return (int) fseeko (stream, offset, whence);
 | 
			
		||||
  
 | 
			
		||||
#endif
 | 
			
		||||
}  /* End of lmp_fseeko() */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										166
									
								
								libs/3rd-party/mseed/lmplatform.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								libs/3rd-party/mseed/lmplatform.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,166 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * lmplatform.h:
 | 
			
		||||
 * 
 | 
			
		||||
 * Platform specific headers.  This file provides a basic level of platform
 | 
			
		||||
 * portability.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Library General Public License
 | 
			
		||||
 * as published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 * the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Library General Public License (GNU-LGPL) for more details.  The
 | 
			
		||||
 * GNU-LGPL and further information can be found here:
 | 
			
		||||
 * http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * Written by Chad Trabant, IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2014.074
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef LMPLATFORM_H
 | 
			
		||||
#define LMPLATFORM_H 1
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* On some platforms (e.g. ARM) structures are aligned on word boundaries
 | 
			
		||||
     by adding padding between the elements.  This library uses structs that
 | 
			
		||||
     map to SEED header/blockette structures that are required to have a
 | 
			
		||||
     layout exactly as specified, i.e. no padding.
 | 
			
		||||
 | 
			
		||||
     If "ATTRIBUTE_PACKED" is defined at compile time (e.g. -DATTRIBUTE_PACKED)
 | 
			
		||||
     the preprocessor will use the define below to add the "packed" attribute 
 | 
			
		||||
     to effected structs.  This attribute is supported by GCC and increasingly
 | 
			
		||||
     more compilers.
 | 
			
		||||
  */
 | 
			
		||||
#if defined(ATTRIBUTE_PACKED)
 | 
			
		||||
  #define LMP_PACKED __attribute__((packed))
 | 
			
		||||
#else
 | 
			
		||||
  #define LMP_PACKED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  /* Make some guesses about the system libraries based
 | 
			
		||||
   * on the architecture.  Currently the assumptions are:
 | 
			
		||||
   * Linux => glibc2 libraries (LMP_GLIBC2)
 | 
			
		||||
   * Sun => Solaris libraties (LMP_SOLARIS)
 | 
			
		||||
   * BSD => BSD libraries, including Apple Mac OS X (LMP_BSD)
 | 
			
		||||
   * WIN32 => WIN32 and Windows Sockets 2 (LMP_WIN32)
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
#if defined(__linux__) || defined(__linux) || defined(__CYGWIN__)
 | 
			
		||||
  #define LMP_GLIBC2 1
 | 
			
		||||
 | 
			
		||||
  #include <stdlib.h>
 | 
			
		||||
  #include <stdio.h>
 | 
			
		||||
  #include <unistd.h>
 | 
			
		||||
  #include <stdarg.h>
 | 
			
		||||
  #include <inttypes.h>
 | 
			
		||||
  #include <sys/socket.h>
 | 
			
		||||
  #include <netinet/in.h>
 | 
			
		||||
  #include <netdb.h>
 | 
			
		||||
  #include <sys/time.h>
 | 
			
		||||
  #include <string.h>
 | 
			
		||||
  #include <ctype.h>
 | 
			
		||||
  #include <features.h>
 | 
			
		||||
  
 | 
			
		||||
#elif defined(__sun__) || defined(__sun)
 | 
			
		||||
  #define LMP_SOLARIS 1
 | 
			
		||||
 | 
			
		||||
  #include <stdlib.h>
 | 
			
		||||
  #include <stdio.h>
 | 
			
		||||
  #include <unistd.h>
 | 
			
		||||
  #include <stdarg.h>
 | 
			
		||||
  #include <inttypes.h>
 | 
			
		||||
  #include <sys/socket.h>
 | 
			
		||||
  #include <netinet/in.h>
 | 
			
		||||
  #include <netdb.h>
 | 
			
		||||
  #include <sys/time.h>
 | 
			
		||||
  #include <string.h>
 | 
			
		||||
  #include <ctype.h>
 | 
			
		||||
  
 | 
			
		||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
 | 
			
		||||
  #define LMP_BSD 1
 | 
			
		||||
 | 
			
		||||
  #include <stdlib.h>
 | 
			
		||||
  #include <stdio.h>
 | 
			
		||||
  #include <unistd.h>
 | 
			
		||||
  #include <stdarg.h>
 | 
			
		||||
  #include <inttypes.h>
 | 
			
		||||
  #include <sys/socket.h>
 | 
			
		||||
  #include <netinet/in.h>
 | 
			
		||||
  #include <netdb.h>
 | 
			
		||||
  #include <sys/time.h>
 | 
			
		||||
  #include <string.h>
 | 
			
		||||
  #include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#elif defined(WIN32) || defined(WIN64)
 | 
			
		||||
  #define LMP_WIN32 1
 | 
			
		||||
 | 
			
		||||
  #include <windows.h>
 | 
			
		||||
  #include <stdarg.h>
 | 
			
		||||
  #include <winsock.h>
 | 
			
		||||
  #include <stdio.h>
 | 
			
		||||
  #include <sys/types.h>
 | 
			
		||||
  #include <ctype.h>
 | 
			
		||||
 | 
			
		||||
  #if defined(_MSC_VER)
 | 
			
		||||
    #define snprintf _snprintf
 | 
			
		||||
    #define vsnprintf _vsnprintf
 | 
			
		||||
    #define strcasecmp _stricmp
 | 
			
		||||
    #define strncasecmp _strnicmp
 | 
			
		||||
    #define strtoull _strtoui64
 | 
			
		||||
    #define strdup _strdup
 | 
			
		||||
    #define fileno _fileno
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if defined(__MINGW32__) 
 | 
			
		||||
    #define fstat _fstat 
 | 
			
		||||
    #define stat _stat 
 | 
			
		||||
  #endif 
 | 
			
		||||
 | 
			
		||||
  typedef signed char int8_t;
 | 
			
		||||
  typedef unsigned char uint8_t;
 | 
			
		||||
  typedef signed short int int16_t;
 | 
			
		||||
  typedef unsigned short int uint16_t;
 | 
			
		||||
  typedef signed int int32_t;
 | 
			
		||||
  typedef unsigned int uint32_t;
 | 
			
		||||
  typedef signed __int64 int64_t;
 | 
			
		||||
  typedef unsigned __int64 uint64_t;
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
  #include <stdlib.h>
 | 
			
		||||
  #include <stdio.h>
 | 
			
		||||
  #include <unistd.h>
 | 
			
		||||
  #include <stdarg.h>
 | 
			
		||||
  #include <inttypes.h>
 | 
			
		||||
  #include <sys/socket.h>
 | 
			
		||||
  #include <netinet/in.h>
 | 
			
		||||
  #include <netdb.h>
 | 
			
		||||
  #include <sys/time.h>
 | 
			
		||||
  #include <string.h>
 | 
			
		||||
  #include <ctype.h>
 | 
			
		||||
 | 
			
		||||
  typedef signed char int8_t;
 | 
			
		||||
  typedef unsigned char uint8_t;
 | 
			
		||||
  typedef signed short int int16_t;
 | 
			
		||||
  typedef unsigned short int uint16_t;
 | 
			
		||||
  typedef signed int int32_t;
 | 
			
		||||
  typedef unsigned int uint32_t;
 | 
			
		||||
  typedef signed long long int64_t;
 | 
			
		||||
  typedef unsigned long long uint64_t;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern off_t lmp_ftello (FILE *stream);
 | 
			
		||||
extern int lmp_fseeko (FILE *stream, off_t offset, int whence);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
#endif /* LMPLATFORM_H */
 | 
			
		||||
							
								
								
									
										334
									
								
								libs/3rd-party/mseed/logging.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								libs/3rd-party/mseed/logging.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,334 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * logging.c
 | 
			
		||||
 *
 | 
			
		||||
 * Log handling routines for libmseed
 | 
			
		||||
 *
 | 
			
		||||
 * Chad Trabant
 | 
			
		||||
 * IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2014.197
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "libmseed.h"
 | 
			
		||||
 | 
			
		||||
void ms_loginit_main (MSLogParam *logp,
 | 
			
		||||
		      void (*log_print)(char*), const char *logprefix,
 | 
			
		||||
		      void (*diag_print)(char*), const char *errprefix);
 | 
			
		||||
 | 
			
		||||
int ms_log_main (MSLogParam *logp, int level, va_list *varlist);
 | 
			
		||||
 | 
			
		||||
/* Initialize the global logging parameters */
 | 
			
		||||
MSLogParam gMSLogParam = {NULL, NULL, NULL, NULL};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_loginit:
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize the global logging parameters.
 | 
			
		||||
 *
 | 
			
		||||
 * See ms_loginit_main() description for usage.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
void
 | 
			
		||||
ms_loginit (void (*log_print)(char*), const char *logprefix,
 | 
			
		||||
	    void (*diag_print)(char*), const char *errprefix)
 | 
			
		||||
{
 | 
			
		||||
  ms_loginit_main(&gMSLogParam, log_print, logprefix, diag_print, errprefix);
 | 
			
		||||
}  /* End of ms_loginit() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_loginit_l:
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize MSLogParam specific logging parameters.  If the logging parameters
 | 
			
		||||
 * have not been initialized (log == NULL) new parameter space will
 | 
			
		||||
 * be allocated.
 | 
			
		||||
 *
 | 
			
		||||
 * See ms_loginit_main() description for usage.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns a pointer to the created/re-initialized MSLogParam struct
 | 
			
		||||
 * on success and NULL on error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
MSLogParam *
 | 
			
		||||
ms_loginit_l (MSLogParam *logp,
 | 
			
		||||
	      void (*log_print)(char*), const char *logprefix,
 | 
			
		||||
	      void (*diag_print)(char*), const char *errprefix)
 | 
			
		||||
{
 | 
			
		||||
  MSLogParam *llog;
 | 
			
		||||
  
 | 
			
		||||
  if ( logp == NULL )
 | 
			
		||||
    {
 | 
			
		||||
      llog = (MSLogParam *) malloc (sizeof(MSLogParam));
 | 
			
		||||
      
 | 
			
		||||
      if ( llog == NULL )
 | 
			
		||||
        {
 | 
			
		||||
          ms_log (2, "ms_loginit_l(): Cannot allocate memory\n");
 | 
			
		||||
          return NULL;
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
      llog->log_print = NULL;
 | 
			
		||||
      llog->logprefix = NULL;
 | 
			
		||||
      llog->diag_print = NULL;
 | 
			
		||||
      llog->errprefix = NULL;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      llog = logp;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  ms_loginit_main (llog, log_print, logprefix, diag_print, errprefix);
 | 
			
		||||
 | 
			
		||||
  return llog;
 | 
			
		||||
}  /* End of ms_loginit_l() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_loginit_main:
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize the logging subsystem.  Given values determine how ms_log()
 | 
			
		||||
 * and ms_log_l() emit messages.
 | 
			
		||||
 *
 | 
			
		||||
 * This function modifies the logging parameters in the passed MSLogParam.
 | 
			
		||||
 *
 | 
			
		||||
 * Any log/error printing functions indicated must except a single
 | 
			
		||||
 * argument, namely a string (char *).  The ms_log() and
 | 
			
		||||
 * ms_log_r() functions format each message and then pass the result
 | 
			
		||||
 * on to the log/error printing functions.
 | 
			
		||||
 *
 | 
			
		||||
 * If the log/error prefixes have been set they will be pre-pended to the
 | 
			
		||||
 * message.
 | 
			
		||||
 *
 | 
			
		||||
 * Use NULL for the function pointers or the prefixes if they should not
 | 
			
		||||
 * be changed from previously set or default values.  The default behavior
 | 
			
		||||
 * of the logging subsystem is given in the example below.
 | 
			
		||||
 *
 | 
			
		||||
 * Example: ms_loginit_main (0, (void*)&printf, NULL, (void*)&printf, "error: ");
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
void
 | 
			
		||||
ms_loginit_main (MSLogParam *logp,
 | 
			
		||||
		 void (*log_print)(char*), const char *logprefix,
 | 
			
		||||
		 void (*diag_print)(char*), const char *errprefix)
 | 
			
		||||
{
 | 
			
		||||
  if ( ! logp )
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  if ( log_print )
 | 
			
		||||
    logp->log_print = log_print;
 | 
			
		||||
  
 | 
			
		||||
  if ( logprefix )
 | 
			
		||||
    {
 | 
			
		||||
      if ( strlen(logprefix) >= MAX_LOG_MSG_LENGTH )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log_l (logp, 2, 0, "log message prefix is too large\n");
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  logp->logprefix = logprefix;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if ( diag_print )
 | 
			
		||||
    logp->diag_print = diag_print;
 | 
			
		||||
  
 | 
			
		||||
  if ( errprefix )
 | 
			
		||||
    {
 | 
			
		||||
      if ( strlen(errprefix) >= MAX_LOG_MSG_LENGTH )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log_l (logp, 2, 0, "error message prefix is too large\n");
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  logp->errprefix = errprefix;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return;
 | 
			
		||||
}  /* End of ms_loginit_main() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_log:
 | 
			
		||||
 *
 | 
			
		||||
 * A wrapper to ms_log_main() that uses the global logging parameters.
 | 
			
		||||
 *
 | 
			
		||||
 * See ms_log_main() description for return values.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
ms_log (int level, ...)
 | 
			
		||||
{
 | 
			
		||||
  int retval;
 | 
			
		||||
  va_list varlist;
 | 
			
		||||
  
 | 
			
		||||
  va_start (varlist, level);
 | 
			
		||||
 | 
			
		||||
  retval = ms_log_main (&gMSLogParam, level, &varlist);
 | 
			
		||||
 | 
			
		||||
  va_end (varlist);
 | 
			
		||||
 | 
			
		||||
  return retval;
 | 
			
		||||
}  /* End of ms_log() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_log_l:
 | 
			
		||||
 *
 | 
			
		||||
 * A wrapper to ms_log_main() that uses the logging parameters in a
 | 
			
		||||
 * supplied MSLogParam.  If the supplied pointer is NULL the global logging
 | 
			
		||||
 * parameters will be used.
 | 
			
		||||
 *
 | 
			
		||||
 * See ms_log_main() description for return values.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
ms_log_l (MSLogParam *logp, int level, ...)
 | 
			
		||||
{
 | 
			
		||||
  int retval;
 | 
			
		||||
  va_list varlist;
 | 
			
		||||
  MSLogParam *llog;
 | 
			
		||||
 | 
			
		||||
  if ( ! logp )
 | 
			
		||||
    llog = &gMSLogParam;
 | 
			
		||||
  else
 | 
			
		||||
    llog = logp;
 | 
			
		||||
  
 | 
			
		||||
  va_start (varlist, level);
 | 
			
		||||
  
 | 
			
		||||
  retval = ms_log_main (llog, level, &varlist);
 | 
			
		||||
 | 
			
		||||
  va_end (varlist);
 | 
			
		||||
 | 
			
		||||
  return retval;
 | 
			
		||||
}  /* End of ms_log_l() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_log_main:
 | 
			
		||||
 *
 | 
			
		||||
 * A standard logging/printing routine.
 | 
			
		||||
 *
 | 
			
		||||
 * The function uses logging parameters specified in the supplied
 | 
			
		||||
 * MSLogParam.
 | 
			
		||||
 * 
 | 
			
		||||
 * This function expects 2+ arguments: message level, fprintf format,
 | 
			
		||||
 * and fprintf arguments. 
 | 
			
		||||
 *
 | 
			
		||||
 * Three levels are recognized:
 | 
			
		||||
 * 0  : Normal log messages, printed using log_print with logprefix
 | 
			
		||||
 * 1  : Diagnostic messages, printed using diag_print with logprefix
 | 
			
		||||
 * 2+ : Error messagess, printed using diag_print with errprefix
 | 
			
		||||
 *
 | 
			
		||||
 * This function builds the log/error message and passes to it as a
 | 
			
		||||
 * string (char *) to the functions defined with ms_loginit() or
 | 
			
		||||
 * ms_loginit_l().  If the log/error printing functions have not been
 | 
			
		||||
 * defined messages will be printed with fprintf, log messages to
 | 
			
		||||
 * stdout and error messages to stderr.
 | 
			
		||||
 *
 | 
			
		||||
 * If the log/error prefix's have been set with ms_loginit() or
 | 
			
		||||
 * ms_loginit_l() they will be pre-pended to the message.
 | 
			
		||||
 *
 | 
			
		||||
 * All messages will be truncated to the MAX_LOG_MSG_LENGTH, this includes
 | 
			
		||||
 * any set prefix.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the number of characters formatted on success, and a
 | 
			
		||||
 * a negative value on error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
ms_log_main (MSLogParam *logp, int level, va_list *varlist)
 | 
			
		||||
{
 | 
			
		||||
  static char message[MAX_LOG_MSG_LENGTH];
 | 
			
		||||
  int retvalue = 0;
 | 
			
		||||
  int presize;
 | 
			
		||||
  const char *format;
 | 
			
		||||
  
 | 
			
		||||
  if ( ! logp )
 | 
			
		||||
    {
 | 
			
		||||
      fprintf(stderr, "ms_log_main() called without specifying log parameters");
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  message[0] = '\0';
 | 
			
		||||
 | 
			
		||||
  format = va_arg (*varlist, const char *);
 | 
			
		||||
 | 
			
		||||
  if ( level >= 2 )  /* Error message */
 | 
			
		||||
    {
 | 
			
		||||
      if ( logp->errprefix != NULL )
 | 
			
		||||
        {
 | 
			
		||||
          strncpy (message, logp->errprefix, MAX_LOG_MSG_LENGTH);
 | 
			
		||||
          message[MAX_LOG_MSG_LENGTH - 1] = '\0';
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          strncpy (message, "Error: ", MAX_LOG_MSG_LENGTH);
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
      presize = strlen(message);
 | 
			
		||||
      retvalue = vsnprintf (&message[presize],
 | 
			
		||||
   			    MAX_LOG_MSG_LENGTH - presize,
 | 
			
		||||
			    format, *varlist);
 | 
			
		||||
      
 | 
			
		||||
      message[MAX_LOG_MSG_LENGTH - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
      if ( logp->diag_print != NULL )
 | 
			
		||||
        {
 | 
			
		||||
          logp->diag_print (message);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          fprintf(stderr, "%s", message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if ( level == 1 )  /* Diagnostic message */
 | 
			
		||||
    {
 | 
			
		||||
      if ( logp->logprefix != NULL )
 | 
			
		||||
        {
 | 
			
		||||
          strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
 | 
			
		||||
          message[MAX_LOG_MSG_LENGTH - 1] = '\0';
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
      presize = strlen(message);
 | 
			
		||||
      retvalue = vsnprintf (&message[presize],
 | 
			
		||||
		            MAX_LOG_MSG_LENGTH - presize,
 | 
			
		||||
			    format, *varlist);
 | 
			
		||||
      
 | 
			
		||||
      message[MAX_LOG_MSG_LENGTH - 1] = '\0';
 | 
			
		||||
      
 | 
			
		||||
      if ( logp->diag_print != NULL )
 | 
			
		||||
        {
 | 
			
		||||
          logp->diag_print (message);
 | 
			
		||||
        }
 | 
			
		||||
      else
 | 
			
		||||
        {
 | 
			
		||||
          fprintf(stderr, "%s", message);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
  else if ( level == 0 )  /* Normal log message */
 | 
			
		||||
    {
 | 
			
		||||
      if ( logp->logprefix != NULL )
 | 
			
		||||
        {
 | 
			
		||||
          strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
 | 
			
		||||
          message[MAX_LOG_MSG_LENGTH - 1] = '\0';
 | 
			
		||||
        }
 | 
			
		||||
      
 | 
			
		||||
      presize = strlen(message);
 | 
			
		||||
      retvalue = vsnprintf (&message[presize],
 | 
			
		||||
			    MAX_LOG_MSG_LENGTH - presize,
 | 
			
		||||
			    format, *varlist);
 | 
			
		||||
      
 | 
			
		||||
      message[MAX_LOG_MSG_LENGTH - 1] = '\0';
 | 
			
		||||
      
 | 
			
		||||
      if ( logp->log_print != NULL )
 | 
			
		||||
	{
 | 
			
		||||
           logp->log_print (message);
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  fprintf(stdout, "%s", message);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return retvalue;
 | 
			
		||||
}  /* End of ms_log_main() */
 | 
			
		||||
							
								
								
									
										235
									
								
								libs/3rd-party/mseed/lookup.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								libs/3rd-party/mseed/lookup.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,235 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * lookup.c:
 | 
			
		||||
 *
 | 
			
		||||
 * Generic lookup routines for Mini-SEED information.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by Chad Trabant, ORFEUS/EC-Project MEREDIAN
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2006.346
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "libmseed.h"
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_samplesize():
 | 
			
		||||
 * 
 | 
			
		||||
 * Returns the sample size based on type code or 0 for unknown.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
uint8_t
 | 
			
		||||
ms_samplesize (const char sampletype)
 | 
			
		||||
{
 | 
			
		||||
  switch (sampletype)
 | 
			
		||||
    {
 | 
			
		||||
    case 'a':
 | 
			
		||||
      return 1;
 | 
			
		||||
    case 'i':
 | 
			
		||||
    case 'f':
 | 
			
		||||
      return 4;
 | 
			
		||||
    case 'd':
 | 
			
		||||
      return 8;
 | 
			
		||||
    default:
 | 
			
		||||
      return 0;
 | 
			
		||||
    }  /* end switch */
 | 
			
		||||
  
 | 
			
		||||
}  /* End of ms_samplesize() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_encodingstr():
 | 
			
		||||
 * 
 | 
			
		||||
 * Returns a string describing a data encoding format.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
char *
 | 
			
		||||
ms_encodingstr (const char encoding)
 | 
			
		||||
{
 | 
			
		||||
  switch (encoding)
 | 
			
		||||
    {
 | 
			
		||||
    case 0:
 | 
			
		||||
      return "ASCII text";
 | 
			
		||||
    case 1:
 | 
			
		||||
      return "16 bit integers";
 | 
			
		||||
    case 2:
 | 
			
		||||
      return "24 bit integers";
 | 
			
		||||
    case 3:
 | 
			
		||||
      return "32 bit integers";
 | 
			
		||||
    case 4:
 | 
			
		||||
      return "IEEE floating point";
 | 
			
		||||
    case 5:
 | 
			
		||||
      return "IEEE double precision float";
 | 
			
		||||
    case 10:
 | 
			
		||||
      return "STEIM 1 Compression";
 | 
			
		||||
    case 11:
 | 
			
		||||
      return "STEIM 2 Compression";
 | 
			
		||||
    case 12:
 | 
			
		||||
      return "GEOSCOPE Muxed 24 bit int";
 | 
			
		||||
    case 13:
 | 
			
		||||
      return "GEOSCOPE Muxed 16/3 bit gain/exp";
 | 
			
		||||
    case 14:
 | 
			
		||||
      return "GEOSCOPE Muxed 16/4 bit gain/exp";
 | 
			
		||||
    case 15:
 | 
			
		||||
      return "US National Network compression";
 | 
			
		||||
    case 16:
 | 
			
		||||
      return "CDSN 16 bit gain ranged";
 | 
			
		||||
    case 17:
 | 
			
		||||
      return "Graefenberg 16 bit gain ranged";
 | 
			
		||||
    case 18:
 | 
			
		||||
      return "IPG - Strasbourg 16 bit gain";
 | 
			
		||||
    case 19:
 | 
			
		||||
      return "STEIM 3 Compression";
 | 
			
		||||
    case 30:
 | 
			
		||||
      return "SRO Gain Ranged Format";
 | 
			
		||||
    case 31:
 | 
			
		||||
      return "HGLP Format";
 | 
			
		||||
    case 32:
 | 
			
		||||
      return "DWWSSN Format";
 | 
			
		||||
    case 33:
 | 
			
		||||
      return "RSTN 16 bit gain ranged";
 | 
			
		||||
    default:
 | 
			
		||||
      return "Unknown format code";
 | 
			
		||||
    }  /* end switch */
 | 
			
		||||
 | 
			
		||||
}  /* End of ms_encodingstr() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_blktdesc():
 | 
			
		||||
 *
 | 
			
		||||
 * Return a string describing a given blockette type or NULL if the
 | 
			
		||||
 * type is unknown.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
char *
 | 
			
		||||
ms_blktdesc (uint16_t blkttype)
 | 
			
		||||
{
 | 
			
		||||
  switch (blkttype)
 | 
			
		||||
    {
 | 
			
		||||
    case 100:
 | 
			
		||||
      return "Sample Rate";
 | 
			
		||||
    case 200:
 | 
			
		||||
      return "Generic Event Detection";
 | 
			
		||||
    case 201:
 | 
			
		||||
      return "Murdock Event Detection";
 | 
			
		||||
    case 300:
 | 
			
		||||
      return "Step Calibration";
 | 
			
		||||
    case 310:
 | 
			
		||||
      return "Sine Calibration";
 | 
			
		||||
    case 320:
 | 
			
		||||
      return "Pseudo-random Calibration";
 | 
			
		||||
    case 390:
 | 
			
		||||
      return "Generic Calibration";
 | 
			
		||||
    case 395:
 | 
			
		||||
      return "Calibration Abort";
 | 
			
		||||
    case 400:
 | 
			
		||||
      return "Beam";
 | 
			
		||||
    case 500:
 | 
			
		||||
      return "Timing";
 | 
			
		||||
    case 1000:
 | 
			
		||||
      return "Data Only SEED";
 | 
			
		||||
    case 1001:
 | 
			
		||||
      return "Data Extension";
 | 
			
		||||
    case 2000:
 | 
			
		||||
      return "Opaque Data";
 | 
			
		||||
    }  /* end switch */
 | 
			
		||||
 | 
			
		||||
  return NULL;
 | 
			
		||||
  
 | 
			
		||||
}  /* End of ms_blktdesc() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_blktlen():
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the total length of a given blockette type in bytes or 0 if
 | 
			
		||||
 * type unknown.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
uint16_t
 | 
			
		||||
ms_blktlen (uint16_t blkttype, const char *blkt, flag swapflag)
 | 
			
		||||
{
 | 
			
		||||
  uint16_t blktlen = 0;
 | 
			
		||||
  
 | 
			
		||||
  switch (blkttype)
 | 
			
		||||
    {
 | 
			
		||||
    case 100:  /* Sample Rate */
 | 
			
		||||
      blktlen = 12;
 | 
			
		||||
      break;
 | 
			
		||||
    case 200:  /* Generic Event Detection */
 | 
			
		||||
      blktlen = 28;
 | 
			
		||||
      break;
 | 
			
		||||
    case 201:  /* Murdock Event Detection */
 | 
			
		||||
      blktlen = 36;
 | 
			
		||||
      break;
 | 
			
		||||
    case 300:  /* Step Calibration */
 | 
			
		||||
      blktlen = 32;
 | 
			
		||||
      break;
 | 
			
		||||
    case 310:  /* Sine Calibration */
 | 
			
		||||
      blktlen = 32;
 | 
			
		||||
      break;
 | 
			
		||||
    case 320:  /* Pseudo-random Calibration */
 | 
			
		||||
      blktlen = 28;
 | 
			
		||||
      break;
 | 
			
		||||
    case 390:  /* Generic Calibration */
 | 
			
		||||
      blktlen = 28;
 | 
			
		||||
      break;
 | 
			
		||||
    case 395:  /* Calibration Abort */
 | 
			
		||||
      blktlen = 16;
 | 
			
		||||
      break;
 | 
			
		||||
    case 400:  /* Beam */
 | 
			
		||||
      blktlen = 16;
 | 
			
		||||
      break;
 | 
			
		||||
    case 500:  /* Timing */
 | 
			
		||||
      blktlen = 8;
 | 
			
		||||
      break;
 | 
			
		||||
    case 1000: /* Data Only SEED */
 | 
			
		||||
      blktlen = 8;
 | 
			
		||||
      break;
 | 
			
		||||
    case 1001: /* Data Extension */
 | 
			
		||||
      blktlen = 8;
 | 
			
		||||
      break;
 | 
			
		||||
    case 2000: /* Opaque Data */
 | 
			
		||||
      /* First 2-byte field after the blockette header is the length */
 | 
			
		||||
      if ( blkt )
 | 
			
		||||
	{
 | 
			
		||||
	  memcpy ((void *) &blktlen, blkt+4, sizeof (int16_t));
 | 
			
		||||
	  if ( swapflag ) ms_gswap2 (&blktlen);
 | 
			
		||||
	}
 | 
			
		||||
      break;
 | 
			
		||||
    }  /* end switch */
 | 
			
		||||
  
 | 
			
		||||
  return blktlen;
 | 
			
		||||
  
 | 
			
		||||
}  /* End of ms_blktlen() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_errorstr():
 | 
			
		||||
 *
 | 
			
		||||
 * Return a string describing a given libmseed error code or NULL if the
 | 
			
		||||
 * code is unknown.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
char *
 | 
			
		||||
ms_errorstr (int errorcode)
 | 
			
		||||
{
 | 
			
		||||
  switch (errorcode)
 | 
			
		||||
    {
 | 
			
		||||
    case MS_ENDOFFILE:
 | 
			
		||||
      return "End of file reached";
 | 
			
		||||
    case MS_NOERROR:
 | 
			
		||||
      return "No error";
 | 
			
		||||
    case MS_GENERROR:
 | 
			
		||||
      return "Generic error";
 | 
			
		||||
    case MS_NOTSEED:
 | 
			
		||||
      return "No SEED data detected";
 | 
			
		||||
    case MS_WRONGLENGTH:
 | 
			
		||||
      return "Length of data read does not match record length";
 | 
			
		||||
    case MS_OUTOFRANGE:
 | 
			
		||||
      return "SEED record length out of range";
 | 
			
		||||
    case MS_UNKNOWNFORMAT:
 | 
			
		||||
      return "Unknown data encoding format";
 | 
			
		||||
    case MS_STBADCOMPFLAG:
 | 
			
		||||
      return "Bad Steim compression flag(s) detected";
 | 
			
		||||
    }				/* end switch */
 | 
			
		||||
  
 | 
			
		||||
  return NULL;
 | 
			
		||||
 | 
			
		||||
}  /* End of ms_blktdesc() */
 | 
			
		||||
							
								
								
									
										1179
									
								
								libs/3rd-party/mseed/msrutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1179
									
								
								libs/3rd-party/mseed/msrutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1065
									
								
								libs/3rd-party/mseed/pack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1065
									
								
								libs/3rd-party/mseed/pack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										699
									
								
								libs/3rd-party/mseed/packdata.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										699
									
								
								libs/3rd-party/mseed/packdata.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,699 @@
 | 
			
		||||
/***********************************************************************
 | 
			
		||||
 *  Routines for packing INT_32, INT_16, FLOAT_32, FLOAT_64,
 | 
			
		||||
 *  STEIM1 and STEIM2 data records.
 | 
			
		||||
 *
 | 
			
		||||
 *	Douglas Neuhauser						
 | 
			
		||||
 *	Seismological Laboratory					
 | 
			
		||||
 *	University of California, Berkeley				
 | 
			
		||||
 *	doug@seismo.berkeley.edu					
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * modified Aug 2008:
 | 
			
		||||
 *  - Optimize Steim 1 & 2 packing routines using small, re-used buffers.
 | 
			
		||||
 *
 | 
			
		||||
 * modified Sep 2004:
 | 
			
		||||
 *  - Reworked and cleaned routines for use within libmseed.
 | 
			
		||||
 *  - Added float32 and float64 packing routines.
 | 
			
		||||
 *
 | 
			
		||||
 * Modified by Chad Trabant, IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2009.111
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 1996-2004 The Regents of the University of California.
 | 
			
		||||
 * All Rights Reserved.
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission to use, copy, modify, and distribute this software and its
 | 
			
		||||
 * documentation for educational, research and non-profit purposes,
 | 
			
		||||
 * without fee, and without a written agreement is hereby granted,
 | 
			
		||||
 * provided that the above copyright notice, this paragraph and the
 | 
			
		||||
 * following three paragraphs appear in all copies.
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission to incorporate this software into commercial products may
 | 
			
		||||
 * be obtained from the Office of Technology Licensing, 2150 Shattuck
 | 
			
		||||
 * Avenue, Suite 510, Berkeley, CA  94704.
 | 
			
		||||
 * 
 | 
			
		||||
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 | 
			
		||||
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
 | 
			
		||||
 * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
 | 
			
		||||
 * ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN
 | 
			
		||||
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE
 | 
			
		||||
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 | 
			
		||||
 * CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 | 
			
		||||
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <memory.h>
 | 
			
		||||
 | 
			
		||||
#include "libmseed.h"
 | 
			
		||||
#include "packdata.h"
 | 
			
		||||
 | 
			
		||||
static int pad_steim_frame (DFRAMES*, int, int, int, int, int);
 | 
			
		||||
 | 
			
		||||
#define	EMPTY_BLOCK(fn,wn) (fn+wn == 0)
 | 
			
		||||
 | 
			
		||||
#define	X0  dframes->f[0].w[0].fw
 | 
			
		||||
#define	XN  dframes->f[0].w[1].fw
 | 
			
		||||
 | 
			
		||||
#define	BIT4PACK(i,points_remaining)		   \
 | 
			
		||||
  (points_remaining >= 7 &&			   \
 | 
			
		||||
   (minbits[i] <= 4) && (minbits[i+1] <= 4) &&	   \
 | 
			
		||||
   (minbits[i+2] <= 4) && (minbits[i+3] <= 4) &&   \
 | 
			
		||||
   (minbits[i+4] <= 4) && (minbits[i+5] <= 4) &&   \
 | 
			
		||||
   (minbits[i+6] <= 4))
 | 
			
		||||
 | 
			
		||||
#define	BIT5PACK(i,points_remaining)		   \
 | 
			
		||||
  (points_remaining >= 6 &&			   \
 | 
			
		||||
   (minbits[i] <= 5) && (minbits[i+1] <= 5) &&	   \
 | 
			
		||||
   (minbits[i+2] <= 5) && (minbits[i+3] <= 5) &&   \
 | 
			
		||||
   (minbits[i+4] <= 5) && (minbits[i+5] <= 5))
 | 
			
		||||
 | 
			
		||||
#define	BIT6PACK(i,points_remaining)		   \
 | 
			
		||||
  (points_remaining >= 5 &&			   \
 | 
			
		||||
   (minbits[i] <= 6) && (minbits[i+1] <= 6) &&	   \
 | 
			
		||||
   (minbits[i+2] <= 6) && (minbits[i+3] <= 6) &&   \
 | 
			
		||||
   (minbits[i+4] <= 6))
 | 
			
		||||
 | 
			
		||||
#define	BYTEPACK(i,points_remaining)		 \
 | 
			
		||||
  (points_remaining >= 4 &&			 \
 | 
			
		||||
   (minbits[i] <= 8) && (minbits[i+1] <= 8) &&	 \
 | 
			
		||||
   (minbits[i+2] <= 8) && (minbits[i+3] <= 8))
 | 
			
		||||
 | 
			
		||||
#define	BIT10PACK(i,points_remaining)		   \
 | 
			
		||||
  (points_remaining >= 3 &&			   \
 | 
			
		||||
   (minbits[i] <= 10) && (minbits[i+1] <= 10) &&   \
 | 
			
		||||
   (minbits[i+2] <= 10))
 | 
			
		||||
 | 
			
		||||
#define	BIT15PACK(i,points_remaining)		\
 | 
			
		||||
  (points_remaining >= 2 &&			\
 | 
			
		||||
   (minbits[i] <= 15) && (minbits[i+1] <= 15))
 | 
			
		||||
 | 
			
		||||
#define	HALFPACK(i,points_remaining)					\
 | 
			
		||||
  (points_remaining >= 2 && (minbits[i] <= 16) && (minbits[i+1] <= 16))
 | 
			
		||||
 | 
			
		||||
#define	BIT30PACK(i,points_remaining)  \
 | 
			
		||||
  (points_remaining >= 1 &&	       \
 | 
			
		||||
   (minbits[i] <= 30))
 | 
			
		||||
 | 
			
		||||
#define	MINBITS(diff,minbits)					       \
 | 
			
		||||
  if (diff >= -8 && diff < 8) minbits = 4;			       \
 | 
			
		||||
  else if (diff >= -16 && diff < 16) minbits = 5;		       \
 | 
			
		||||
  else if (diff >= -32 && diff < 32) minbits = 6;		       \
 | 
			
		||||
  else if (diff >= -128 && diff < 128) minbits = 8;		       \
 | 
			
		||||
  else if (diff >= -512 && diff < 512) minbits = 10;		       \
 | 
			
		||||
  else if (diff >= -16384 && diff < 16384) minbits = 15;	       \
 | 
			
		||||
  else if (diff >= -32768 && diff < 32768) minbits = 16;	       \
 | 
			
		||||
  else if (diff >= -536870912 && diff < 536870912) minbits = 30;       \
 | 
			
		||||
  else minbits = 32;
 | 
			
		||||
 | 
			
		||||
#define PACK(bits,n,m1,m2)  {			\
 | 
			
		||||
    int i = 0;					\
 | 
			
		||||
    unsigned int val = 0;			\
 | 
			
		||||
    for (i=0;i<n;i++) {				\
 | 
			
		||||
      val = (val<<bits) | (diff[i]&m1); 	\
 | 
			
		||||
    }						\
 | 
			
		||||
    val |= ((unsigned int)m2 << 30);		\
 | 
			
		||||
    dframes->f[fn].w[wn].fw = val; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_int_16:							*
 | 
			
		||||
 *	Pack integer data into INT_16 format.				*
 | 
			
		||||
 *	Return: 0 on success, -1 on failure.				*
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_int_16
 | 
			
		||||
 (int16_t    *packed,           /* output data array - packed           */
 | 
			
		||||
  int32_t    *data,             /* input data array                     */
 | 
			
		||||
  int         ns,               /* desired number of samples to pack    */
 | 
			
		||||
  int         max_bytes,        /* max # of bytes for output buffer     */
 | 
			
		||||
  int         pad,              /* flag to specify padding to max_bytes */
 | 
			
		||||
  int        *pnbytes,          /* number of bytes actually packed      */
 | 
			
		||||
  int        *pnsamples,        /* number of samples actually packed    */
 | 
			
		||||
  int         swapflag)         /* if data should be swapped            */
 | 
			
		||||
{
 | 
			
		||||
  int points_remaining = ns;    /* number of samples remaining to pack  */
 | 
			
		||||
  int i = 0;
 | 
			
		||||
  
 | 
			
		||||
  while (points_remaining > 0 && max_bytes >= 2)
 | 
			
		||||
    {  /* Pack the next available data into INT_16 format */
 | 
			
		||||
      if ( data[i] < -32768 || data[i] > 32767 )
 | 
			
		||||
	ms_log (2, "msr_pack_int_16(%s): input sample out of range: %d\n",
 | 
			
		||||
		PACK_SRCNAME, data[i]);
 | 
			
		||||
      
 | 
			
		||||
      *packed = data[i];      
 | 
			
		||||
      if ( swapflag ) ms_gswap2 (packed);
 | 
			
		||||
      
 | 
			
		||||
      packed++;
 | 
			
		||||
      max_bytes -= 2;
 | 
			
		||||
      points_remaining--;
 | 
			
		||||
      i++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnbytes = (ns - points_remaining) * 2;
 | 
			
		||||
  
 | 
			
		||||
  /* Pad miniSEED block if necessary */
 | 
			
		||||
  if (pad)
 | 
			
		||||
    {
 | 
			
		||||
      memset ((void *)packed, 0, max_bytes);
 | 
			
		||||
      *pnbytes += max_bytes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_int_32:							*
 | 
			
		||||
 *	Pack integer data into INT_32 format.				*
 | 
			
		||||
 *	Return: 0 on success, -1 on failure.				*
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_int_32 
 | 
			
		||||
 (int32_t  *packed,          /* output data array - packed              */
 | 
			
		||||
  int32_t  *data,            /* input data array - unpacked             */
 | 
			
		||||
  int       ns,              /* desired number of samples to pack       */
 | 
			
		||||
  int       max_bytes,       /* max # of bytes for output buffer        */
 | 
			
		||||
  int       pad,             /* flag to specify padding to max_bytes    */
 | 
			
		||||
  int      *pnbytes,         /* number of bytes actually packed         */
 | 
			
		||||
  int      *pnsamples,       /* number of samples actually packed       */
 | 
			
		||||
  int       swapflag)        /* if data should be swapped               */
 | 
			
		||||
{
 | 
			
		||||
  int points_remaining = ns; /* number of samples remaining to pack */
 | 
			
		||||
  int i = 0;
 | 
			
		||||
 | 
			
		||||
  while (points_remaining > 0 && max_bytes >= 4)
 | 
			
		||||
    { /* Pack the next available data into INT_32 format */
 | 
			
		||||
      *packed = data[i];
 | 
			
		||||
      if ( swapflag ) ms_gswap4 (packed);
 | 
			
		||||
      
 | 
			
		||||
      packed++;
 | 
			
		||||
      max_bytes -= 4;
 | 
			
		||||
      points_remaining--;
 | 
			
		||||
      i++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnbytes = (ns - points_remaining) * 4;
 | 
			
		||||
  
 | 
			
		||||
  /* Pad miniSEED block if necessary */
 | 
			
		||||
  if (pad)
 | 
			
		||||
    {
 | 
			
		||||
      memset ((void *)packed, 0, max_bytes);
 | 
			
		||||
      *pnbytes += max_bytes;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_float_32:							*
 | 
			
		||||
 *	Pack float data into FLOAT32 format.				*
 | 
			
		||||
 *	Return: 0 on success, -1 on error.				*
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_float_32 
 | 
			
		||||
 (float    *packed,          /* output data array - packed              */
 | 
			
		||||
  float    *data,            /* input data array - unpacked             */
 | 
			
		||||
  int       ns,              /* desired number of samples to pack       */
 | 
			
		||||
  int       max_bytes,       /* max # of bytes for output buffer        */
 | 
			
		||||
  int       pad,             /* flag to specify padding to max_bytes    */
 | 
			
		||||
  int      *pnbytes,         /* number of bytes actually packed         */
 | 
			
		||||
  int      *pnsamples,       /* number of samples actually packed       */
 | 
			
		||||
  int       swapflag)        /* if data should be swapped               */
 | 
			
		||||
{
 | 
			
		||||
  int points_remaining = ns; /* number of samples remaining to pack */
 | 
			
		||||
  int i = 0;
 | 
			
		||||
  
 | 
			
		||||
  while (points_remaining > 0 && max_bytes >= 4)
 | 
			
		||||
    {
 | 
			
		||||
      *packed = data[i];
 | 
			
		||||
      if ( swapflag ) ms_gswap4 (packed);
 | 
			
		||||
      
 | 
			
		||||
      packed++;
 | 
			
		||||
      max_bytes -= 4;
 | 
			
		||||
      points_remaining--;
 | 
			
		||||
      i++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnbytes = (ns - points_remaining) * 4;
 | 
			
		||||
  
 | 
			
		||||
  /* Pad miniSEED block if necessary */
 | 
			
		||||
  if (pad)
 | 
			
		||||
    {
 | 
			
		||||
      memset ((void *)packed, 0, max_bytes);
 | 
			
		||||
      *pnbytes += max_bytes;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_float_64:							*
 | 
			
		||||
 *	Pack double data into FLOAT64 format.				*
 | 
			
		||||
 *	Return: 0 on success, -1 on error.				*
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_float_64 
 | 
			
		||||
 (double   *packed,          /* output data array - packed              */
 | 
			
		||||
  double   *data,            /* input data array - unpacked             */
 | 
			
		||||
  int       ns,              /* desired number of samples to pack       */
 | 
			
		||||
  int       max_bytes,       /* max # of bytes for output buffer        */
 | 
			
		||||
  int       pad,             /* flag to specify padding to max_bytes    */
 | 
			
		||||
  int      *pnbytes,         /* number of bytes actually packed         */
 | 
			
		||||
  int      *pnsamples,       /* number of samples actually packed       */
 | 
			
		||||
  int       swapflag)        /* if data should be swapped               */
 | 
			
		||||
{
 | 
			
		||||
  int points_remaining = ns; /* number of samples remaining to pack */
 | 
			
		||||
  int i = 0;
 | 
			
		||||
  
 | 
			
		||||
  while (points_remaining > 0 && max_bytes >= 8)
 | 
			
		||||
    {
 | 
			
		||||
      *packed = data[i];
 | 
			
		||||
      if ( swapflag ) ms_gswap8 (packed);
 | 
			
		||||
      
 | 
			
		||||
      packed++;
 | 
			
		||||
      max_bytes -= 8;
 | 
			
		||||
      points_remaining--;
 | 
			
		||||
      i++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnbytes = (ns - points_remaining) * 8;
 | 
			
		||||
  
 | 
			
		||||
  /* Pad miniSEED block if necessary */
 | 
			
		||||
  if (pad)
 | 
			
		||||
    {
 | 
			
		||||
      memset ((void *)packed, 0, max_bytes);
 | 
			
		||||
      *pnbytes += max_bytes;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_steim1:							*
 | 
			
		||||
 *	Pack data into STEIM1 data frames.				*
 | 
			
		||||
 *  return:								*
 | 
			
		||||
 *	0 on success.							*
 | 
			
		||||
 *	-1 on error.		           	         	        *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_steim1
 | 
			
		||||
 (DFRAMES      *dframes,       	/* ptr to data frames                   */
 | 
			
		||||
  int32_t      *data,		/* ptr to unpacked data array           */
 | 
			
		||||
  int32_t       d0,		/* first difference value               */
 | 
			
		||||
  int		ns,		/* number of samples to pack            */
 | 
			
		||||
  int		nf,		/* total number of data frames          */
 | 
			
		||||
  int		pad,		/* flag to specify padding to nf        */
 | 
			
		||||
  int	       *pnframes,	/* number of frames actually packed     */
 | 
			
		||||
  int	       *pnsamples,	/* number of samples actually packed    */
 | 
			
		||||
  int           swapflag)       /* if data should be swapped            */
 | 
			
		||||
{
 | 
			
		||||
  int		points_remaining = ns;
 | 
			
		||||
  int           points_packed = 0;
 | 
			
		||||
  int32_t       diff[4];        /* array of differences                 */
 | 
			
		||||
  uint8_t       minbits[4];     /* array of minimum bits for diffs      */
 | 
			
		||||
  int		i, j;
 | 
			
		||||
  int		mask;
 | 
			
		||||
  int		ipt = 0;	/* index of initial data to pack.	*/
 | 
			
		||||
  int		fn = 0;		/* index of initial frame to pack.	*/
 | 
			
		||||
  int		wn = 2;		/* index of initial word to pack.	*/
 | 
			
		||||
  int32_t      	itmp;
 | 
			
		||||
  int16_t	stmp;
 | 
			
		||||
  
 | 
			
		||||
  /* Calculate initial difference and minbits buffers */
 | 
			
		||||
  diff[0] = d0;
 | 
			
		||||
  MINBITS(diff[0],minbits[0]);
 | 
			
		||||
  for (i=1; i < 4 && i < ns; i++)
 | 
			
		||||
    {
 | 
			
		||||
      diff[i] = data[i] - data[i-1];
 | 
			
		||||
      MINBITS(diff[i],minbits[i]);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  dframes->f[fn].ctrl = 0;
 | 
			
		||||
  
 | 
			
		||||
  /* Set X0 and XN values in first frame */
 | 
			
		||||
  X0 = data[0];
 | 
			
		||||
  if ( swapflag ) ms_gswap4 (&X0);
 | 
			
		||||
  dframes->f[0].ctrl = (dframes->f[0].ctrl<<2) | STEIM1_SPECIAL_MASK;
 | 
			
		||||
  XN = data[ns-1];
 | 
			
		||||
  if ( swapflag ) ms_gswap4 (&XN);
 | 
			
		||||
  dframes->f[0].ctrl = (dframes->f[0].ctrl<<2) | STEIM1_SPECIAL_MASK;
 | 
			
		||||
  
 | 
			
		||||
  while (points_remaining > 0)
 | 
			
		||||
    {
 | 
			
		||||
      points_packed = 0;
 | 
			
		||||
      
 | 
			
		||||
      /* Pack the next available data into the most compact form */
 | 
			
		||||
      if (BYTEPACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  mask = STEIM1_BYTE_MASK;
 | 
			
		||||
	  for (j=0; j<4; j++) { dframes->f[fn].w[wn].byte[j] = diff[j]; }
 | 
			
		||||
	  points_packed = 4;
 | 
			
		||||
	}
 | 
			
		||||
      else if (HALFPACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  mask = STEIM1_HALFWORD_MASK;
 | 
			
		||||
	  for (j=0; j<2; j++)
 | 
			
		||||
	    {
 | 
			
		||||
	      stmp = diff[j];
 | 
			
		||||
	      if ( swapflag ) ms_gswap2 (&stmp);
 | 
			
		||||
	      dframes->f[fn].w[wn].hw[j] = stmp;
 | 
			
		||||
	    }
 | 
			
		||||
	  points_packed = 2;
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  mask = STEIM1_FULLWORD_MASK;
 | 
			
		||||
	  itmp = diff[0];
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&itmp);
 | 
			
		||||
	  dframes->f[fn].w[wn].fw = itmp;
 | 
			
		||||
	  points_packed = 1;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Append mask for this word to current mask */
 | 
			
		||||
      dframes->f[fn].ctrl = (dframes->f[fn].ctrl<<2) | mask;
 | 
			
		||||
      
 | 
			
		||||
      points_remaining -= points_packed;
 | 
			
		||||
      ipt += points_packed;
 | 
			
		||||
      
 | 
			
		||||
      /* Check for full frame or full block */
 | 
			
		||||
      if (++wn >= VALS_PER_FRAME)
 | 
			
		||||
	{
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].ctrl);
 | 
			
		||||
	  /* Reset output index to beginning of frame */
 | 
			
		||||
	  wn = 0;
 | 
			
		||||
	  /* If block is full, output block and reinitialize */
 | 
			
		||||
	  if (++fn >= nf) break;
 | 
			
		||||
	  dframes->f[fn].ctrl = 0;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Shift and re-fill difference and minbits buffers */
 | 
			
		||||
      for ( i=points_packed; i < 4; i++ )
 | 
			
		||||
	{
 | 
			
		||||
	  /* Shift remaining buffer entries */
 | 
			
		||||
	  diff[i-points_packed] = diff[i];
 | 
			
		||||
	  minbits[i-points_packed] = minbits[i];
 | 
			
		||||
	}
 | 
			
		||||
      for ( i=4-points_packed,j=ipt+(4-points_packed); i < 4 && j < ns; i++,j++ )
 | 
			
		||||
	{
 | 
			
		||||
	  /* Re-fill entries */
 | 
			
		||||
	  diff[i] = data[j] - data[j-1];
 | 
			
		||||
	  MINBITS(diff[i],minbits[i]);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  /* Update XN value in first frame */
 | 
			
		||||
  XN = data[(ns-1)-points_remaining];
 | 
			
		||||
  if ( swapflag ) ms_gswap4 (&XN);
 | 
			
		||||
  
 | 
			
		||||
  /* End of data.  Pad current frame and optionally rest of block */
 | 
			
		||||
  /* Do not pad and output a completely empty block */
 | 
			
		||||
  if ( ! EMPTY_BLOCK(fn,wn) )
 | 
			
		||||
    {
 | 
			
		||||
      *pnframes = pad_steim_frame (dframes, fn, wn, nf, swapflag, pad);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      *pnframes = 0;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_steim2:							*
 | 
			
		||||
 *	Pack data into STEIM1 data frames.				*
 | 
			
		||||
 *  return:								*
 | 
			
		||||
 *	0 on success.							*
 | 
			
		||||
 *	-1 on error.                                                    *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_steim2
 | 
			
		||||
 (DFRAMES      *dframes,	/* ptr to data frames                   */
 | 
			
		||||
  int32_t      *data,		/* ptr to unpacked data array           */
 | 
			
		||||
  int32_t       d0,		/* first difference value               */
 | 
			
		||||
  int		ns,		/* number of samples to pack            */
 | 
			
		||||
  int		nf,		/* total number of data frames to pack  */
 | 
			
		||||
  int		pad,		/* flag to specify padding to nf        */
 | 
			
		||||
  int	       *pnframes,	/* number of frames actually packed     */
 | 
			
		||||
  int	       *pnsamples,	/* number of samples actually packed    */
 | 
			
		||||
  int           swapflag)       /* if data should be swapped            */
 | 
			
		||||
{
 | 
			
		||||
  int		points_remaining = ns;
 | 
			
		||||
  int           points_packed = 0;
 | 
			
		||||
  int32_t       diff[7];        /* array of differences                 */
 | 
			
		||||
  uint8_t       minbits[7];     /* array of minimum bits for diffs      */
 | 
			
		||||
  int		i, j;
 | 
			
		||||
  int		mask;
 | 
			
		||||
  int		ipt = 0;	/* index of initial data to pack.	*/
 | 
			
		||||
  int		fn = 0;		/* index of initial frame to pack.	*/
 | 
			
		||||
  int		wn = 2;		/* index of initial word to pack.	*/
 | 
			
		||||
  
 | 
			
		||||
  /* Calculate initial difference and minbits buffers */
 | 
			
		||||
  diff[0] = d0;
 | 
			
		||||
  MINBITS(diff[0],minbits[0]);
 | 
			
		||||
  for (i=1; i < 7 && i < ns; i++)
 | 
			
		||||
    {
 | 
			
		||||
      diff[i] = data[i] - data[i-1];
 | 
			
		||||
      MINBITS(diff[i],minbits[i]);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  dframes->f[fn].ctrl = 0;
 | 
			
		||||
  
 | 
			
		||||
  /* Set X0 and XN values in first frame */
 | 
			
		||||
  X0 = data[0];
 | 
			
		||||
  if ( swapflag ) ms_gswap4 (&X0);
 | 
			
		||||
  dframes->f[0].ctrl = (dframes->f[0].ctrl<<2) | STEIM2_SPECIAL_MASK;
 | 
			
		||||
  XN = data[ns-1];
 | 
			
		||||
  if ( swapflag ) ms_gswap4 (&XN);
 | 
			
		||||
  dframes->f[0].ctrl = (dframes->f[0].ctrl<<2) | STEIM2_SPECIAL_MASK;
 | 
			
		||||
  
 | 
			
		||||
  while (points_remaining > 0)
 | 
			
		||||
    {
 | 
			
		||||
      points_packed = 0;
 | 
			
		||||
      
 | 
			
		||||
      /* Pack the next available datapoints into the most compact form */
 | 
			
		||||
      if (BIT4PACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  PACK(4,7,0x0000000f,02)
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].w[wn].fw);
 | 
			
		||||
	  mask = STEIM2_567_MASK;
 | 
			
		||||
	  points_packed = 7;
 | 
			
		||||
	}
 | 
			
		||||
      else if (BIT5PACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  PACK(5,6,0x0000001f,01)
 | 
			
		||||
	    if ( swapflag ) ms_gswap4 (&dframes->f[fn].w[wn].fw);
 | 
			
		||||
	  mask = STEIM2_567_MASK;
 | 
			
		||||
	  points_packed = 6;
 | 
			
		||||
	}
 | 
			
		||||
      else if (BIT6PACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  PACK(6,5,0x0000003f,00)
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].w[wn].fw);
 | 
			
		||||
	  mask = STEIM2_567_MASK;
 | 
			
		||||
	  points_packed = 5;
 | 
			
		||||
	}
 | 
			
		||||
      else if (BYTEPACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  mask = STEIM2_BYTE_MASK;
 | 
			
		||||
	  for (j=0; j<4; j++) dframes->f[fn].w[wn].byte[j] = diff[j];
 | 
			
		||||
	  points_packed = 4;
 | 
			
		||||
	}
 | 
			
		||||
      else if (BIT10PACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  PACK(10,3,0x000003ff,03)
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].w[wn].fw);
 | 
			
		||||
	  mask = STEIM2_123_MASK;
 | 
			
		||||
	  points_packed = 3;
 | 
			
		||||
	}
 | 
			
		||||
      else if (BIT15PACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  PACK(15,2,0x00007fff,02)
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].w[wn].fw);
 | 
			
		||||
	  mask = STEIM2_123_MASK;
 | 
			
		||||
	  points_packed = 2;
 | 
			
		||||
	}
 | 
			
		||||
      else if (BIT30PACK(0,points_remaining))
 | 
			
		||||
	{
 | 
			
		||||
	  PACK(30,1,0x3fffffff,01)
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].w[wn].fw);
 | 
			
		||||
	  mask = STEIM2_123_MASK;
 | 
			
		||||
	  points_packed = 1;
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log (2, "msr_pack_steim2(%s): Unable to represent difference in <= 30 bits\n",
 | 
			
		||||
		  PACK_SRCNAME);
 | 
			
		||||
	  return -1;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Append mask for this word to current mask */
 | 
			
		||||
      dframes->f[fn].ctrl = (dframes->f[fn].ctrl<<2) | mask;
 | 
			
		||||
      
 | 
			
		||||
      points_remaining -= points_packed;
 | 
			
		||||
      ipt += points_packed;
 | 
			
		||||
      
 | 
			
		||||
      /* Check for full frame or full block */
 | 
			
		||||
      if (++wn >= VALS_PER_FRAME)
 | 
			
		||||
	{
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].ctrl);
 | 
			
		||||
	  /* Reset output index to beginning of frame */
 | 
			
		||||
	  wn = 0;
 | 
			
		||||
	  /* If block is full, output block and reinitialize */
 | 
			
		||||
	  if (++fn >= nf) break;
 | 
			
		||||
	  dframes->f[fn].ctrl = 0;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Shift and re-fill difference and minbits buffers */
 | 
			
		||||
      for ( i=points_packed; i < 7; i++ )
 | 
			
		||||
	{
 | 
			
		||||
	  /* Shift remaining buffer entries */
 | 
			
		||||
	  diff[i-points_packed] = diff[i];
 | 
			
		||||
	  minbits[i-points_packed] = minbits[i];
 | 
			
		||||
	}
 | 
			
		||||
      for ( i=7-points_packed,j=ipt+(7-points_packed); i < 7 && j < ns; i++,j++ )
 | 
			
		||||
	{
 | 
			
		||||
	  /* Re-fill entries */
 | 
			
		||||
	  diff[i] = data[j] - data[j-1];
 | 
			
		||||
	  MINBITS(diff[i],minbits[i]);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  /* Update XN value in first frame */
 | 
			
		||||
  XN = data[(ns-1)-points_remaining];
 | 
			
		||||
  if ( swapflag ) ms_gswap4 (&XN);
 | 
			
		||||
  
 | 
			
		||||
  /* End of data.  Pad current frame and optionally rest of block */
 | 
			
		||||
  /* Do not pad and output a completely empty block */
 | 
			
		||||
  if ( ! EMPTY_BLOCK(fn,wn) )
 | 
			
		||||
    {
 | 
			
		||||
      *pnframes = pad_steim_frame (dframes, fn, wn, nf, swapflag, pad);
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      *pnframes = 0;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  pad_steim_frame:							*
 | 
			
		||||
 *	Pad the rest of the data record with null values,		*
 | 
			
		||||
 *	and optionally the rest of the total number of frames.		*
 | 
			
		||||
 *  return:								*
 | 
			
		||||
 *	total number of frames in record.				*
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
static int pad_steim_frame
 | 
			
		||||
 (DFRAMES      *dframes,
 | 
			
		||||
  int		fn,	    	/* current frame number.		*/
 | 
			
		||||
  int	    	wn,		/* current work number.			*/
 | 
			
		||||
  int	    	nf,		/* total number of data frames.		*/
 | 
			
		||||
  int		swapflag,	/* flag to swap byte order of data.	*/
 | 
			
		||||
  int	    	pad)		/* flag to pad # frames to nf.		*/
 | 
			
		||||
{
 | 
			
		||||
  /* Finish off the current frame */
 | 
			
		||||
  if (wn < VALS_PER_FRAME && fn < nf)
 | 
			
		||||
    {
 | 
			
		||||
      for (; wn < VALS_PER_FRAME; wn++)
 | 
			
		||||
	{
 | 
			
		||||
	  dframes->f[fn].w[wn].fw = 0;
 | 
			
		||||
	  dframes->f[fn].ctrl = (dframes->f[fn].ctrl<<2) | STEIM1_SPECIAL_MASK;
 | 
			
		||||
	}
 | 
			
		||||
      if ( swapflag ) ms_gswap4 (&dframes->f[fn].ctrl);
 | 
			
		||||
      fn++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  /* Fill the remaining frames in the block */
 | 
			
		||||
  if (pad)
 | 
			
		||||
    {
 | 
			
		||||
      for (; fn<nf; fn++)
 | 
			
		||||
	{
 | 
			
		||||
	  dframes->f[fn].ctrl = STEIM1_SPECIAL_MASK;	/* mask for ctrl */
 | 
			
		||||
	  for (wn=0; wn<VALS_PER_FRAME; wn++)
 | 
			
		||||
	    {
 | 
			
		||||
	      dframes->f[fn].w[wn].fw = 0;
 | 
			
		||||
	      dframes->f[fn].ctrl = (dframes->f[fn].ctrl<<2) | STEIM1_SPECIAL_MASK;
 | 
			
		||||
	    }
 | 
			
		||||
	  
 | 
			
		||||
	  if ( swapflag ) ms_gswap4 (&dframes->f[fn].ctrl);
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return fn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_pack_text:						       	*
 | 
			
		||||
 *	Pack text data into text format.  Split input data on line	*
 | 
			
		||||
*	breaks so as to not split lines between records.		* 
 | 
			
		||||
*	Return: 0 on success, -1 on error.				*
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_pack_text
 | 
			
		||||
 (char 	       *packed,         /* output data array - packed.		*/
 | 
			
		||||
  char	       *data,		/* input data array - unpacked.		*/
 | 
			
		||||
  int		ns,		/* desired number of samples to pack.	*/
 | 
			
		||||
  int		max_bytes,	/* max # of bytes for output buffer.	*/
 | 
			
		||||
  int		pad,		/* flag to specify padding to max_bytes.*/
 | 
			
		||||
  int	       *pnbytes,	/* number of bytes actually packed.	*/
 | 
			
		||||
  int	       *pnsamples)	/* number of samples actually packed.	*/
 | 
			
		||||
{
 | 
			
		||||
  int points_remaining = ns;	/* number of samples remaining to pack.	*/
 | 
			
		||||
  int		last = -1;
 | 
			
		||||
  int		nbytes;
 | 
			
		||||
  int		i;
 | 
			
		||||
  
 | 
			
		||||
  /* Split lines only if a single line will not fit in 1 record */
 | 
			
		||||
  if (points_remaining > max_bytes)
 | 
			
		||||
    {
 | 
			
		||||
      /* Look for the last newline that will fit in output buffer */
 | 
			
		||||
      for (i=max_bytes-1; i>=0; i--)
 | 
			
		||||
	{
 | 
			
		||||
	  if (data[i] == '\n') {
 | 
			
		||||
	    last = i;
 | 
			
		||||
	    break;
 | 
			
		||||
	  }
 | 
			
		||||
	}
 | 
			
		||||
      if (last < 0) last = max_bytes - 1;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if (last < 0) last = points_remaining - 1;
 | 
			
		||||
  nbytes = last + 1;
 | 
			
		||||
  memcpy (packed, data, nbytes);
 | 
			
		||||
  packed += nbytes;
 | 
			
		||||
  max_bytes -= nbytes;
 | 
			
		||||
  *pnbytes = nbytes;
 | 
			
		||||
  *pnsamples = nbytes;
 | 
			
		||||
  points_remaining -= nbytes;
 | 
			
		||||
  
 | 
			
		||||
  /* Pad miniSEED block if necessary */
 | 
			
		||||
  if (pad)
 | 
			
		||||
    {
 | 
			
		||||
      memset ((void *)packed, 0, max_bytes);
 | 
			
		||||
      *pnbytes += max_bytes;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  *pnsamples = ns - points_remaining;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								libs/3rd-party/mseed/packdata.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								libs/3rd-party/mseed/packdata.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * packdata.h:
 | 
			
		||||
 * 
 | 
			
		||||
 * Interface declarations for the Mini-SEED packing routines in
 | 
			
		||||
 * packdata.c
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2008.220
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef	PACKDATA_H
 | 
			
		||||
#define	PACKDATA_H 1
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "steimdata.h"
 | 
			
		||||
 | 
			
		||||
/* Pointer to srcname of record being packed, declared in pack.c */
 | 
			
		||||
extern char *PACK_SRCNAME;
 | 
			
		||||
 | 
			
		||||
extern int msr_pack_int_16 (int16_t*, int32_t*, int, int, int, int*, int*, int);
 | 
			
		||||
extern int msr_pack_int_32 (int32_t*, int32_t*, int, int, int, int*, int*, int);
 | 
			
		||||
extern int msr_pack_float_32 (float*, float*, int, int, int, int*, int*, int);
 | 
			
		||||
extern int msr_pack_float_64 (double*, double*, int, int, int, int*, int*, int);
 | 
			
		||||
extern int msr_pack_steim1 (DFRAMES*, int32_t*, int32_t, int, int, int, int*, int*, int);
 | 
			
		||||
extern int msr_pack_steim2 (DFRAMES*, int32_t*, int32_t, int, int, int, int*, int*, int);
 | 
			
		||||
extern int msr_pack_text (char *, char *, int, int, int, int*, int*);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1163
									
								
								libs/3rd-party/mseed/parseutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1163
									
								
								libs/3rd-party/mseed/parseutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										680
									
								
								libs/3rd-party/mseed/selection.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										680
									
								
								libs/3rd-party/mseed/selection.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,680 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * selection.c:
 | 
			
		||||
 *
 | 
			
		||||
 * Generic routines to manage selection lists.
 | 
			
		||||
 *
 | 
			
		||||
 * Written by Chad Trabant unless otherwise noted
 | 
			
		||||
 *   IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2014.197
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
#include "libmseed.h"
 | 
			
		||||
 | 
			
		||||
static int ms_globmatch (char *string, char *pattern);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_matchselect:
 | 
			
		||||
 *
 | 
			
		||||
 * Test the specified parameters for a matching selection entry.  The
 | 
			
		||||
 * srcname parameter may contain globbing characters.  The NULL value
 | 
			
		||||
 * (matching any times) for the start and end times is HPTERROR.
 | 
			
		||||
 *
 | 
			
		||||
 * Return Selections pointer to matching entry on successful match and
 | 
			
		||||
 * NULL for no match or error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
Selections *
 | 
			
		||||
ms_matchselect (Selections *selections, char *srcname, hptime_t starttime,
 | 
			
		||||
		hptime_t endtime, SelectTime **ppselecttime)
 | 
			
		||||
{
 | 
			
		||||
  Selections *findsl = NULL;
 | 
			
		||||
  SelectTime *findst = NULL;
 | 
			
		||||
  SelectTime *matchst = NULL;
 | 
			
		||||
  
 | 
			
		||||
  if ( selections )
 | 
			
		||||
    {
 | 
			
		||||
      findsl = selections;
 | 
			
		||||
      while ( findsl )
 | 
			
		||||
	{
 | 
			
		||||
	  if ( ms_globmatch (srcname, findsl->srcname) )
 | 
			
		||||
	    {
 | 
			
		||||
	      findst = findsl->timewindows;              
 | 
			
		||||
	      while ( findst )
 | 
			
		||||
		{
 | 
			
		||||
		  if ( starttime != HPTERROR && findst->starttime != HPTERROR &&
 | 
			
		||||
		       (starttime < findst->starttime && ! (starttime <= findst->starttime && endtime >= findst->starttime)) )
 | 
			
		||||
		    { findst = findst->next; continue; }
 | 
			
		||||
		  else if ( endtime != HPTERROR && findst->endtime != HPTERROR &&
 | 
			
		||||
			    (endtime > findst->endtime && ! (starttime <= findst->endtime && endtime >= findst->endtime)) )
 | 
			
		||||
		    { findst = findst->next; continue; }
 | 
			
		||||
		  
 | 
			
		||||
		  matchst = findst;
 | 
			
		||||
		  break;
 | 
			
		||||
		}
 | 
			
		||||
	    }
 | 
			
		||||
	  
 | 
			
		||||
	  if ( matchst )
 | 
			
		||||
	    break;
 | 
			
		||||
	  else
 | 
			
		||||
	    findsl = findsl->next;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if ( ppselecttime )
 | 
			
		||||
    *ppselecttime = matchst;
 | 
			
		||||
  
 | 
			
		||||
  return ( matchst ) ? findsl : NULL;
 | 
			
		||||
} /* End of ms_matchselect() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * msr_matchselect:
 | 
			
		||||
 *
 | 
			
		||||
 * A simple wrapper for calling ms_matchselect() using details from a
 | 
			
		||||
 * MSRecord struct.
 | 
			
		||||
 *
 | 
			
		||||
 * Return Selections pointer to matching entry on successful match and
 | 
			
		||||
 * NULL for no match or error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
Selections *
 | 
			
		||||
msr_matchselect (Selections *selections, MSRecord *msr, SelectTime **ppselecttime)
 | 
			
		||||
{
 | 
			
		||||
  char srcname[50];
 | 
			
		||||
  hptime_t endtime;
 | 
			
		||||
  
 | 
			
		||||
  if ( ! selections || ! msr )
 | 
			
		||||
    return NULL;
 | 
			
		||||
  
 | 
			
		||||
  msr_srcname (msr, srcname, 1);
 | 
			
		||||
  endtime = msr_endtime (msr);
 | 
			
		||||
  
 | 
			
		||||
  return ms_matchselect (selections, srcname, msr->starttime, endtime,
 | 
			
		||||
			 ppselecttime);
 | 
			
		||||
} /* End of msr_matchselect() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_addselect:
 | 
			
		||||
 *
 | 
			
		||||
 * Add select parameters to a specified selection list.  The srcname
 | 
			
		||||
 * argument may contain globbing parameters.  The NULL value (matching
 | 
			
		||||
 * any value) for the start and end times is HPTERROR.
 | 
			
		||||
 *
 | 
			
		||||
 * Return 0 on success and -1 on error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
ms_addselect (Selections **ppselections, char *srcname,
 | 
			
		||||
	      hptime_t starttime, hptime_t endtime)
 | 
			
		||||
{
 | 
			
		||||
  Selections *newsl = NULL;
 | 
			
		||||
  SelectTime *newst = NULL;
 | 
			
		||||
  
 | 
			
		||||
  if ( ! ppselections || ! srcname )
 | 
			
		||||
    return -1;
 | 
			
		||||
  
 | 
			
		||||
  /* Allocate new SelectTime and populate */
 | 
			
		||||
  if ( ! (newst = (SelectTime *) calloc (1, sizeof(SelectTime))) )
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (2, "Cannot allocate memory\n");
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  newst->starttime = starttime;
 | 
			
		||||
  newst->endtime = endtime;
 | 
			
		||||
  
 | 
			
		||||
  /* Add new Selections struct to begining of list */
 | 
			
		||||
  if ( ! *ppselections )
 | 
			
		||||
    {
 | 
			
		||||
      /* Allocate new Selections and populate */
 | 
			
		||||
      if ( ! (newsl = (Selections *) calloc (1, sizeof(Selections))) )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log (2, "Cannot allocate memory\n");
 | 
			
		||||
	  return -1;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      strncpy (newsl->srcname, srcname, sizeof(newsl->srcname));
 | 
			
		||||
      newsl->srcname[sizeof(newsl->srcname) - 1] = '\0';
 | 
			
		||||
      
 | 
			
		||||
      /* Add new Selections struct as first in list */
 | 
			
		||||
      *ppselections = newsl;
 | 
			
		||||
      newsl->timewindows = newst;
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      Selections *findsl = *ppselections;
 | 
			
		||||
      Selections *matchsl = 0;
 | 
			
		||||
      
 | 
			
		||||
      /* Search for matching Selectlink entry */
 | 
			
		||||
      while ( findsl )
 | 
			
		||||
	{
 | 
			
		||||
	  if ( ! strcmp (findsl->srcname, srcname) )
 | 
			
		||||
	    {
 | 
			
		||||
	      matchsl = findsl;
 | 
			
		||||
	      break;
 | 
			
		||||
	    }
 | 
			
		||||
	  
 | 
			
		||||
	  findsl = findsl->next;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      if ( matchsl )
 | 
			
		||||
	{
 | 
			
		||||
	  /* Add time window selection to beginning of window list */
 | 
			
		||||
	  newst->next = matchsl->timewindows;
 | 
			
		||||
	  matchsl->timewindows = newst;
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  /* Allocate new Selections and populate */
 | 
			
		||||
	  if ( ! (newsl = (Selections *) calloc (1, sizeof(Selections))) )
 | 
			
		||||
	    {
 | 
			
		||||
	      ms_log (2, "Cannot allocate memory\n");
 | 
			
		||||
	      return -1;
 | 
			
		||||
	    }
 | 
			
		||||
	  
 | 
			
		||||
	  strncpy (newsl->srcname, srcname, sizeof(newsl->srcname));
 | 
			
		||||
	  newsl->srcname[sizeof(newsl->srcname) - 1] = '\0';
 | 
			
		||||
	  
 | 
			
		||||
	  /* Add new Selections to beginning of list */
 | 
			
		||||
	  newsl->next = *ppselections;
 | 
			
		||||
	  *ppselections = newsl;
 | 
			
		||||
	  newsl->timewindows = newst;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
} /* End of ms_addselect() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_addselect_comp:
 | 
			
		||||
 *
 | 
			
		||||
 * Add select parameters to a specified selection list based on
 | 
			
		||||
 * separate name components.  The network, station, location, channel
 | 
			
		||||
 * and quality arguments may contain globbing parameters.  The NULL
 | 
			
		||||
 * value (matching any value) for the start and end times is HPTERROR.
 | 
			
		||||
 *
 | 
			
		||||
 * If any of the naming parameters are not supplied (pointer is NULL)
 | 
			
		||||
 * a wildcard for all matches is substituted.  As a special case, if
 | 
			
		||||
 * the location ID (loc) is set to "--" to match a space-space/blank
 | 
			
		||||
 * ID it will be translated to an empty string to match libmseed's
 | 
			
		||||
 * notation.
 | 
			
		||||
 *
 | 
			
		||||
 * Return 0 on success and -1 on error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
ms_addselect_comp (Selections **ppselections, char *net, char* sta, char *loc,
 | 
			
		||||
		   char *chan, char *qual, hptime_t starttime, hptime_t endtime)
 | 
			
		||||
{
 | 
			
		||||
  char srcname[100];
 | 
			
		||||
  char selnet[20];
 | 
			
		||||
  char selsta[20];
 | 
			
		||||
  char selloc[20];
 | 
			
		||||
  char selchan[20];
 | 
			
		||||
  char selqual[20];
 | 
			
		||||
  
 | 
			
		||||
  if ( ! ppselections )
 | 
			
		||||
    return -1;
 | 
			
		||||
  
 | 
			
		||||
  if ( net )
 | 
			
		||||
    {
 | 
			
		||||
      strncpy (selnet, net, sizeof(selnet));
 | 
			
		||||
      selnet[sizeof(selnet)-1] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    strcpy (selnet, "*");
 | 
			
		||||
  
 | 
			
		||||
  if ( sta )
 | 
			
		||||
    {
 | 
			
		||||
      strncpy (selsta, sta, sizeof(selsta));
 | 
			
		||||
      selsta[sizeof(selsta)-1] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    strcpy (selsta, "*");
 | 
			
		||||
  
 | 
			
		||||
  if ( loc )
 | 
			
		||||
    {
 | 
			
		||||
      /* Test for special case blank location ID */
 | 
			
		||||
      if ( ! strcmp (loc, "--") )
 | 
			
		||||
	selloc[0] = '\0';
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  strncpy (selloc, loc, sizeof(selloc));
 | 
			
		||||
	  selloc[sizeof(selloc)-1] = '\0';
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    strcpy (selloc, "*");
 | 
			
		||||
  
 | 
			
		||||
  if ( chan )
 | 
			
		||||
    {
 | 
			
		||||
      strncpy (selchan, chan, sizeof(selchan));
 | 
			
		||||
      selchan[sizeof(selchan)-1] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    strcpy (selchan, "*");
 | 
			
		||||
  
 | 
			
		||||
  if ( qual )
 | 
			
		||||
    {
 | 
			
		||||
      strncpy (selqual, qual, sizeof(selqual));
 | 
			
		||||
      selqual[sizeof(selqual)-1] = '\0';
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    strcpy (selqual, "?");
 | 
			
		||||
  
 | 
			
		||||
  /* Create the srcname globbing match for this entry */
 | 
			
		||||
  snprintf (srcname, sizeof(srcname), "%s_%s_%s_%s_%s",
 | 
			
		||||
	    selnet, selsta, selloc, selchan, selqual);
 | 
			
		||||
  
 | 
			
		||||
  /* Add selection to list */
 | 
			
		||||
  if ( ms_addselect (ppselections, srcname, starttime, endtime) )
 | 
			
		||||
    return -1;
 | 
			
		||||
  
 | 
			
		||||
  return 0;
 | 
			
		||||
} /* End of ms_addselect_comp() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_readselectionsfile:
 | 
			
		||||
 *
 | 
			
		||||
 * Read a list of data selections from a file and them to the
 | 
			
		||||
 * specified selections list.  On errors this routine will leave
 | 
			
		||||
 * allocated memory unreachable (leaked), it is expected that this is
 | 
			
		||||
 * a program failing condition.
 | 
			
		||||
 *
 | 
			
		||||
 * As a special case if the filename is "-", selection lines will be
 | 
			
		||||
 * read from stdin.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns count of selections added on success and -1 on error.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
int
 | 
			
		||||
ms_readselectionsfile (Selections **ppselections, char *filename)
 | 
			
		||||
{
 | 
			
		||||
  FILE *fp;
 | 
			
		||||
  hptime_t starttime;
 | 
			
		||||
  hptime_t endtime;
 | 
			
		||||
  char selectline[200];
 | 
			
		||||
  char *selnet;
 | 
			
		||||
  char *selsta;
 | 
			
		||||
  char *selloc;
 | 
			
		||||
  char *selchan;
 | 
			
		||||
  char *selqual;
 | 
			
		||||
  char *selstart;
 | 
			
		||||
  char *selend;
 | 
			
		||||
  char *cp;
 | 
			
		||||
  char next;
 | 
			
		||||
  int selectcount = 0;
 | 
			
		||||
  int linecount = 0;
 | 
			
		||||
  
 | 
			
		||||
  if ( ! ppselections || ! filename )
 | 
			
		||||
    return -1;
 | 
			
		||||
  
 | 
			
		||||
  if ( strcmp (filename, "-" ) )
 | 
			
		||||
    {
 | 
			
		||||
      if ( ! (fp = fopen(filename, "rb")) )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log (2, "Cannot open file %s: %s\n", filename, strerror(errno));
 | 
			
		||||
	  return -1;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      /* Use stdin as special case */
 | 
			
		||||
      fp = stdin;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  while ( fgets (selectline, sizeof(selectline)-1, fp) )
 | 
			
		||||
    {
 | 
			
		||||
      selnet = 0;
 | 
			
		||||
      selsta = 0;
 | 
			
		||||
      selloc = 0;
 | 
			
		||||
      selchan = 0;
 | 
			
		||||
      selqual = 0;
 | 
			
		||||
      selstart = 0;
 | 
			
		||||
      selend = 0;
 | 
			
		||||
      
 | 
			
		||||
      linecount++;
 | 
			
		||||
      
 | 
			
		||||
      /* Guarantee termination */
 | 
			
		||||
      selectline[sizeof(selectline)-1] = '\0';
 | 
			
		||||
      
 | 
			
		||||
      /* End string at first newline character if any */
 | 
			
		||||
      if ( (cp = strchr(selectline, '\n')) )
 | 
			
		||||
        *cp = '\0';
 | 
			
		||||
      
 | 
			
		||||
      /* Skip empty lines */
 | 
			
		||||
      if ( ! strlen (selectline) )
 | 
			
		||||
        continue;
 | 
			
		||||
      
 | 
			
		||||
      /* Skip comment lines */
 | 
			
		||||
      if ( *selectline == '#' )
 | 
			
		||||
        continue;
 | 
			
		||||
      
 | 
			
		||||
      /* Parse: identify components of selection and terminate */
 | 
			
		||||
      cp = selectline;
 | 
			
		||||
      next = 1;
 | 
			
		||||
      while ( *cp )
 | 
			
		||||
	{
 | 
			
		||||
	  if ( *cp == ' ' || *cp == '\t' ) { *cp = '\0'; next = 1; }
 | 
			
		||||
	  else if ( *cp == '#' ) { *cp = '\0'; break; }
 | 
			
		||||
	  else if ( next && ! selnet ) { selnet = cp; next = 0; }
 | 
			
		||||
	  else if ( next && ! selsta ) { selsta = cp; next = 0; }
 | 
			
		||||
	  else if ( next && ! selloc ) { selloc = cp; next = 0; }
 | 
			
		||||
	  else if ( next && ! selchan ) { selchan = cp; next = 0; }
 | 
			
		||||
	  else if ( next && ! selqual ) { selqual = cp; next = 0; }
 | 
			
		||||
	  else if ( next && ! selstart ) { selstart = cp; next = 0; }
 | 
			
		||||
	  else if ( next && ! selend ) { selend = cp; next = 0; }
 | 
			
		||||
	  else if ( next ) { *cp = '\0'; break; }
 | 
			
		||||
	  cp++;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Skip line if network, station, location and channel are not defined */
 | 
			
		||||
      if ( ! selnet || ! selsta || ! selloc || ! selchan )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log (2, "[%s] Skipping data selection line number %d\n", filename, linecount);
 | 
			
		||||
	  continue;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      if ( selstart )
 | 
			
		||||
	{
 | 
			
		||||
	  starttime = ms_seedtimestr2hptime (selstart);
 | 
			
		||||
	  if ( starttime == HPTERROR )
 | 
			
		||||
	    {
 | 
			
		||||
	      ms_log (2, "Cannot convert data selection start time (line %d): %s\n", linecount, selstart);
 | 
			
		||||
	      return -1;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  starttime = HPTERROR;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      if ( selend )
 | 
			
		||||
	{
 | 
			
		||||
	  endtime = ms_seedtimestr2hptime (selend);
 | 
			
		||||
	  if ( endtime == HPTERROR )
 | 
			
		||||
	    {
 | 
			
		||||
	      ms_log (2, "Cannot convert data selection end time (line %d): %s\n",  linecount, selend);
 | 
			
		||||
	      return -1;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
      else
 | 
			
		||||
	{
 | 
			
		||||
	  endtime = HPTERROR;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Add selection to list */
 | 
			
		||||
      if ( ms_addselect_comp (ppselections, selnet, selsta, selloc, selchan, selqual, starttime, endtime) )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log (2, "[%s] Error adding selection on line %d\n", filename, linecount);
 | 
			
		||||
	  return -1;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      selectcount++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if ( fp != stdin )
 | 
			
		||||
    fclose (fp);
 | 
			
		||||
  
 | 
			
		||||
  return selectcount;
 | 
			
		||||
} /* End of ms_readselectionsfile() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_freeselections:
 | 
			
		||||
 *
 | 
			
		||||
 * Free all memory associated with a Selections struct.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
void
 | 
			
		||||
ms_freeselections ( Selections *selections )
 | 
			
		||||
{
 | 
			
		||||
  Selections *select;
 | 
			
		||||
  Selections *selectnext;
 | 
			
		||||
  SelectTime *selecttime;
 | 
			
		||||
  SelectTime *selecttimenext;
 | 
			
		||||
  
 | 
			
		||||
  if ( selections )
 | 
			
		||||
    {
 | 
			
		||||
      select = selections;
 | 
			
		||||
      
 | 
			
		||||
      while ( select )
 | 
			
		||||
	{
 | 
			
		||||
	  selectnext = select->next;
 | 
			
		||||
	  
 | 
			
		||||
	  selecttime = select->timewindows;
 | 
			
		||||
	  
 | 
			
		||||
	  while ( selecttime )
 | 
			
		||||
	    {
 | 
			
		||||
	      selecttimenext = selecttime->next;
 | 
			
		||||
	      
 | 
			
		||||
	      free (selecttime);
 | 
			
		||||
	      
 | 
			
		||||
	      selecttime = selecttimenext;
 | 
			
		||||
	    }
 | 
			
		||||
	  
 | 
			
		||||
	  free (select);
 | 
			
		||||
	  
 | 
			
		||||
	  select = selectnext;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
} /* End of ms_freeselections() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * ms_printselections:
 | 
			
		||||
 *
 | 
			
		||||
 * Print the selections list using the ms_log() facility.
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
void
 | 
			
		||||
ms_printselections ( Selections *selections )
 | 
			
		||||
{
 | 
			
		||||
  Selections *select;
 | 
			
		||||
  SelectTime *selecttime;
 | 
			
		||||
  char starttime[50];
 | 
			
		||||
  char endtime[50];
 | 
			
		||||
  
 | 
			
		||||
  if ( ! selections )
 | 
			
		||||
    return;
 | 
			
		||||
  
 | 
			
		||||
  select = selections;
 | 
			
		||||
  while ( select )
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (0, "Selection: %s\n", select->srcname);
 | 
			
		||||
      
 | 
			
		||||
      selecttime = select->timewindows;
 | 
			
		||||
      while ( selecttime )
 | 
			
		||||
	{
 | 
			
		||||
	  if ( selecttime->starttime != HPTERROR )
 | 
			
		||||
	    ms_hptime2seedtimestr (selecttime->starttime, starttime, 1);
 | 
			
		||||
	  else
 | 
			
		||||
	    strncpy (starttime, "No start time", sizeof(starttime)-1);
 | 
			
		||||
	  
 | 
			
		||||
	  if ( selecttime->endtime != HPTERROR )
 | 
			
		||||
	    ms_hptime2seedtimestr (selecttime->endtime, endtime, 1);
 | 
			
		||||
	  else
 | 
			
		||||
	    strncpy (endtime, "No end time", sizeof(endtime)-1);
 | 
			
		||||
	  
 | 
			
		||||
	  ms_log (0, "  %30s  %30s\n", starttime, endtime);
 | 
			
		||||
	  
 | 
			
		||||
	  selecttime = selecttime->next;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      select = select->next;
 | 
			
		||||
    }
 | 
			
		||||
} /* End of ms_printselections() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/***********************************************************************
 | 
			
		||||
 * robust glob pattern matcher
 | 
			
		||||
 * ozan s. yigit/dec 1994
 | 
			
		||||
 * public domain
 | 
			
		||||
 *
 | 
			
		||||
 * glob patterns:
 | 
			
		||||
 *	*	matches zero or more characters
 | 
			
		||||
 *	?	matches any single character
 | 
			
		||||
 *	[set]	matches any character in the set
 | 
			
		||||
 *	[^set]	matches any character NOT in the set
 | 
			
		||||
 *		where a set is a group of characters or ranges. a range
 | 
			
		||||
 *		is written as two characters seperated with a hyphen: a-z denotes
 | 
			
		||||
 *		all characters between a to z inclusive.
 | 
			
		||||
 *	[-set]	set matches a literal hypen and any character in the set
 | 
			
		||||
 *	[]set]	matches a literal close bracket and any character in the set
 | 
			
		||||
 *
 | 
			
		||||
 *	char	matches itself except where char is '*' or '?' or '['
 | 
			
		||||
 *	\char	matches char, including any pattern character
 | 
			
		||||
 *
 | 
			
		||||
 * examples:
 | 
			
		||||
 *	a*c		ac abc abbc ...
 | 
			
		||||
 *	a?c		acc abc aXc ...
 | 
			
		||||
 *	a[a-z]c		aac abc acc ...
 | 
			
		||||
 *	a[-a-z]c	a-c aac abc ...
 | 
			
		||||
 *
 | 
			
		||||
 * Revision 1.4  2004/12/26  12:38:00  ct
 | 
			
		||||
 * Changed function name (amatch -> globmatch), variables and
 | 
			
		||||
 * formatting for clarity.  Also add matching header globmatch.h.
 | 
			
		||||
 *
 | 
			
		||||
 * Revision 1.3  1995/09/14  23:24:23  oz
 | 
			
		||||
 * removed boring test/main code.
 | 
			
		||||
 *
 | 
			
		||||
 * Revision 1.2  94/12/11  10:38:15  oz
 | 
			
		||||
 * charset code fixed. it is now robust and interprets all
 | 
			
		||||
 * variations of charset [i think] correctly, including [z-a] etc.
 | 
			
		||||
 * 
 | 
			
		||||
 * Revision 1.1  94/12/08  12:45:23  oz
 | 
			
		||||
 * Initial revision
 | 
			
		||||
 ***********************************************************************/
 | 
			
		||||
 | 
			
		||||
#define GLOBMATCH_TRUE    1
 | 
			
		||||
#define GLOBMATCH_FALSE   0
 | 
			
		||||
#define GLOBMATCH_NEGATE '^'       /* std char set negation char */
 | 
			
		||||
 | 
			
		||||
/***********************************************************************
 | 
			
		||||
 * ms_globmatch:
 | 
			
		||||
 *
 | 
			
		||||
 * Check if a string matches a globbing pattern.
 | 
			
		||||
 *
 | 
			
		||||
 * Return 0 if string does not match pattern and non-zero otherwise.
 | 
			
		||||
 **********************************************************************/
 | 
			
		||||
static int
 | 
			
		||||
ms_globmatch (char *string, char *pattern)
 | 
			
		||||
{
 | 
			
		||||
  int negate;
 | 
			
		||||
  int match;
 | 
			
		||||
  int c;
 | 
			
		||||
  
 | 
			
		||||
  while ( *pattern )
 | 
			
		||||
    {
 | 
			
		||||
      if ( !*string && *pattern != '*' )
 | 
			
		||||
	return GLOBMATCH_FALSE;
 | 
			
		||||
      
 | 
			
		||||
      switch ( c = *pattern++ )
 | 
			
		||||
	{
 | 
			
		||||
	  
 | 
			
		||||
	case '*':
 | 
			
		||||
	  while ( *pattern == '*' )
 | 
			
		||||
	    pattern++;
 | 
			
		||||
	  
 | 
			
		||||
	  if ( !*pattern )
 | 
			
		||||
	    return GLOBMATCH_TRUE;
 | 
			
		||||
	  
 | 
			
		||||
	  if ( *pattern != '?' && *pattern != '[' && *pattern != '\\' )
 | 
			
		||||
	    while ( *string && *pattern != *string )
 | 
			
		||||
	      string++;
 | 
			
		||||
	  
 | 
			
		||||
	  while ( *string )
 | 
			
		||||
	    {
 | 
			
		||||
	      if ( ms_globmatch(string, pattern) )
 | 
			
		||||
		return GLOBMATCH_TRUE;
 | 
			
		||||
	      string++;
 | 
			
		||||
	    }
 | 
			
		||||
	  return GLOBMATCH_FALSE;
 | 
			
		||||
	  
 | 
			
		||||
	case '?':
 | 
			
		||||
	  if ( *string )
 | 
			
		||||
	    break;
 | 
			
		||||
	  return GLOBMATCH_FALSE;
 | 
			
		||||
	  
 | 
			
		||||
	  /* set specification is inclusive, that is [a-z] is a, z and
 | 
			
		||||
	   * everything in between. this means [z-a] may be interpreted
 | 
			
		||||
	   * as a set that contains z, a and nothing in between.
 | 
			
		||||
	   */
 | 
			
		||||
	case '[':
 | 
			
		||||
	  if ( *pattern != GLOBMATCH_NEGATE )
 | 
			
		||||
	    negate = GLOBMATCH_FALSE;
 | 
			
		||||
	  else
 | 
			
		||||
	    {
 | 
			
		||||
	      negate = GLOBMATCH_TRUE;
 | 
			
		||||
	      pattern++;
 | 
			
		||||
	    }
 | 
			
		||||
	  
 | 
			
		||||
	  match = GLOBMATCH_FALSE;
 | 
			
		||||
	  
 | 
			
		||||
	  while ( !match && (c = *pattern++) )
 | 
			
		||||
	    {
 | 
			
		||||
	      if ( !*pattern )
 | 
			
		||||
		return GLOBMATCH_FALSE;
 | 
			
		||||
	      
 | 
			
		||||
	      if ( *pattern == '-' ) 	/* c-c */
 | 
			
		||||
		{
 | 
			
		||||
		  if ( !*++pattern )
 | 
			
		||||
		    return GLOBMATCH_FALSE;
 | 
			
		||||
		  if ( *pattern != ']' )
 | 
			
		||||
		    {
 | 
			
		||||
		      if ( *string == c || *string == *pattern ||
 | 
			
		||||
			   ( *string > c && *string < *pattern ) )
 | 
			
		||||
			match = GLOBMATCH_TRUE;
 | 
			
		||||
		    }
 | 
			
		||||
		  else
 | 
			
		||||
		    {		/* c-] */
 | 
			
		||||
		      if ( *string >= c )
 | 
			
		||||
			match = GLOBMATCH_TRUE;
 | 
			
		||||
		      break;
 | 
			
		||||
		    }
 | 
			
		||||
		}
 | 
			
		||||
	      else			/* cc or c] */
 | 
			
		||||
		{
 | 
			
		||||
		  if ( c == *string )
 | 
			
		||||
		    match = GLOBMATCH_TRUE;
 | 
			
		||||
		  if ( *pattern != ']' )
 | 
			
		||||
		    {
 | 
			
		||||
		      if ( *pattern == *string )
 | 
			
		||||
			match = GLOBMATCH_TRUE;
 | 
			
		||||
		    }
 | 
			
		||||
		  else
 | 
			
		||||
		    break;
 | 
			
		||||
		}
 | 
			
		||||
	    } 
 | 
			
		||||
	  
 | 
			
		||||
	  if ( negate == match )
 | 
			
		||||
	    return GLOBMATCH_FALSE;
 | 
			
		||||
	  
 | 
			
		||||
	  /*
 | 
			
		||||
	   * if there is a match, skip past the charset and continue on
 | 
			
		||||
	   */
 | 
			
		||||
	  while ( *pattern && *pattern != ']' )
 | 
			
		||||
	    pattern++;
 | 
			
		||||
	  if ( !*pattern++ )	/* oops! */
 | 
			
		||||
	    return GLOBMATCH_FALSE;
 | 
			
		||||
	  break;
 | 
			
		||||
	  
 | 
			
		||||
	case '\\':
 | 
			
		||||
	  if ( *pattern )
 | 
			
		||||
	    c = *pattern++;
 | 
			
		||||
	default:
 | 
			
		||||
	  if ( c != *string )
 | 
			
		||||
	    return GLOBMATCH_FALSE;
 | 
			
		||||
	  break;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      string++;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return !*string;
 | 
			
		||||
}  /* End of ms_globmatch() */
 | 
			
		||||
							
								
								
									
										51
									
								
								libs/3rd-party/mseed/steimdata.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								libs/3rd-party/mseed/steimdata.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * steimdata.h:
 | 
			
		||||
 * 
 | 
			
		||||
 * Declarations for Steim compression routines.
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2004.278
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef STEIMDATA_H
 | 
			
		||||
#define STEIMDATA_H 1
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define STEIM1_FRAME_MAX_SAMPLES  60
 | 
			
		||||
#define STEIM2_FRAME_MAX_SAMPLES  105
 | 
			
		||||
 | 
			
		||||
#define VALS_PER_FRAME  15      /* # of ints for data per frame.*/
 | 
			
		||||
 | 
			
		||||
#define STEIM1_SPECIAL_MASK     0
 | 
			
		||||
#define STEIM1_BYTE_MASK        1
 | 
			
		||||
#define STEIM1_HALFWORD_MASK    2
 | 
			
		||||
#define STEIM1_FULLWORD_MASK    3
 | 
			
		||||
 | 
			
		||||
#define STEIM2_SPECIAL_MASK     0
 | 
			
		||||
#define STEIM2_BYTE_MASK        1
 | 
			
		||||
#define STEIM2_123_MASK         2
 | 
			
		||||
#define STEIM2_567_MASK         3
 | 
			
		||||
 | 
			
		||||
typedef union u_diff {          /* union for Steim objects.     */
 | 
			
		||||
  int8_t          byte[4];      /* 4 1-byte differences.        */
 | 
			
		||||
  int16_t         hw[2];        /* 2 halfword differences.      */
 | 
			
		||||
  int32_t         fw;           /* 1 fullword difference.       */
 | 
			
		||||
} U_DIFF;
 | 
			
		||||
 | 
			
		||||
typedef struct frame {          /* frame in a seed data record. */
 | 
			
		||||
  uint32_t        ctrl;         /* control word for frame.      */
 | 
			
		||||
  U_DIFF          w[15];        /* compressed data.             */
 | 
			
		||||
} FRAME;
 | 
			
		||||
 | 
			
		||||
typedef struct dframes {        /* seed data frames.            */
 | 
			
		||||
    FRAME f[1];                 /* data record header frames.   */
 | 
			
		||||
} DFRAMES;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* STEIMDATA_H */
 | 
			
		||||
							
								
								
									
										1277
									
								
								libs/3rd-party/mseed/tracelist.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1277
									
								
								libs/3rd-party/mseed/tracelist.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1855
									
								
								libs/3rd-party/mseed/traceutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1855
									
								
								libs/3rd-party/mseed/traceutils.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1083
									
								
								libs/3rd-party/mseed/unpack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1083
									
								
								libs/3rd-party/mseed/unpack.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										892
									
								
								libs/3rd-party/mseed/unpackdata.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										892
									
								
								libs/3rd-party/mseed/unpackdata.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,892 @@
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  Routines for unpacking INT_16, INT_32, FLOAT_32, FLOAT_64,
 | 
			
		||||
 *  STEIM1, STEIM2, GEOSCOPE (24bit and gain ranged), CDSN, SRO
 | 
			
		||||
 *  and DWWSSN encoded data records.
 | 
			
		||||
 *
 | 
			
		||||
 *  Some routines originated and were borrowed from qlib2 by:
 | 
			
		||||
 *
 | 
			
		||||
 *	Douglas Neuhauser
 | 
			
		||||
 *	Seismographic Station
 | 
			
		||||
 *	University of California, Berkeley
 | 
			
		||||
 *	doug@seismo.berkeley.edu
 | 
			
		||||
 *									
 | 
			
		||||
 *  Modified by Chad Trabant,
 | 
			
		||||
 *  (previously) ORFEUS/EC-Project MEREDIAN
 | 
			
		||||
 *  (currently) IRIS Data Management Center
 | 
			
		||||
 *
 | 
			
		||||
 *  modified: 2012.357
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 1996 The Regents of the University of California.
 | 
			
		||||
 * All Rights Reserved.
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission to use, copy, modify, and distribute this software and its
 | 
			
		||||
 * documentation for educational, research and non-profit purposes,
 | 
			
		||||
 * without fee, and without a written agreement is hereby granted,
 | 
			
		||||
 * provided that the above copyright notice, this paragraph and the
 | 
			
		||||
 * following three paragraphs appear in all copies.
 | 
			
		||||
 * 
 | 
			
		||||
 * Permission to incorporate this software into commercial products may
 | 
			
		||||
 * be obtained from the Office of Technology Licensing, 2150 Shattuck
 | 
			
		||||
 * Avenue, Suite 510, Berkeley, CA  94704.
 | 
			
		||||
 * 
 | 
			
		||||
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 | 
			
		||||
 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
 | 
			
		||||
 * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND
 | 
			
		||||
 * ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN
 | 
			
		||||
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 * 
 | 
			
		||||
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE
 | 
			
		||||
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 | 
			
		||||
 * CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 | 
			
		||||
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <memory.h>
 | 
			
		||||
 | 
			
		||||
#include "libmseed.h"
 | 
			
		||||
#include "unpackdata.h"
 | 
			
		||||
 | 
			
		||||
#define MAX12 0x7ff         /* maximum 12 bit positive # */
 | 
			
		||||
#define MAX14 0x1fff        /* maximum 14 bit positive # */
 | 
			
		||||
#define MAX16 0x7fff        /* maximum 16 bit positive # */
 | 
			
		||||
#define MAX24 0x7fffff      /* maximum 24 bit positive # */
 | 
			
		||||
 | 
			
		||||
/* For Steim encodings */
 | 
			
		||||
#define X0  pf->w[0].fw
 | 
			
		||||
#define XN  pf->w[1].fw
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_int_16:							*
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack int_16 miniSEED data and place in supplied buffer.           *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_int_16 
 | 
			
		||||
 (int16_t      *ibuf,		/* ptr to input data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)       /* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int		nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  int16_t	stmp;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++) {
 | 
			
		||||
    stmp = ibuf[nd];
 | 
			
		||||
    if ( swapflag ) ms_gswap2a (&stmp);
 | 
			
		||||
    databuff[nd] = stmp;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_int_16() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_int_32:							*
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack int_32 miniSEED data and place in supplied buffer.           *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_int_32
 | 
			
		||||
 (int32_t      *ibuf,		/* ptr to input data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int		nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  int32_t    	itmp;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++) {
 | 
			
		||||
    itmp = ibuf[nd];
 | 
			
		||||
    if ( swapflag) ms_gswap4a (&itmp);
 | 
			
		||||
    databuff[nd] = itmp;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_int_32() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_float_32:	       				 	*
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack float_32 miniSEED data and place in supplied buffer.	        *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_float_32
 | 
			
		||||
 (float	       *fbuf,		/* ptr to input data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  float	       *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int		nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  float    	ftmp;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++) {
 | 
			
		||||
    memcpy (&ftmp, &fbuf[nd], sizeof(float));
 | 
			
		||||
    if ( swapflag ) ms_gswap4a (&ftmp);
 | 
			
		||||
    databuff[nd] = ftmp;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_float_32() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_float_64:	       					*
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack float_64 miniSEED data and place in supplied buffer.	        *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_float_64
 | 
			
		||||
 (double       *fbuf,		/* ptr to input data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  double       *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int		nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  double  	dtmp;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++) {
 | 
			
		||||
    memcpy (&dtmp, &fbuf[nd], sizeof(double));
 | 
			
		||||
    if ( swapflag ) ms_gswap8a (&dtmp);
 | 
			
		||||
    databuff[nd] = dtmp;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_float_64() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_steim1:							*
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack STEIM1 data frames and place in supplied buffer.		*
 | 
			
		||||
 *  See the SEED format manual for Steim-1 encoding details.            *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned or negative error code.               *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_steim1
 | 
			
		||||
 (FRAME	       *pf,		/* ptr to Steim1 data frames.		*/
 | 
			
		||||
  int		nbytes,		/* number of bytes in all data frames.	*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in all frames.*/
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int32_t      *diffbuff,	/* ptr to unpacked diff array.		*/
 | 
			
		||||
  int32_t      *px0,		/* return X0, first sample in frame.	*/
 | 
			
		||||
  int32_t      *pxn,		/* return XN, last sample in frame.	*/
 | 
			
		||||
  int		swapflag,	/* if data should be swapped.	        */
 | 
			
		||||
  int           verbose)
 | 
			
		||||
{
 | 
			
		||||
  int32_t      *diff = diffbuff;
 | 
			
		||||
  int32_t      *data = databuff;
 | 
			
		||||
  int32_t      *prev;
 | 
			
		||||
  int	        num_data_frames = nbytes / sizeof(FRAME);
 | 
			
		||||
  int		nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  int		fn;		/* current frame number.		*/
 | 
			
		||||
  int		wn;		/* current work number in the frame.	*/
 | 
			
		||||
  int		compflag;      	/* current compression flag.		*/
 | 
			
		||||
  int		nr, i;
 | 
			
		||||
  int32_t	last_data;
 | 
			
		||||
  int32_t	itmp;
 | 
			
		||||
  int16_t	stmp;
 | 
			
		||||
  uint32_t	ctrl;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (num_samples == 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  /* Extract forward and reverse integration constants in first frame */
 | 
			
		||||
  *px0 = X0;
 | 
			
		||||
  *pxn = XN;
 | 
			
		||||
  
 | 
			
		||||
  if ( swapflag )
 | 
			
		||||
    {
 | 
			
		||||
      ms_gswap4a (px0);
 | 
			
		||||
      ms_gswap4a (pxn);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if ( verbose > 2 )
 | 
			
		||||
    ms_log (1, "%s: forward/reverse integration constants:\nX0: %d  XN: %d\n",
 | 
			
		||||
	    UNPACK_SRCNAME, *px0, *pxn);
 | 
			
		||||
  
 | 
			
		||||
  /* Decode compressed data in each frame */
 | 
			
		||||
  for (fn = 0; fn < num_data_frames; fn++)
 | 
			
		||||
    {
 | 
			
		||||
      
 | 
			
		||||
      ctrl = pf->ctrl;
 | 
			
		||||
      if ( swapflag ) ms_gswap4a (&ctrl);
 | 
			
		||||
 | 
			
		||||
      for (wn = 0; wn < VALS_PER_FRAME; wn++)
 | 
			
		||||
	{
 | 
			
		||||
	  if (nd >= num_samples) break;
 | 
			
		||||
	  
 | 
			
		||||
	  compflag = (ctrl >> ((VALS_PER_FRAME-wn-1)*2)) & 0x3;
 | 
			
		||||
	  
 | 
			
		||||
	  switch (compflag)
 | 
			
		||||
	    {
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM1_SPECIAL_MASK:
 | 
			
		||||
	      /* Headers info -- skip it */
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM1_BYTE_MASK:
 | 
			
		||||
	      /* Next 4 bytes are 4 1-byte differences */
 | 
			
		||||
	      for (i=0; i < 4 && nd < num_samples; i++, nd++)
 | 
			
		||||
		*diff++ = pf->w[wn].byte[i];
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM1_HALFWORD_MASK:
 | 
			
		||||
	      /* Next 4 bytes are 2 2-byte differences */
 | 
			
		||||
	      for (i=0; i < 2 && nd < num_samples; i++, nd++)
 | 
			
		||||
		{
 | 
			
		||||
		  if ( swapflag )
 | 
			
		||||
		    {
 | 
			
		||||
		      stmp = pf->w[wn].hw[i];
 | 
			
		||||
		      ms_gswap2a (&stmp);
 | 
			
		||||
		      *diff++ = stmp;
 | 
			
		||||
		    }
 | 
			
		||||
		  else *diff++ = pf->w[wn].hw[i];
 | 
			
		||||
		}
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM1_FULLWORD_MASK:
 | 
			
		||||
	      /* Next 4 bytes are 1 4-byte difference */
 | 
			
		||||
	      if ( swapflag )
 | 
			
		||||
		{
 | 
			
		||||
		  itmp = pf->w[wn].fw;
 | 
			
		||||
		  ms_gswap4a (&itmp);
 | 
			
		||||
		  *diff++ = itmp;
 | 
			
		||||
		}
 | 
			
		||||
	      else *diff++ = pf->w[wn].fw;
 | 
			
		||||
	      nd++;
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    default:
 | 
			
		||||
	      /* Should NEVER get here */
 | 
			
		||||
	      ms_log (2, "msr_unpack_steim1(%s): invalid compression flag = %d\n",
 | 
			
		||||
		      UNPACK_SRCNAME, compflag);
 | 
			
		||||
	      return MS_STBADCOMPFLAG;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
      ++pf;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  /* Test if the number of samples implied by the data frames is the
 | 
			
		||||
   * same number indicated in the header.
 | 
			
		||||
   */
 | 
			
		||||
  if ( nd != num_samples )
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (1, "Warning: msr_unpack_steim1(%s): number of samples indicated in header (%d) does not equal data (%d)\n",
 | 
			
		||||
	      UNPACK_SRCNAME, num_samples, nd);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  /*	For now, assume sample count in header to be correct.		*/
 | 
			
		||||
  /*	One way of "trimming" data from a block is simply to reduce	*/
 | 
			
		||||
  /*	the sample count.  It is not clear from the documentation	*/
 | 
			
		||||
  /*	whether this is a valid or not, but it appears to be done	*/
 | 
			
		||||
  /*	by other program, so we should not complain about its effect.	*/
 | 
			
		||||
  
 | 
			
		||||
  nr = req_samples;
 | 
			
		||||
  
 | 
			
		||||
  /* Compute first value based on last_value from previous buffer.	*/
 | 
			
		||||
  /* The two should correspond in all cases EXCEPT for the first	*/
 | 
			
		||||
  /* record for each component (because we don't have a valid xn from	*/
 | 
			
		||||
  /* a previous record).  Although the Steim compression algorithm	*/
 | 
			
		||||
  /* defines x(-1) as 0 for the first record, this only works for the	*/
 | 
			
		||||
  /* first record created since coldstart of the datalogger, NOT the	*/
 | 
			
		||||
  /* first record of an arbitrary starting record.	                */
 | 
			
		||||
  
 | 
			
		||||
  /* In all cases, assume x0 is correct, since we don't have x(-1).	*/
 | 
			
		||||
  data = databuff;
 | 
			
		||||
  diff = diffbuff;
 | 
			
		||||
  last_data = *px0;
 | 
			
		||||
  if (nr > 0)
 | 
			
		||||
    *data = *px0;
 | 
			
		||||
  
 | 
			
		||||
  /* Compute all but first values based on previous value               */
 | 
			
		||||
  prev = data - 1;
 | 
			
		||||
  while (--nr > 0 && --nd > 0)
 | 
			
		||||
    last_data = *++data = *++diff + *++prev;
 | 
			
		||||
  
 | 
			
		||||
  /* If a short count was requested compute the last sample in order    */
 | 
			
		||||
  /* to perform the integrity check comparison                          */
 | 
			
		||||
  while (--nd > 0)
 | 
			
		||||
    last_data = *++diff + last_data;
 | 
			
		||||
  
 | 
			
		||||
  /* Verify that the last value is identical to xn = rev. int. constant */
 | 
			
		||||
  if (last_data != *pxn)
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (1, "%s: Warning: Data integrity check for Steim-1 failed, last_data=%d, xn=%d\n",
 | 
			
		||||
	      UNPACK_SRCNAME, last_data, *pxn);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return ((req_samples < num_samples) ? req_samples : num_samples);
 | 
			
		||||
}  /* End of msr_unpack_steim1() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_steim2:							*
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack STEIM2 data frames and place in supplied buffer.		*
 | 
			
		||||
 *  See the SEED format manual for Steim-2 encoding details.            *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned or negative error code.               *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_steim2 
 | 
			
		||||
 (FRAME	       *pf,		/* ptr to Steim2 data frames.		*/
 | 
			
		||||
  int		nbytes,		/* number of bytes in all data frames.	*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in all frames.*/
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int32_t      *diffbuff,	/* ptr to unpacked diff array.		*/
 | 
			
		||||
  int32_t      *px0,		/* return X0, first sample in frame.	*/
 | 
			
		||||
  int32_t      *pxn,		/* return XN, last sample in frame.	*/
 | 
			
		||||
  int		swapflag,	/* if data should be swapped.	        */
 | 
			
		||||
  int           verbose)
 | 
			
		||||
{
 | 
			
		||||
  int32_t      *diff = diffbuff;
 | 
			
		||||
  int32_t      *data = databuff;
 | 
			
		||||
  int32_t      *prev;
 | 
			
		||||
  int		num_data_frames = nbytes / sizeof(FRAME);
 | 
			
		||||
  int		nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  int		fn;		/* current frame number.		*/
 | 
			
		||||
  int		wn;		/* current work number in the frame.	*/
 | 
			
		||||
  int		compflag;     	/* current compression flag.		*/
 | 
			
		||||
  int		nr, i;
 | 
			
		||||
  int		n, bits, m1, m2;
 | 
			
		||||
  int32_t	last_data;
 | 
			
		||||
  int32_t    	val;
 | 
			
		||||
  int8_t	dnib;
 | 
			
		||||
  uint32_t	ctrl;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (num_samples == 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  /* Extract forward and reverse integration constants in first frame.*/
 | 
			
		||||
  *px0 = X0;
 | 
			
		||||
  *pxn = XN;
 | 
			
		||||
  
 | 
			
		||||
  if ( swapflag )
 | 
			
		||||
    {
 | 
			
		||||
      ms_gswap4a (px0);
 | 
			
		||||
      ms_gswap4a (pxn);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  if ( verbose > 2 )
 | 
			
		||||
    ms_log (1, "%s: forward/reverse integration constants:  X0: %d  XN: %d\n",
 | 
			
		||||
	    UNPACK_SRCNAME, *px0, *pxn);
 | 
			
		||||
  
 | 
			
		||||
  /* Decode compressed data in each frame */
 | 
			
		||||
  for (fn = 0; fn < num_data_frames; fn++)
 | 
			
		||||
    {
 | 
			
		||||
      
 | 
			
		||||
      ctrl = pf->ctrl;
 | 
			
		||||
      if ( swapflag ) ms_gswap4a (&ctrl);
 | 
			
		||||
      
 | 
			
		||||
      for (wn = 0; wn < VALS_PER_FRAME; wn++)
 | 
			
		||||
	{
 | 
			
		||||
	  if (nd >= num_samples) break;
 | 
			
		||||
	  
 | 
			
		||||
	  compflag = (ctrl >> ((VALS_PER_FRAME-wn-1)*2)) & 0x3;
 | 
			
		||||
	  
 | 
			
		||||
	  switch (compflag)
 | 
			
		||||
	    {
 | 
			
		||||
	    case STEIM2_SPECIAL_MASK:
 | 
			
		||||
	      /* Headers info -- skip it */
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM2_BYTE_MASK:
 | 
			
		||||
	      /* Next 4 bytes are 4 1-byte differences */
 | 
			
		||||
	      for (i=0; i < 4 && nd < num_samples; i++, nd++)
 | 
			
		||||
		*diff++ = pf->w[wn].byte[i];
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM2_123_MASK:
 | 
			
		||||
	      val = pf->w[wn].fw;
 | 
			
		||||
	      if ( swapflag ) ms_gswap4a (&val);
 | 
			
		||||
	      dnib =  val >> 30 & 0x3;
 | 
			
		||||
	      switch (dnib)
 | 
			
		||||
		{
 | 
			
		||||
		case 1:	/* 1 30-bit difference */
 | 
			
		||||
		  bits = 30; n = 1; m1 = 0x3fffffff; m2 = 0x20000000; break;
 | 
			
		||||
		case 2:	/* 2 15-bit differences */
 | 
			
		||||
		  bits = 15; n = 2; m1 = 0x00007fff; m2 = 0x00004000; break;
 | 
			
		||||
		case 3:	/* 3 10-bit differences */
 | 
			
		||||
		  bits = 10; n = 3; m1 = 0x000003ff; m2 = 0x00000200; break;
 | 
			
		||||
		default:	/*  should NEVER get here  */
 | 
			
		||||
		  ms_log (2, "msr_unpack_steim2(%s): invalid compflag, dnib, fn, wn = %d, %d, %d, %d\n", 
 | 
			
		||||
			  UNPACK_SRCNAME, compflag, dnib, fn, wn);
 | 
			
		||||
		  return MS_STBADCOMPFLAG;
 | 
			
		||||
		}
 | 
			
		||||
	      /*  Uncompress the differences */
 | 
			
		||||
	      for (i=(n-1)*bits; i >= 0 && nd < num_samples; i-=bits, nd++)
 | 
			
		||||
		{
 | 
			
		||||
		  *diff = (val >> i) & m1;
 | 
			
		||||
		  *diff = (*diff & m2) ? *diff | ~m1 : *diff;
 | 
			
		||||
		  diff++;
 | 
			
		||||
		}
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    case STEIM2_567_MASK:
 | 
			
		||||
	      val = pf->w[wn].fw;
 | 
			
		||||
	      if ( swapflag ) ms_gswap4a (&val);
 | 
			
		||||
	      dnib =  val >> 30 & 0x3;
 | 
			
		||||
	      switch (dnib)
 | 
			
		||||
		{
 | 
			
		||||
		case 0:	/*  5 6-bit differences  */
 | 
			
		||||
		  bits = 6; n = 5; m1 = 0x0000003f; m2 = 0x00000020; break;
 | 
			
		||||
		case 1:	/*  6 5-bit differences  */
 | 
			
		||||
		  bits = 5; n = 6; m1 = 0x0000001f; m2 = 0x00000010; break;
 | 
			
		||||
		case 2:	/*  7 4-bit differences  */
 | 
			
		||||
		  bits = 4; n = 7; m1 = 0x0000000f; m2 = 0x00000008; break;
 | 
			
		||||
		default:
 | 
			
		||||
		  ms_log (2, "msr_unpack_steim2(%s): invalid compflag, dnib, fn, wn = %d, %d, %d, %d\n", 
 | 
			
		||||
			  UNPACK_SRCNAME, compflag, dnib, fn, wn);
 | 
			
		||||
		  return MS_STBADCOMPFLAG;
 | 
			
		||||
		}
 | 
			
		||||
	      /* Uncompress the differences */
 | 
			
		||||
	      for (i=(n-1)*bits; i >= 0 && nd < num_samples; i-=bits, nd++)
 | 
			
		||||
		{
 | 
			
		||||
		  *diff = (val >> i) & m1;
 | 
			
		||||
		  *diff = (*diff & m2) ? *diff | ~m1 : *diff;
 | 
			
		||||
		  diff++;
 | 
			
		||||
		}
 | 
			
		||||
	      break;
 | 
			
		||||
	      
 | 
			
		||||
	    default:
 | 
			
		||||
	      /* Should NEVER get here */
 | 
			
		||||
	      ms_log (2, "msr_unpack_steim2(%s): invalid compflag, fn, wn = %d, %d, %d - nsamp: %d\n",
 | 
			
		||||
		      UNPACK_SRCNAME, compflag, fn, wn, nd);
 | 
			
		||||
	      return MS_STBADCOMPFLAG;
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
      ++pf;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
  /* Test if the number of samples implied by the data frames is the
 | 
			
		||||
   * same number indicated in the header.
 | 
			
		||||
   */
 | 
			
		||||
  if ( nd != num_samples )
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (1, "Warning: msr_unpack_steim2(%s): number of samples indicated in header (%d) does not equal data (%d)\n",
 | 
			
		||||
	      UNPACK_SRCNAME, num_samples, nd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  /*	For now, assume sample count in header to be correct.		*/
 | 
			
		||||
  /*	One way of "trimming" data from a block is simply to reduce	*/
 | 
			
		||||
  /*	the sample count.  It is not clear from the documentation	*/
 | 
			
		||||
  /*	whether this is a valid or not, but it appears to be done	*/
 | 
			
		||||
  /*	by other program, so we should not complain about its effect.	*/
 | 
			
		||||
  
 | 
			
		||||
  nr = req_samples;
 | 
			
		||||
  
 | 
			
		||||
  /* Compute first value based on last_value from previous buffer.	*/
 | 
			
		||||
  /* The two should correspond in all cases EXCEPT for the first	*/
 | 
			
		||||
  /* record for each component (because we don't have a valid xn from	*/
 | 
			
		||||
  /* a previous record).  Although the Steim compression algorithm	*/
 | 
			
		||||
  /* defines x(-1) as 0 for the first record, this only works for the	*/
 | 
			
		||||
  /* first record created since coldstart of the datalogger, NOT the	*/
 | 
			
		||||
  /* first record of an arbitrary starting record.	                */
 | 
			
		||||
  
 | 
			
		||||
  /* In all cases, assume x0 is correct, since we don't have x(-1).	*/
 | 
			
		||||
  data = databuff;
 | 
			
		||||
  diff = diffbuff;
 | 
			
		||||
  last_data = *px0;
 | 
			
		||||
  if (nr > 0)
 | 
			
		||||
    *data = *px0;
 | 
			
		||||
 | 
			
		||||
  /* Compute all but first values based on previous value               */
 | 
			
		||||
  prev = data - 1;
 | 
			
		||||
  while (--nr > 0 && --nd > 0)
 | 
			
		||||
    last_data = *++data = *++diff + *++prev;
 | 
			
		||||
  
 | 
			
		||||
  /* If a short count was requested compute the last sample in order    */
 | 
			
		||||
  /* to perform the integrity check comparison                          */
 | 
			
		||||
  while (--nd > 0)
 | 
			
		||||
    last_data = *++diff + last_data;
 | 
			
		||||
  
 | 
			
		||||
  /* Verify that the last value is identical to xn = rev. int. constant */
 | 
			
		||||
  if (last_data != *pxn)
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (1, "%s: Warning: Data integrity check for Steim-2 failed, last_data=%d, xn=%d\n",
 | 
			
		||||
	      UNPACK_SRCNAME, last_data, *pxn);
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return ((req_samples < num_samples) ? req_samples : num_samples);
 | 
			
		||||
}  /* End of msr_unpack_steim2() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Defines for GEOSCOPE encoding */
 | 
			
		||||
#define GEOSCOPE_MANTISSA_MASK 0x0fff   /* mask for mantissa */
 | 
			
		||||
#define GEOSCOPE_GAIN3_MASK 0x7000      /* mask for gainrange factor */
 | 
			
		||||
#define GEOSCOPE_GAIN4_MASK 0xf000      /* mask for gainrange factor */
 | 
			
		||||
#define GEOSCOPE_SHIFT 12               /* # bits in mantissa */
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_geoscope:                                                *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack GEOSCOPE gain ranged data (demultiplexed only) encoded       *
 | 
			
		||||
 *  miniSEED data and place in supplied buffer.                         *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_geoscope
 | 
			
		||||
 (const char   *edata,		/* ptr to encoded data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  float	       *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int           encoding,       /* specific GEOSCOPE encoding type      */
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int nd = 0;		/* # of data points in packet.		*/
 | 
			
		||||
  int mantissa;		/* mantissa from SEED data */
 | 
			
		||||
  int gainrange;	/* gain range factor */
 | 
			
		||||
  int exponent;		/* total exponent */
 | 
			
		||||
  int k;
 | 
			
		||||
  uint64_t exp2val;
 | 
			
		||||
  int16_t sint;
 | 
			
		||||
  double dsample = 0.0;
 | 
			
		||||
  
 | 
			
		||||
  union {
 | 
			
		||||
    uint8_t b[4];
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
  } sample32;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
 | 
			
		||||
  /* Make sure we recognize this as a GEOSCOPE encoding format */
 | 
			
		||||
  if ( encoding != DE_GEOSCOPE24 &&
 | 
			
		||||
       encoding != DE_GEOSCOPE163 &&
 | 
			
		||||
       encoding != DE_GEOSCOPE164 )
 | 
			
		||||
    {
 | 
			
		||||
      ms_log (2, "msr_unpack_geoscope(%s): unrecognized GEOSCOPE encoding: %d\n",
 | 
			
		||||
	      UNPACK_SRCNAME, encoding);
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++)
 | 
			
		||||
    {
 | 
			
		||||
      switch (encoding)
 | 
			
		||||
	{
 | 
			
		||||
	case DE_GEOSCOPE24:
 | 
			
		||||
	  sample32.i = 0;
 | 
			
		||||
	  if ( swapflag )
 | 
			
		||||
	    for (k=0; k < 3; k++)
 | 
			
		||||
	      sample32.b[2-k] = edata[k];
 | 
			
		||||
	  else
 | 
			
		||||
	    for (k=0; k < 3; k++)
 | 
			
		||||
	      sample32.b[1+k] = edata[k];
 | 
			
		||||
	  
 | 
			
		||||
	  mantissa = sample32.i;
 | 
			
		||||
 | 
			
		||||
	  /* Take 2's complement for mantissa for overflow */
 | 
			
		||||
	  if (mantissa > MAX24) 
 | 
			
		||||
	    mantissa -= 2 * (MAX24 + 1);
 | 
			
		||||
	  
 | 
			
		||||
	  /* Store */
 | 
			
		||||
	  dsample = (double) mantissa;
 | 
			
		||||
	  
 | 
			
		||||
	  break;
 | 
			
		||||
	case DE_GEOSCOPE163:
 | 
			
		||||
	  memcpy (&sint, edata, sizeof(int16_t));
 | 
			
		||||
	  if ( swapflag ) ms_gswap2a(&sint);
 | 
			
		||||
	  
 | 
			
		||||
	  /* Recover mantissa and gain range factor */
 | 
			
		||||
	  mantissa = (sint & GEOSCOPE_MANTISSA_MASK);
 | 
			
		||||
	  gainrange = (sint & GEOSCOPE_GAIN3_MASK) >> GEOSCOPE_SHIFT;
 | 
			
		||||
	  
 | 
			
		||||
	  /* Exponent is just gainrange for GEOSCOPE */
 | 
			
		||||
	  exponent = gainrange;
 | 
			
		||||
	  
 | 
			
		||||
	  /* Calculate sample as mantissa / 2^exponent */
 | 
			
		||||
	  exp2val = (uint64_t) 1 << exponent;
 | 
			
		||||
	  dsample = ((double) (mantissa-2048)) / exp2val;
 | 
			
		||||
	  
 | 
			
		||||
	  break;
 | 
			
		||||
	case DE_GEOSCOPE164:
 | 
			
		||||
	  memcpy (&sint, edata, sizeof(int16_t));
 | 
			
		||||
	  if ( swapflag ) ms_gswap2a(&sint);
 | 
			
		||||
	  
 | 
			
		||||
	  /* Recover mantissa and gain range factor */
 | 
			
		||||
	  mantissa = (sint & GEOSCOPE_MANTISSA_MASK);
 | 
			
		||||
	  gainrange = (sint & GEOSCOPE_GAIN4_MASK) >> GEOSCOPE_SHIFT;
 | 
			
		||||
	  
 | 
			
		||||
	  /* Exponent is just gainrange for GEOSCOPE */
 | 
			
		||||
	  exponent = gainrange;
 | 
			
		||||
	  
 | 
			
		||||
	  /* Calculate sample as mantissa / 2^exponent */
 | 
			
		||||
	  exp2val = (uint64_t) 1 << exponent;
 | 
			
		||||
	  dsample = ((double) (mantissa-2048)) / exp2val;
 | 
			
		||||
	  
 | 
			
		||||
	  break;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Save sample in output array */
 | 
			
		||||
      databuff[nd] = (float) dsample;
 | 
			
		||||
      
 | 
			
		||||
      /* Increment edata pointer depending on size */
 | 
			
		||||
      switch (encoding)
 | 
			
		||||
	{
 | 
			
		||||
	case DE_GEOSCOPE24:
 | 
			
		||||
	  edata += 3;
 | 
			
		||||
	  break;
 | 
			
		||||
	case DE_GEOSCOPE163:
 | 
			
		||||
	case DE_GEOSCOPE164:
 | 
			
		||||
	  edata += 2;
 | 
			
		||||
	  break;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_geoscope() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Defines for CDSN encoding */
 | 
			
		||||
#define CDSN_MANTISSA_MASK 0x3fff   /* mask for mantissa */
 | 
			
		||||
#define CDSN_GAINRANGE_MASK 0xc000  /* mask for gainrange factor */
 | 
			
		||||
#define CDSN_SHIFT 14               /* # bits in mantissa */
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_cdsn:                                                    *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack CDSN gain ranged data encoded miniSEED data and place in     *
 | 
			
		||||
 *  supplied buffer.                                                    *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Notes from original rdseed routine:                                 *
 | 
			
		||||
 *  CDSN data are compressed according to the formula                   *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  sample = M * (2 exp G)                                              *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  where                                                               *
 | 
			
		||||
 *     sample = seismic data sample                                     *
 | 
			
		||||
 *     M      = mantissa; biased mantissa B is written to tape          *
 | 
			
		||||
 *     G      = exponent of multiplier (i.e. gain range factor);        *
 | 
			
		||||
 *                      key K is written to tape                        *
 | 
			
		||||
 *     exp    = exponentiation operation                                *
 | 
			
		||||
 *     B      = M + 8191, biased mantissa, written to tape              *
 | 
			
		||||
 *     K      = key to multiplier exponent, written to tape             *
 | 
			
		||||
 *                      K may have any of the values 0 - 3, as follows: *
 | 
			
		||||
 *                      0 => G = 0, multiplier = 2 exp 0 = 1            *
 | 
			
		||||
 *                      1 => G = 2, multiplier = 2 exp 2 = 4            *
 | 
			
		||||
 *                      2 => G = 4, multiplier = 2 exp 4 = 16           *
 | 
			
		||||
 *                      3 => G = 7, multiplier = 2 exp 7 = 128          *
 | 
			
		||||
 *     Data are stored on tape in two bytes as follows:                 *
 | 
			
		||||
 *             fedc ba98 7654 3210 = bit number, power of two           *
 | 
			
		||||
 *             KKBB BBBB BBBB BBBB = form of SEED data                  *
 | 
			
		||||
 *             where K = key to multiplier exponent and B = biased mantissa *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *     Masks to recover key to multiplier exponent and biased mantissa  *
 | 
			
		||||
 *     from tape are:                                                   *
 | 
			
		||||
 *             fedc ba98 7654 3210 = bit number = power of two          *
 | 
			
		||||
 *             0011 1111 1111 1111 = 0x3fff     = mask for biased mantissa *
 | 
			
		||||
 *            1100 0000 0000 0000 = 0xc000     = mask for gain range key *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_cdsn
 | 
			
		||||
 (int16_t      *edata,		/* ptr to encoded data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int32_t nd = 0;	/* sample count */
 | 
			
		||||
  int32_t mantissa;	/* mantissa */
 | 
			
		||||
  int32_t gainrange;	/* gain range factor */
 | 
			
		||||
  int32_t mult = -1;    /* multiplier for gain range */
 | 
			
		||||
  uint16_t sint;
 | 
			
		||||
  int32_t sample;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&sint, &edata[nd], sizeof(int16_t));
 | 
			
		||||
      if ( swapflag ) ms_gswap2a(&sint);
 | 
			
		||||
      
 | 
			
		||||
      /* Recover mantissa and gain range factor */
 | 
			
		||||
      mantissa = (sint & CDSN_MANTISSA_MASK);
 | 
			
		||||
      gainrange = (sint & CDSN_GAINRANGE_MASK) >> CDSN_SHIFT;
 | 
			
		||||
      
 | 
			
		||||
      /* Determine multiplier from the gain range factor and format definition
 | 
			
		||||
       * because shift operator is used later, these are powers of two */
 | 
			
		||||
      if ( gainrange == 0 ) mult = 0;
 | 
			
		||||
      else if ( gainrange == 1 ) mult = 2;
 | 
			
		||||
      else if ( gainrange == 2 ) mult = 4;
 | 
			
		||||
      else if ( gainrange == 3 ) mult = 7;
 | 
			
		||||
      
 | 
			
		||||
      /* Unbias the mantissa */
 | 
			
		||||
      mantissa -= MAX14;
 | 
			
		||||
      
 | 
			
		||||
      /* Calculate sample from mantissa and multiplier using left shift
 | 
			
		||||
       * mantissa << mult is equivalent to mantissa * (2 exp (mult)) */
 | 
			
		||||
      sample = (mantissa << mult);
 | 
			
		||||
      
 | 
			
		||||
      /* Save sample in output array */
 | 
			
		||||
      databuff[nd] = sample;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_cdsn() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Defines for SRO encoding */
 | 
			
		||||
#define SRO_MANTISSA_MASK 0x0fff   /* mask for mantissa */
 | 
			
		||||
#define SRO_GAINRANGE_MASK 0xf000  /* mask for gainrange factor */
 | 
			
		||||
#define SRO_SHIFT 12               /* # bits in mantissa */
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_sro:                                                     *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack SRO gain ranged data encoded miniSEED data and place in      *
 | 
			
		||||
 *  supplied buffer.                                                    *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Notes from original rdseed routine:                                 *
 | 
			
		||||
 *  SRO data are represented according to the formula                   *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  sample = M * (b exp {[m * (G + agr)] + ar})                         *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  where                                                               *
 | 
			
		||||
 *	sample = seismic data sample                                    *
 | 
			
		||||
 *	M      = mantissa                                               *
 | 
			
		||||
 *	G      = gain range factor                                      *
 | 
			
		||||
 *	b      = base to be exponentiated = 2 for SRO                   *
 | 
			
		||||
 *	m      = multiplier  = -1 for SRO                               *
 | 
			
		||||
 *	agr    = term to be added to gain range factor = 0 for SRO      *
 | 
			
		||||
 *	ar     = term to be added to [m * (gr + agr)]  = 10 for SRO     *
 | 
			
		||||
 *	exp    = exponentiation operation                               *
 | 
			
		||||
 *	Data are stored in two bytes as follows:                        *
 | 
			
		||||
 *		fedc ba98 7654 3210 = bit number, power of two          *
 | 
			
		||||
 *		GGGG MMMM MMMM MMMM = form of SEED data                 *
 | 
			
		||||
 *		where G = gain range factor and M = mantissa            *
 | 
			
		||||
 *	Masks to recover gain range and mantissa:                       *
 | 
			
		||||
 *		fedc ba98 7654 3210 = bit number = power of two         *
 | 
			
		||||
 *		0000 1111 1111 1111 = 0x0fff     = mask for mantissa    *
 | 
			
		||||
 *		1111 0000 0000 0000 = 0xf000     = mask for gain range  *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_sro
 | 
			
		||||
 (int16_t      *edata,		/* ptr to encoded data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int32_t nd = 0;	/* sample count */
 | 
			
		||||
  int32_t mantissa;	/* mantissa */
 | 
			
		||||
  int32_t gainrange;	/* gain range factor */
 | 
			
		||||
  int32_t add2gr;       /* added to gainrage factor */
 | 
			
		||||
  int32_t mult;         /* multiplier for gain range */
 | 
			
		||||
  int32_t add2result;   /* added to multiplied gain rage */
 | 
			
		||||
  int32_t exponent;	/* total exponent */
 | 
			
		||||
  uint16_t sint;
 | 
			
		||||
  int32_t sample;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  add2gr = 0;
 | 
			
		||||
  mult = -1;
 | 
			
		||||
  add2result = 10;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&sint, &edata[nd], sizeof(int16_t));
 | 
			
		||||
      if ( swapflag ) ms_gswap2a(&sint);
 | 
			
		||||
      
 | 
			
		||||
      /* Recover mantissa and gain range factor */
 | 
			
		||||
      mantissa = (sint & SRO_MANTISSA_MASK);
 | 
			
		||||
      gainrange = (sint & SRO_GAINRANGE_MASK) >> SRO_SHIFT;
 | 
			
		||||
      
 | 
			
		||||
      /* Take 2's complement for mantissa */
 | 
			
		||||
      if ( mantissa > MAX12 )
 | 
			
		||||
	mantissa -= 2 * (MAX12 + 1);
 | 
			
		||||
      
 | 
			
		||||
      /* Calculate exponent, SRO exponent = 0..10 */
 | 
			
		||||
      exponent = (mult * (gainrange + add2gr)) + add2result;
 | 
			
		||||
      
 | 
			
		||||
      if ( exponent < 0 || exponent > 10 )
 | 
			
		||||
	{
 | 
			
		||||
	  ms_log (2, "msr_unpack_sro(%s): SRO gain ranging exponent out of range: %d\n",
 | 
			
		||||
		  UNPACK_SRCNAME, exponent);
 | 
			
		||||
	  return MS_GENERROR;
 | 
			
		||||
	}
 | 
			
		||||
      
 | 
			
		||||
      /* Calculate sample as mantissa * 2^exponent */
 | 
			
		||||
      sample = mantissa * ( (uint64_t) 1 << exponent );
 | 
			
		||||
      
 | 
			
		||||
      /* Save sample in output array */
 | 
			
		||||
      databuff[nd] = sample;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_sro() */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/************************************************************************
 | 
			
		||||
 *  msr_unpack_dwwssn:                                                  *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Unpack DWWSSN encoded miniSEED data and place in supplied buffer.   *
 | 
			
		||||
 *                                                                      *
 | 
			
		||||
 *  Return: # of samples returned.                                      *
 | 
			
		||||
 ************************************************************************/
 | 
			
		||||
int msr_unpack_dwwssn
 | 
			
		||||
 (int16_t      *edata,		/* ptr to encoded data.			*/
 | 
			
		||||
  int		num_samples,	/* number of data samples in total.     */
 | 
			
		||||
  int		req_samples,	/* number of data desired by caller.	*/
 | 
			
		||||
  int32_t      *databuff,	/* ptr to unpacked data array.		*/
 | 
			
		||||
  int		swapflag)	/* if data should be swapped.	        */
 | 
			
		||||
{
 | 
			
		||||
  int32_t nd = 0;	/* sample count */
 | 
			
		||||
  int32_t sample;
 | 
			
		||||
  uint16_t sint;
 | 
			
		||||
  
 | 
			
		||||
  if (num_samples < 0) return 0;
 | 
			
		||||
  if (req_samples < 0) return 0;
 | 
			
		||||
  
 | 
			
		||||
  for (nd=0; nd<req_samples && nd<num_samples; nd++)
 | 
			
		||||
    {
 | 
			
		||||
      memcpy (&sint, &edata[nd], sizeof(uint16_t));
 | 
			
		||||
      if ( swapflag ) ms_gswap2a(&sint);
 | 
			
		||||
      sample = (int32_t) sint;
 | 
			
		||||
      
 | 
			
		||||
      /* Take 2's complement for sample */
 | 
			
		||||
      if ( sample > MAX16 )
 | 
			
		||||
	sample -= 2 * (MAX16 + 1);
 | 
			
		||||
      
 | 
			
		||||
      /* Save sample in output array */
 | 
			
		||||
      databuff[nd] = sample;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  return nd;
 | 
			
		||||
}  /* End of msr_unpack_dwwssn() */
 | 
			
		||||
							
								
								
									
										40
									
								
								libs/3rd-party/mseed/unpackdata.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								libs/3rd-party/mseed/unpackdata.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * unpack.h:
 | 
			
		||||
 * 
 | 
			
		||||
 * Interface declarations for the Mini-SEED unpacking routines in
 | 
			
		||||
 * unpackdata.c
 | 
			
		||||
 *
 | 
			
		||||
 * modified: 2009.111
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef	UNPACKDATA_H
 | 
			
		||||
#define	UNPACKDATA_H 1
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "steimdata.h"
 | 
			
		||||
 | 
			
		||||
/* Pointer to srcname of record being unpacked, declared in unpack.c */
 | 
			
		||||
extern char *UNPACK_SRCNAME;
 | 
			
		||||
  
 | 
			
		||||
extern int msr_unpack_int_16 (int16_t*, int, int, int32_t*, int);
 | 
			
		||||
extern int msr_unpack_int_32 (int32_t*, int, int, int32_t*, int);
 | 
			
		||||
extern int msr_unpack_float_32 (float*, int, int, float*, int);
 | 
			
		||||
extern int msr_unpack_float_64 (double*, int, int, double*, int);
 | 
			
		||||
extern int msr_unpack_steim1 (FRAME*, int, int, int, int32_t*, int32_t*,
 | 
			
		||||
			      int32_t*, int32_t*, int, int);
 | 
			
		||||
extern int msr_unpack_steim2 (FRAME*, int, int, int, int32_t*, int32_t*,
 | 
			
		||||
			      int32_t*, int32_t*, int, int);
 | 
			
		||||
extern int msr_unpack_geoscope (const char*, int, int, float*, int, int);
 | 
			
		||||
extern int msr_unpack_cdsn (int16_t*, int, int, int32_t*, int);
 | 
			
		||||
extern int msr_unpack_sro (int16_t*, int, int, int32_t*, int);
 | 
			
		||||
extern int msr_unpack_dwwssn (int16_t*, int, int, int32_t*, int);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										5
									
								
								libs/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								libs/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
SUBDIRS(3rd-party gempa)
 | 
			
		||||
 | 
			
		||||
IF(LIBCAPS_PYTHON_WRAPPER)
 | 
			
		||||
	SUBDIRS(swig)
 | 
			
		||||
ENDIF()
 | 
			
		||||
							
								
								
									
										1
									
								
								libs/gempa/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libs/gempa/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
subdirs(caps)
 | 
			
		||||
							
								
								
									
										150
									
								
								libs/gempa/caps/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								libs/gempa/caps/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
			
		||||
# Change Log
 | 
			
		||||
 | 
			
		||||
All notable changes to the CAPS client library will be documented in this file.
 | 
			
		||||
 | 
			
		||||
## 2021-04-21 1.0.0
 | 
			
		||||
### Changed
 | 
			
		||||
- Set library version to 1.0.0
 | 
			
		||||
 | 
			
		||||
## 2021-02-16
 | 
			
		||||
### Added
 | 
			
		||||
- Allow to set maximum allowed future end time via plugin API. In additon
 | 
			
		||||
  add commandline and config support to the plugin application class e.g.
 | 
			
		||||
  ```
 | 
			
		||||
  output.maxFutureEndTime = 120
 | 
			
		||||
  ```
 | 
			
		||||
  By default the option is set to 120 seconds.
 | 
			
		||||
 | 
			
		||||
## 2020-12-14
 | 
			
		||||
### Added
 | 
			
		||||
- Support to set miniSEED record length via API
 | 
			
		||||
 | 
			
		||||
## 2020-09-22
 | 
			
		||||
### Changed
 | 
			
		||||
- Use last sample time as reference time for maximum future time check. Before
 | 
			
		||||
  we used the packet end time as reference time but this makes no sense in case
 | 
			
		||||
  of low sampled data.
 | 
			
		||||
- So far we used the current time as start time if journal entries exceeded the
 | 
			
		||||
  maximum allowed future time. With this release we use the journal time no
 | 
			
		||||
  matter what its value but display a warning when the journal time is more than
 | 
			
		||||
  one day in the future.
 | 
			
		||||
 | 
			
		||||
## 2020-06-22
 | 
			
		||||
### Added
 | 
			
		||||
- Python3 byte array support to any record push
 | 
			
		||||
 | 
			
		||||
## 2020-02-21
 | 
			
		||||
### Changed
 | 
			
		||||
- Increase default timeout for acknowledgement messages from 5s to 60s
 | 
			
		||||
 | 
			
		||||
## 2019-09-24
 | 
			
		||||
### Fixed
 | 
			
		||||
- Fix high load if packets could not be sent to CAPS. In that case the plugin
 | 
			
		||||
  automatically reconnects after some amount of time. If triggered under certain
 | 
			
		||||
  circumstances this delay was not in effect and caused unnecessarily high
 | 
			
		||||
  amount of connection attempts. Under some circumstances the plugin could have
 | 
			
		||||
  crashed due to a stack overflow.
 | 
			
		||||
- The quit method has now the semantics to continue pushing packets as long
 | 
			
		||||
  as the connection is established and only abort in case of an error without
 | 
			
		||||
  attempting a reconnect.
 | 
			
		||||
 | 
			
		||||
## 2019-09-20
 | 
			
		||||
### Fixed
 | 
			
		||||
- Fix error string if not all data could be sent to the server
 | 
			
		||||
 | 
			
		||||
## 2019-08-19
 | 
			
		||||
### Changed
 | 
			
		||||
- Discard packets whose end time is more than 120 seconds before the system time.
 | 
			
		||||
 | 
			
		||||
## 2019-08-06
 | 
			
		||||
### Added
 | 
			
		||||
- new config option ``output.addr``
 | 
			
		||||
 | 
			
		||||
### Fixed
 | 
			
		||||
- ambiguous command line option ``-h``. With this version of the library the
 | 
			
		||||
host and port can be set via the command line option ``--addr``.
 | 
			
		||||
- wrong config option parsing
 | 
			
		||||
 | 
			
		||||
## 2019-08-05
 | 
			
		||||
### Fixed
 | 
			
		||||
- seg fault in date time parser
 | 
			
		||||
 | 
			
		||||
## 2019-08-02
 | 
			
		||||
### Fixed
 | 
			
		||||
- Hanging TCP connections. In case of the remote side does not shutdown cleanly
 | 
			
		||||
the plugin did not notice that the connection is no longer available. With this
 | 
			
		||||
version the plugin reconnects to the server when the TCP send buffer is full and
 | 
			
		||||
tries to send all not acknowledged packets again.
 | 
			
		||||
- Do not discard packets if the packet buffer is full. Instead we block until
 | 
			
		||||
the server acknowledges some packets.
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- The plugin application class checks whether the configured buffer size is
 | 
			
		||||
below the minimum.
 | 
			
		||||
 | 
			
		||||
## 2019-07-05
 | 
			
		||||
### Changed
 | 
			
		||||
- Ignore journal entries where the timestamp is more than 10 seconds
 | 
			
		||||
  before the system time.
 | 
			
		||||
 | 
			
		||||
## 2018-12-19
 | 
			
		||||
### Fixed
 | 
			
		||||
- Read journal from file in plugin application.
 | 
			
		||||
 | 
			
		||||
## 2018-12-18
 | 
			
		||||
### Fixed
 | 
			
		||||
- Do not reconnect if the plugin buffer is full. Instead of we try to read
 | 
			
		||||
acknowledgements from the CAPS server until the plugin buffer is below the
 | 
			
		||||
threshold.
 | 
			
		||||
 | 
			
		||||
## 2018-12-17
 | 
			
		||||
### Added
 | 
			
		||||
- Support to retrieve status information e.g. the number of buffered bytes from
 | 
			
		||||
  plugin.
 | 
			
		||||
 | 
			
		||||
## 2018-09-06
 | 
			
		||||
### Changed
 | 
			
		||||
- Enable more verbose logging for MSEED packets
 | 
			
		||||
 | 
			
		||||
## 2018-07-25
 | 
			
		||||
### Fixed
 | 
			
		||||
- unset variable of the raw data record
 | 
			
		||||
- trim function will return false in case of an unknown datatype
 | 
			
		||||
 | 
			
		||||
## 2018-05-30
 | 
			
		||||
### Fixed
 | 
			
		||||
- Fixed unexpected closed SSL connections
 | 
			
		||||
 | 
			
		||||
## 2018-06-05
 | 
			
		||||
### Fixed
 | 
			
		||||
- Fix RawDataRecord::setHeader
 | 
			
		||||
 | 
			
		||||
## 2018-05-16
 | 
			
		||||
### Fixed
 | 
			
		||||
- RAW data end time calculation
 | 
			
		||||
 | 
			
		||||
## 2018-03-19
 | 
			
		||||
### Added
 | 
			
		||||
- SSL support
 | 
			
		||||
 | 
			
		||||
## 2017-11-20
 | 
			
		||||
### Added
 | 
			
		||||
- float and double support for Steim encoders. All values will be converted implicitly
 | 
			
		||||
to int 32 values
 | 
			
		||||
 | 
			
		||||
## 2017-11-08
 | 
			
		||||
### Added
 | 
			
		||||
- timing quality parameter to push call. By default the timing quality is set to -1.
 | 
			
		||||
 | 
			
		||||
## 2017-11-07
 | 
			
		||||
### Fixed
 | 
			
		||||
- do not flush encoders after reconnect
 | 
			
		||||
 | 
			
		||||
## 2017-10-26
 | 
			
		||||
### Added
 | 
			
		||||
- SSL support
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 2017-10-24
 | 
			
		||||
### Fixed
 | 
			
		||||
- packet synchronization error after reconnect
 | 
			
		||||
							
								
								
									
										22
									
								
								libs/gempa/caps/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								libs/gempa/caps/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
SET(PACKAGE_NAME LIB_CAPS)
 | 
			
		||||
SET(LIB_NAME capsclient)
 | 
			
		||||
 | 
			
		||||
FILE(GLOB ${PACKAGE_NAME}_SOURCES
 | 
			
		||||
	"*.cpp"
 | 
			
		||||
	"mseed/*.cpp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
LIST(FILTER ${PACKAGE_NAME}_SOURCES EXCLUDE REGEX pluginapplication.cpp)
 | 
			
		||||
 | 
			
		||||
IF(WIN32)
 | 
			
		||||
	SET(${PACKAGE_NAME}_SOURCES ${${PACKAGE_NAME}_SOURCES} strptime.c)
 | 
			
		||||
ENDIF(WIN32)
 | 
			
		||||
 | 
			
		||||
INCLUDE_DIRECTORIES(../../3rd-party/mseed)
 | 
			
		||||
 | 
			
		||||
ADD_LIBRARY(${LIB_NAME} SHARED ${${PACKAGE_NAME}_SOURCES})
 | 
			
		||||
SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES COMPILE_FLAGS -fPIC)
 | 
			
		||||
SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES VERSION 1.0.0 SOVERSION 1)
 | 
			
		||||
TARGET_LINK_LIBRARIES(${LIB_NAME} mseed)
 | 
			
		||||
 | 
			
		||||
INSTALL(TARGETS ${LIB_NAME} DESTINATION lib)
 | 
			
		||||
							
								
								
									
										197
									
								
								libs/gempa/caps/anypacket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								libs/gempa/caps/anypacket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,197 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2012 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/anypacket.h>
 | 
			
		||||
#include <gempa/caps/riff.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::AnyHeader::put(std::streambuf &buf) const {
 | 
			
		||||
	Endianess::Writer put(buf);
 | 
			
		||||
	put(type, sizeof(type)-1);
 | 
			
		||||
	dataHeader.put(buf);
 | 
			
		||||
 | 
			
		||||
	put(endTime.year);
 | 
			
		||||
	put(endTime.yday);
 | 
			
		||||
	put(endTime.hour);
 | 
			
		||||
	put(endTime.minute);
 | 
			
		||||
	put(endTime.second);
 | 
			
		||||
	put(endTime.usec);
 | 
			
		||||
 | 
			
		||||
	return put.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AnyDataRecord::AnyDataRecord() {
 | 
			
		||||
	strncpy(_header.type, "ANY", sizeof(_header.type));
 | 
			
		||||
	_header.dataHeader.samplingFrequencyDenominator = 0;
 | 
			
		||||
	_header.dataHeader.samplingFrequencyNumerator = 0;
 | 
			
		||||
	// Just a bunch of bytes
 | 
			
		||||
	_header.dataHeader.dataType = DT_INT8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::setType(const char *type) {
 | 
			
		||||
	strncpy(_header.type, type, sizeof(_header.type));
 | 
			
		||||
 | 
			
		||||
	// Input clipped?
 | 
			
		||||
	if ( _header.type[sizeof(_header.type)-1] != '\0' ) {
 | 
			
		||||
		_header.type[sizeof(_header.type)-1] = '\0';
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *AnyDataRecord::type() const {
 | 
			
		||||
	return _header.type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnyDataRecord::setStartTime(const Time &time) {
 | 
			
		||||
	timeToTimestamp(_header.dataHeader.samplingTime, time);
 | 
			
		||||
	_startTime = time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void AnyDataRecord::setEndTime(const Time &time) {
 | 
			
		||||
	timeToTimestamp(_header.endTime, time);
 | 
			
		||||
	_endTime = time;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void AnyDataRecord::setSamplingFrequency(uint16_t numerator, uint16_t denominator) {
 | 
			
		||||
	_header.dataHeader.samplingFrequencyNumerator = numerator;
 | 
			
		||||
	_header.dataHeader.samplingFrequencyDenominator = denominator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *AnyDataRecord::formatName() const {
 | 
			
		||||
	return "ANY";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
                                 Header &header,
 | 
			
		||||
                                 Time &startTime, Time &endTime) {
 | 
			
		||||
	// Read record type
 | 
			
		||||
	buf.sgetn(_header.type, 4);
 | 
			
		||||
	_header.type[sizeof(_header.type)-1] = '\0';
 | 
			
		||||
 | 
			
		||||
	size -= sizeof(_header.type)-1;
 | 
			
		||||
 | 
			
		||||
	if ( !header.get(buf) ) return false;
 | 
			
		||||
 | 
			
		||||
	TimeStamp tmp;
 | 
			
		||||
	Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
	get(tmp.year);
 | 
			
		||||
	get(tmp.yday);
 | 
			
		||||
	get(tmp.hour);
 | 
			
		||||
	get(tmp.minute);
 | 
			
		||||
	get(tmp.second);
 | 
			
		||||
	get(tmp.usec);
 | 
			
		||||
 | 
			
		||||
	startTime = timestampToTime(header.samplingTime);
 | 
			
		||||
	endTime = timestampToTime(tmp);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const DataRecord::Header *AnyDataRecord::header() const {
 | 
			
		||||
	return &_header.dataHeader;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time AnyDataRecord::startTime() const {
 | 
			
		||||
	return _startTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time AnyDataRecord::endTime() const {
 | 
			
		||||
	return _endTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::canTrim() const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::canMerge() const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::trim(const Time &start,
 | 
			
		||||
                         const Time &end) const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
size_t AnyDataRecord::dataSize(bool withHeader) const {
 | 
			
		||||
	if ( withHeader )
 | 
			
		||||
		return _data.size() + _header.dataSize();
 | 
			
		||||
	else
 | 
			
		||||
		return _data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DataRecord::ReadStatus AnyDataRecord::get(std::streambuf &buf, int size,
 | 
			
		||||
                                          const Time &start, const Time &end,
 | 
			
		||||
                                          int) {
 | 
			
		||||
	_data.clear();
 | 
			
		||||
	size -= _header.dataSize();
 | 
			
		||||
	if ( size < 0 ) return RS_Error;
 | 
			
		||||
	if ( !_header.get(buf) ) return RS_Error;
 | 
			
		||||
 | 
			
		||||
	_startTime = timestampToTime(_header.dataHeader.samplingTime);
 | 
			
		||||
	_endTime = timestampToTime(_header.endTime);
 | 
			
		||||
 | 
			
		||||
	if ( start.valid() ) {
 | 
			
		||||
		if ( _endTime < start || (_startTime < start && _endTime == start) )
 | 
			
		||||
			return RS_BeforeTimeWindow;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( end.valid() ) {
 | 
			
		||||
		if ( _startTime >= end ) return RS_AfterTimeWindow;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RIFF::VectorChunk<1,false> dataChunk(_data, 0, size);
 | 
			
		||||
	if ( !dataChunk.get(buf, size) ) return RS_Error;
 | 
			
		||||
 | 
			
		||||
	return RS_Complete;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool AnyDataRecord::put(std::streambuf &buf, bool withHeader) const {
 | 
			
		||||
	if ( withHeader && !_header.put(buf) ) return false;
 | 
			
		||||
	return (int)buf.sputn(_data.data(), _data.size()) == (int)_data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnyDataRecord::setData(char *data, size_t size) {
 | 
			
		||||
	_data.resize(size);
 | 
			
		||||
	memcpy(_data.data(), data, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										154
									
								
								libs/gempa/caps/anypacket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								libs/gempa/caps/anypacket.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,154 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2012 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_CUSTOMPACKET_H
 | 
			
		||||
#define GEMPA_CAPS_CUSTOMPACKET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
#include <gempa/caps/endianess.h>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class AnyDataRecord : public DataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef std::vector<char> Buffer;
 | 
			
		||||
 | 
			
		||||
		struct AnyHeader {
 | 
			
		||||
			char      type[5];
 | 
			
		||||
			Header    dataHeader;
 | 
			
		||||
			TimeStamp endTime;
 | 
			
		||||
 | 
			
		||||
			bool get(std::streambuf &buf) {
 | 
			
		||||
				Endianess::Reader get(buf);
 | 
			
		||||
				get(type, sizeof(type)-1);
 | 
			
		||||
				type[sizeof(type)-1] = '\0';
 | 
			
		||||
				dataHeader.get(buf);
 | 
			
		||||
 | 
			
		||||
				get(endTime.year);
 | 
			
		||||
				get(endTime.yday);
 | 
			
		||||
				get(endTime.hour);
 | 
			
		||||
				get(endTime.minute);
 | 
			
		||||
				get(endTime.second);
 | 
			
		||||
				get(endTime.usec);
 | 
			
		||||
 | 
			
		||||
				return get.good;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool put(std::streambuf &buf) const;
 | 
			
		||||
 | 
			
		||||
			// 4 additional bytes (type) with respect to the original
 | 
			
		||||
			// data header
 | 
			
		||||
			int dataSize() const {
 | 
			
		||||
				return sizeof(type)-1 +
 | 
			
		||||
				       dataHeader.dataSize() +
 | 
			
		||||
				       sizeof(endTime.year) +
 | 
			
		||||
				       sizeof(endTime.yday) +
 | 
			
		||||
				       sizeof(endTime.hour) +
 | 
			
		||||
				       sizeof(endTime.minute) +
 | 
			
		||||
				       sizeof(endTime.second) +
 | 
			
		||||
				       sizeof(endTime.usec);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		AnyDataRecord();
 | 
			
		||||
 | 
			
		||||
		//! Sets the format of the any record. The format can be
 | 
			
		||||
		//! anything that fits into 4 characters. If more than
 | 
			
		||||
		//! 4 characters are given, false is returned.
 | 
			
		||||
		bool setType(const char *type);
 | 
			
		||||
		const char *type() const;
 | 
			
		||||
 | 
			
		||||
		virtual const char *formatName() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
		                          Header &header,
 | 
			
		||||
		                          Time &startTime,
 | 
			
		||||
		                          Time &endTime);
 | 
			
		||||
 | 
			
		||||
		virtual const Header *header() const;
 | 
			
		||||
		virtual Time startTime() const;
 | 
			
		||||
		virtual Time endTime() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool canTrim() const;
 | 
			
		||||
		virtual bool canMerge() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool trim(const Time &start,
 | 
			
		||||
		                  const Time &end) const;
 | 
			
		||||
 | 
			
		||||
		virtual size_t dataSize(bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		virtual ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		                       const Time &start = Time(),
 | 
			
		||||
		                       const Time &end = Time(),
 | 
			
		||||
		                       int maxSize = -1);
 | 
			
		||||
 | 
			
		||||
		virtual bool put(std::streambuf &buf, bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the packet type
 | 
			
		||||
		 * @return The packet type
 | 
			
		||||
		 */
 | 
			
		||||
		PacketType packetType() const { return ANYPacket; }
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the start time of the record
 | 
			
		||||
		 * @param The start time
 | 
			
		||||
		 */
 | 
			
		||||
		void setStartTime(const Time &time);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the end time of the record
 | 
			
		||||
		 * @param The end time
 | 
			
		||||
		 */
 | 
			
		||||
		void setEndTime(const Time &time);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the sampling frequency of the record
 | 
			
		||||
		 * @param numerator The numerator
 | 
			
		||||
		 * @param denominator The denomintor
 | 
			
		||||
		 */
 | 
			
		||||
		void setSamplingFrequency(uint16_t numerator, uint16_t denominator);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the data vector to be filled by the caller
 | 
			
		||||
		 * @return The pointer to the internal buffer
 | 
			
		||||
		 */
 | 
			
		||||
		Buffer *data() { return &_data; }
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Initializes the internal data vector from the given buffer
 | 
			
		||||
		 * @param The buffer to read the data from
 | 
			
		||||
		 * @param The buffer size
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void setData(char *data, size_t size);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		AnyHeader      _header;
 | 
			
		||||
		Buffer         _data;
 | 
			
		||||
 | 
			
		||||
		Time          _startTime;
 | 
			
		||||
		Time          _endTime;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										17
									
								
								libs/gempa/caps/api.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								libs/gempa/caps/api.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
#ifndef SC_GEMPA_CAPS_API_H
 | 
			
		||||
#define SC_GEMPA_CAPS_API_H
 | 
			
		||||
 | 
			
		||||
#if defined(WIN32) && (defined(SC_GEMPA_CAPS_SHARED) || defined(SC_ALL_SHARED))
 | 
			
		||||
# if defined(SC_GEMPA_CAPS_EXPORTS)
 | 
			
		||||
#  define SC_GEMPA_CAPS_API __declspec(dllexport)
 | 
			
		||||
#  define SC_GEMPA_CAPS_TEMPLATE_EXPORT
 | 
			
		||||
# else
 | 
			
		||||
#  define SC_GEMPA_CAPS_API __declspec(dllimport)
 | 
			
		||||
#  define SC_GEMPA_CAPS_TEMPLATE_EXPORT extern
 | 
			
		||||
# endif
 | 
			
		||||
#else
 | 
			
		||||
# define SC_GEMPA_CAPS_API
 | 
			
		||||
# define SC_GEMPA_CAPS_TEMPLATE_EXPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										141
									
								
								libs/gempa/caps/application.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								libs/gempa/caps/application.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,141 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2015 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/application.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
 | 
			
		||||
#include <csignal>
 | 
			
		||||
#include <locale.h>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
void signalHandler(int signal) {
 | 
			
		||||
	Gempa::CAPS::Application::Interrupt(signal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void registerSignalHandler() {
 | 
			
		||||
	CAPS_DEBUG("Registering signal handler");
 | 
			
		||||
 | 
			
		||||
	signal(SIGTERM, signalHandler);
 | 
			
		||||
	signal(SIGINT, signalHandler);
 | 
			
		||||
	signal(SIGHUP, SIG_IGN);
 | 
			
		||||
	signal(SIGPIPE, SIG_IGN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
Application* Application::_app = NULL;
 | 
			
		||||
 | 
			
		||||
Application::Application(int argc, char **argv) {
 | 
			
		||||
	_exitRequested = false;
 | 
			
		||||
	_argc = argc;
 | 
			
		||||
	_argv = argv;
 | 
			
		||||
 | 
			
		||||
	_app = this;
 | 
			
		||||
 | 
			
		||||
	registerSignalHandler();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Application::done() {
 | 
			
		||||
	_exitRequested = true;
 | 
			
		||||
	 CAPS_DEBUG("leaving ::done");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Application::exec() {
 | 
			
		||||
	_returnCode = 1;
 | 
			
		||||
	if ( init() ) {
 | 
			
		||||
		_returnCode = 0;
 | 
			
		||||
 | 
			
		||||
		if ( !run() && _returnCode == 0 )
 | 
			
		||||
			_returnCode = 1;
 | 
			
		||||
 | 
			
		||||
		done();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		done();
 | 
			
		||||
 | 
			
		||||
	return _returnCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Application::exit(int returnCode) {
 | 
			
		||||
	_returnCode = returnCode;
 | 
			
		||||
	_exitRequested = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Application::handleInterrupt(int signal) {
 | 
			
		||||
	switch ( signal ) {
 | 
			
		||||
		case SIGABRT:
 | 
			
		||||
			exit(-1);
 | 
			
		||||
 | 
			
		||||
		case SIGSEGV:
 | 
			
		||||
			exit(-1);
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			this->exit(_returnCode);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Application::Interrupt(int signal) {
 | 
			
		||||
	if ( _app ) _app->handleInterrupt(signal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Application::init() {
 | 
			
		||||
	setlocale(LC_ALL, "C");
 | 
			
		||||
 | 
			
		||||
	if ( !initCommandLine() ) {
 | 
			
		||||
		exit(1);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !initConfiguration() ) {
 | 
			
		||||
		exit(1);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !initCommandLine() ) {
 | 
			
		||||
		exit(1);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !validateParameters() ) {
 | 
			
		||||
		exit(1);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Application::initCommandLine() {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Application::initConfiguration() {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Application::run() {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Application::validateParameters() {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								libs/gempa/caps/application.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								libs/gempa/caps/application.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2015 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_APPLICATION_H
 | 
			
		||||
#define GEMPA_CAPS_APPLICATION_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/api.h>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API Application {
 | 
			
		||||
	public:
 | 
			
		||||
		Application(int argc, char **argv);
 | 
			
		||||
		virtual ~Application() {}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Exit the application and set the returnCode.
 | 
			
		||||
		 * @param returnCode The value returned from exec()
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void exit(int returnCode);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Conventient function to simplify usage
 | 
			
		||||
		 * @return The value returned from exec()
 | 
			
		||||
		 */
 | 
			
		||||
		int operator()() { return exec(); }
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief In case of an interrupt this method can be used to
 | 
			
		||||
		 *        forward the signal to the internal signal handling.
 | 
			
		||||
		 * @param signal
 | 
			
		||||
		 */
 | 
			
		||||
		static void Interrupt(int signal);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Cleanup method called before exec() returns.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void done();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Execs the mainloop and waits until exit() is called
 | 
			
		||||
		 * or a appropriate signal has been fired (e.g. SIGTERM).
 | 
			
		||||
		 * @return The value that was set with to exit()
 | 
			
		||||
		 */
 | 
			
		||||
		int exec();
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief This method can be used to implement custom
 | 
			
		||||
		 *        signal handling.
 | 
			
		||||
		 * @param signal The emitted signal
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void handleInterrupt(int signal);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Initialization method. This method calls the initCommandLine
 | 
			
		||||
		 *        initConfiguration and validateParameters function
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool init();
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Handles commandline arguments
 | 
			
		||||
		*/
 | 
			
		||||
		virtual bool initCommandLine();
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Handles configuration files
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool initConfiguration();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief This method must be implemented in the inherited class to
 | 
			
		||||
		 *        execute the plugin specific code.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool run();
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief This method can be used to verify custom configuration or
 | 
			
		||||
			      commandline parameters
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool validateParameters();
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		bool                _exitRequested;
 | 
			
		||||
		int                 _argc;
 | 
			
		||||
		char              **_argv;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		int                 _returnCode;
 | 
			
		||||
		static Application *_app;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										621
									
								
								libs/gempa/caps/connection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										621
									
								
								libs/gempa/caps/connection.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,621 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2014 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/connection.h>
 | 
			
		||||
#include <gempa/caps/anypacket.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
#include <gempa/caps/metapacket.h>
 | 
			
		||||
#include <gempa/caps/rawpacket.h>
 | 
			
		||||
#include <gempa/caps/sessiontable.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <cerrno>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
const Time InvalidTime = Time();
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool fromString(T &value, const string &str);
 | 
			
		||||
 | 
			
		||||
template<> inline bool fromString(int &value, const string &str) {
 | 
			
		||||
	stringstream ss(str);
 | 
			
		||||
	ss >> value;
 | 
			
		||||
	return !ss.bad();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Connection::Connection() {
 | 
			
		||||
	_port = 18002;
 | 
			
		||||
	_server = "localhost";
 | 
			
		||||
 | 
			
		||||
	_metaMode = false;
 | 
			
		||||
	_realtime = true;
 | 
			
		||||
	_ssl = false;
 | 
			
		||||
 | 
			
		||||
	_sessionTable = SessionTablePtr(new SessionTable());
 | 
			
		||||
	_sessionTable->setItemAboutToBeRemovedFunc(
 | 
			
		||||
		bind(&Connection::onItemAboutToBeRemoved, this, placeholders::_1)
 | 
			
		||||
	);
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Connection::~Connection() {
 | 
			
		||||
	close();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::setServer(const string &server) {
 | 
			
		||||
	close();
 | 
			
		||||
	reset();
 | 
			
		||||
 | 
			
		||||
	size_t pos = server.rfind(':');
 | 
			
		||||
	string addr = server;
 | 
			
		||||
	int timeout = 300;
 | 
			
		||||
 | 
			
		||||
	if ( pos == string::npos )
 | 
			
		||||
		_server = addr;
 | 
			
		||||
	else {
 | 
			
		||||
		_server = addr.substr(0, pos);
 | 
			
		||||
		if ( !fromString(_port, addr.substr(pos+1)) ) {
 | 
			
		||||
			CAPS_ERROR("invalid source address: %s", addr.c_str());
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( timeout > 0 ) {
 | 
			
		||||
		CAPS_DEBUG("setting socket timeout to %ds", timeout);
 | 
			
		||||
		//_socket->setSocketTimeout(timeout,0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::setCredentials(const std::string &user,
 | 
			
		||||
                                const std::string &password) {
 | 
			
		||||
	if ( user.empty() || password.empty() ) {
 | 
			
		||||
		_auth.clear();
 | 
			
		||||
		CAPS_DEBUG("authentication deactivated");
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		_auth = "AUTH " + user + " " + password;
 | 
			
		||||
		CAPS_DEBUG("credentials set: %s:***", user.c_str());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Socket* Connection::createSocket() const {
 | 
			
		||||
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
 | 
			
		||||
	return _ssl? new SSLSocket() : new Socket();
 | 
			
		||||
#else
 | 
			
		||||
	return new Socket();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::disconnect() {
 | 
			
		||||
	if ( _socket == NULL ) return;
 | 
			
		||||
 | 
			
		||||
	CAPS_DEBUG("disconnecting");
 | 
			
		||||
	if ( _state != Aborted )
 | 
			
		||||
		_state = Error;
 | 
			
		||||
 | 
			
		||||
	_socket->shutdown();
 | 
			
		||||
	_socket->close();
 | 
			
		||||
	_sessionTable->reset();
 | 
			
		||||
	_currentID = - 1;
 | 
			
		||||
	_currentItem = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::close() {
 | 
			
		||||
	boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
//	_state = Aborted;
 | 
			
		||||
	disconnect();
 | 
			
		||||
	_state = Aborted;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::abort() {
 | 
			
		||||
	boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
	if ( _state == Aborted ) {
 | 
			
		||||
		CAPS_WARNING("abort already requested");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( _socket->isValid() && _state == Active ) {
 | 
			
		||||
		static string line("ABORT\n");
 | 
			
		||||
		if ( _socket->write(line.c_str(), line.size()) != (int) line.size() ) {
 | 
			
		||||
			CAPS_ERROR("could not send abort request");
 | 
			
		||||
			disconnect();
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			CAPS_DEBUG("abort command sent");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	_state = Aborted;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::setTimeout(int /*seconds*/) {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::addStream(const string &net, const string &sta,
 | 
			
		||||
                           const string &loc, const string &cha) {
 | 
			
		||||
	return addRequest(net, sta, loc, cha, _startTime, _endTime, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::addStream(const string &net, const string &sta,
 | 
			
		||||
                           const string &loc, const string &cha,
 | 
			
		||||
                           const Time &stime,
 | 
			
		||||
                           const Time &etime) {
 | 
			
		||||
	return addRequest(net, sta, loc, cha, stime, etime, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::addRequest(const string &net, const string &sta,
 | 
			
		||||
                            const string &loc, const string &cha,
 | 
			
		||||
                            const Time &stime,
 | 
			
		||||
                            const Time &etime,
 | 
			
		||||
                            bool receivedData) {
 | 
			
		||||
	boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
	if ( _state != EOD ) {
 | 
			
		||||
		if ( _state == Active )
 | 
			
		||||
			CAPS_WARNING("cannot add streams to an active session, invoke "
 | 
			
		||||
			             "abort() or close() first");
 | 
			
		||||
		else
 | 
			
		||||
			CAPS_WARNING("cannot add streams to an erroneous or aborted "
 | 
			
		||||
			             "session, invoke reset() first");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	string streamID = net + "." + sta + "." + loc + "." + cha;
 | 
			
		||||
	Request &req = _requests[streamID];
 | 
			
		||||
	req.net = net;
 | 
			
		||||
	req.sta = sta;
 | 
			
		||||
	req.loc = loc;
 | 
			
		||||
	req.cha = cha;
 | 
			
		||||
	req.start = stime;
 | 
			
		||||
	req.end = etime;
 | 
			
		||||
	req.receivedData = receivedData;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataRecord* Connection::next() {
 | 
			
		||||
	if ( !handshake() ) return NULL;
 | 
			
		||||
 | 
			
		||||
	while ( true ) {
 | 
			
		||||
		{
 | 
			
		||||
			boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
			// skip unread bytes of previous iteration and check connection state
 | 
			
		||||
			if ( !seekToReadLimit() || _state == Error || _state == EOD )
 | 
			
		||||
				return NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ResponseHeader responseHeader;
 | 
			
		||||
		if ( !responseHeader.get(_socketBuf) ) {
 | 
			
		||||
			boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
			if ( _state != Aborted)
 | 
			
		||||
				CAPS_ERROR("could not read header");
 | 
			
		||||
			disconnect();
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CAPS_DEBUG("read header (id/size): %i/%lu", responseHeader.id,
 | 
			
		||||
		           (unsigned long)responseHeader.size);
 | 
			
		||||
		_socketBuf.set_read_limit(responseHeader.size);
 | 
			
		||||
 | 
			
		||||
//		if ( _abortRequested ) break;
 | 
			
		||||
 | 
			
		||||
		// State or session table update
 | 
			
		||||
		if ( responseHeader.id == 0 ) {
 | 
			
		||||
			while ( responseHeader.size > 0 /*&& _state == Active*/) {
 | 
			
		||||
				istream is(&_socketBuf);
 | 
			
		||||
				if ( is.getline(_lineBuf, 200).fail() ) {
 | 
			
		||||
					boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
					CAPS_ERROR("header line exceeds maximum of 200 characters");
 | 
			
		||||
					disconnect();
 | 
			
		||||
					return NULL;
 | 
			
		||||
				}
 | 
			
		||||
				responseHeader.size -= is.gcount();
 | 
			
		||||
 | 
			
		||||
				SessionTable::Status status =
 | 
			
		||||
				        _sessionTable->handleResponse(_lineBuf, is.gcount());
 | 
			
		||||
				if ( status == SessionTable::Error ) {
 | 
			
		||||
					boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
					disconnect();
 | 
			
		||||
					return NULL;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if ( status == SessionTable::EOD ) {
 | 
			
		||||
					_state = EOD;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CAPS_DEBUG("reading data record");
 | 
			
		||||
		// data
 | 
			
		||||
		if ( _currentID != responseHeader.id ) {
 | 
			
		||||
			_currentItem = _sessionTable->getItem(responseHeader.id);
 | 
			
		||||
			_currentID = responseHeader.id;
 | 
			
		||||
 | 
			
		||||
			if ( _currentItem == NULL ) {
 | 
			
		||||
				CAPS_WARNING("unknown data request ID %d", responseHeader.id);
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int size = responseHeader.size;
 | 
			
		||||
 | 
			
		||||
		// To improve performance CAPS uses an optimized protocol
 | 
			
		||||
		// to deliver RAW packets. The RAW packet class can't be used
 | 
			
		||||
		// to read the header from socket.
 | 
			
		||||
		DataRecord *dataRecord = NULL;
 | 
			
		||||
		if ( _currentItem->type == RawDataPacket ) {
 | 
			
		||||
			// Read optimized header
 | 
			
		||||
			RawResponseHeader rawResponseHeader;
 | 
			
		||||
			if ( !rawResponseHeader.get(_socketBuf) ) {
 | 
			
		||||
				boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
				CAPS_ERROR("failed to extract raw response header %s",
 | 
			
		||||
				           _currentItem->streamID.c_str());
 | 
			
		||||
				disconnect();
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Time time(rawResponseHeader.timeSeconds, rawResponseHeader.timeMicroSeconds);
 | 
			
		||||
			size -= rawResponseHeader.dataSize();
 | 
			
		||||
 | 
			
		||||
			// Create raw record, set header and read payload
 | 
			
		||||
			RawDataRecord *record = new RawDataRecord;
 | 
			
		||||
			record->setStartTime(time);
 | 
			
		||||
			record->setSamplingFrequency(_currentItem->samplingFrequency,
 | 
			
		||||
			                             _currentItem->samplingFrequencyDivider);
 | 
			
		||||
			record->setDataType(_currentItem->dataType);
 | 
			
		||||
			record->getData(_socketBuf, size);
 | 
			
		||||
 | 
			
		||||
			dataRecord =  record;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( _currentItem->type == ANYPacket ) {
 | 
			
		||||
			AnyDataRecord *record = new AnyDataRecord;
 | 
			
		||||
			record->get(_socketBuf, size, InvalidTime, InvalidTime, size);
 | 
			
		||||
			dataRecord = record;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( _currentItem->type == MSEEDPacket ) {
 | 
			
		||||
			MSEEDDataRecord *record = new MSEEDDataRecord;
 | 
			
		||||
			record->get(_socketBuf, size, InvalidTime, InvalidTime, size);
 | 
			
		||||
			dataRecord = record;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( _currentItem->type == MetaDataPacket ) {
 | 
			
		||||
			// Read start time from optimized header
 | 
			
		||||
			MetaResponseHeader metaResponseHeader;
 | 
			
		||||
			if ( !metaResponseHeader.get(_socketBuf) ) {
 | 
			
		||||
				boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
				CAPS_ERROR("failed to extract meta information from stream %s",
 | 
			
		||||
				           _currentItem->streamID.c_str());
 | 
			
		||||
				disconnect();
 | 
			
		||||
				return NULL;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Time stime(metaResponseHeader.startTime.seconds,
 | 
			
		||||
			           metaResponseHeader.endTime.microSeconds),
 | 
			
		||||
			     etime(metaResponseHeader.endTime.seconds,
 | 
			
		||||
			           metaResponseHeader.endTime.microSeconds);
 | 
			
		||||
 | 
			
		||||
			size -= metaResponseHeader.dataSize();
 | 
			
		||||
 | 
			
		||||
			MetaDataRecord::MetaHeader recHeader;
 | 
			
		||||
			recHeader.dataHeader.setSamplingTime(stime);
 | 
			
		||||
			recHeader.setEndTime(etime);
 | 
			
		||||
			recHeader.dataHeader.samplingFrequencyNumerator = _currentItem->samplingFrequency;
 | 
			
		||||
			recHeader.dataHeader.samplingFrequencyDenominator = _currentItem->samplingFrequencyDivider;
 | 
			
		||||
			recHeader.dataHeader.dataType = _currentItem->dataType;
 | 
			
		||||
 | 
			
		||||
			MetaDataRecord *record = new MetaDataRecord;
 | 
			
		||||
			record->setHeader(recHeader);
 | 
			
		||||
			dataRecord = record;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			CAPS_ERROR("received unknown packet type %d in stream %s",
 | 
			
		||||
			           _currentItem->type, _currentItem->streamID.c_str());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ( dataRecord == NULL ) {
 | 
			
		||||
			boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
			disconnect();
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CAPS_DEBUG("data record read");
 | 
			
		||||
 | 
			
		||||
		RequestList::iterator it = _requests.find(_currentItem->streamID);
 | 
			
		||||
		if ( it == _requests.end() ) {
 | 
			
		||||
			// TODO: Search request map for wildcard match. Add entry with
 | 
			
		||||
			// streamID -> (record->endTime, wildcardItem->endTime) to
 | 
			
		||||
			// restrict data query in case of reconnect
 | 
			
		||||
 | 
			
		||||
//			CAPS_WARNING("received unrequested record: %s: %s - %s",
 | 
			
		||||
//			             _currentItem->streamID.c_str(),
 | 
			
		||||
//			             dataRecord->startTime().iso().c_str(),
 | 
			
		||||
//			             dataRecord->endTime().iso().c_str());
 | 
			
		||||
		}
 | 
			
		||||
		// Update request map to reflect current stream state
 | 
			
		||||
		else if ( dataRecord->endTime() > it->second.start ) {
 | 
			
		||||
			it->second.start = dataRecord->endTime();
 | 
			
		||||
			it->second.receivedData = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return dataRecord;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::handshake() {
 | 
			
		||||
	{
 | 
			
		||||
		boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
		if ( _state == Error || _state == Aborted) {
 | 
			
		||||
			CAPS_ERROR("cannot read from an erroneous or aborted session, invoke "
 | 
			
		||||
			           "reset() first");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		else if ( _state == Active )
 | 
			
		||||
			return true;
 | 
			
		||||
		// _state is set to EOD
 | 
			
		||||
		else if ( _requests.empty() ) {
 | 
			
		||||
			CAPS_WARNING("no stream requested, invoke addStream() first");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( _socket == NULL ) {
 | 
			
		||||
		_socket = SocketPtr(createSocket());
 | 
			
		||||
		if ( _socket == NULL ) return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Connect to server if necessary
 | 
			
		||||
	while ( !_socket->isValid() && _state == EOD ) {
 | 
			
		||||
		if ( _socket->connect(_server, _port) == Socket::Success ) {
 | 
			
		||||
			_socketBuf.setsocket(_socket.get());
 | 
			
		||||
			CAPS_DEBUG("connection to %s:%d established", _server.c_str(), _port);
 | 
			
		||||
//			_state = ios_base::eofbit;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CAPS_WARNING("unable to connect to %s:%d, retrying in 5 seconds",
 | 
			
		||||
				     _server.c_str(), _port);
 | 
			
		||||
 | 
			
		||||
		// Wait 5 seconds and keep response latency low
 | 
			
		||||
		for ( int i = 0; (i < 10) && _state == EOD; ++i )
 | 
			
		||||
			usleep(500000);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if ( _state != EOD ) return false;
 | 
			
		||||
 | 
			
		||||
//	if ( _socket->isValid() ) {
 | 
			
		||||
//		// Read all data from session
 | 
			
		||||
//		if ( !seekToReadLimit() ) return false;
 | 
			
		||||
////		fd_set set;
 | 
			
		||||
////		FD_ZERO(&set);
 | 
			
		||||
////		FD_SET(_socket->fd(), &set);
 | 
			
		||||
////		timeval t = (struct timeval) {0};
 | 
			
		||||
 | 
			
		||||
////		/* select returns 0 on timeout, 1 if input/output is available, -1 on error. */
 | 
			
		||||
////		int retn = TEMP_FAILURE_RETRY(select(_socket->fd()+1, &set, NULL, NULL, &t));
 | 
			
		||||
////		if ( retn != 0 )  CAPS_ERROR("UUPS");
 | 
			
		||||
//	}
 | 
			
		||||
 | 
			
		||||
//	if ( _state == Aborted ) return false;
 | 
			
		||||
 | 
			
		||||
	// Request streams
 | 
			
		||||
	stringstream req;
 | 
			
		||||
 | 
			
		||||
	if ( !_auth.empty() )
 | 
			
		||||
		req << _auth << endl;
 | 
			
		||||
 | 
			
		||||
	req << "BEGIN REQUEST" << endl
 | 
			
		||||
	    << "META " << (_metaMode ? "ON" : "OFF") << endl
 | 
			
		||||
		<< "REALTIME " << ( _realtime ? "ON" : "OFF") << endl;
 | 
			
		||||
 | 
			
		||||
	// First pass: continue all previous streams
 | 
			
		||||
	for ( RequestList::const_iterator it = _requests.begin();
 | 
			
		||||
	      it != _requests.end() && _state == EOD; ++it ) {
 | 
			
		||||
		if ( it->second.receivedData )
 | 
			
		||||
			formatRequest(req, it);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Second pass: subscribe to remaining streams
 | 
			
		||||
	for ( RequestList::iterator it = _requests.begin();
 | 
			
		||||
	      it != _requests.end() && _state == EOD; ++it ) {
 | 
			
		||||
		if ( !it->second.receivedData )
 | 
			
		||||
			formatRequest(req, it);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req << "END" << endl;
 | 
			
		||||
 | 
			
		||||
	return sendRequest(req.str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::sendRequest(const string &req) {
 | 
			
		||||
	boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
 | 
			
		||||
	if ( _state != EOD ) return false;
 | 
			
		||||
 | 
			
		||||
	CAPS_DEBUG("%s", req.c_str());
 | 
			
		||||
	if ( _socket->write(req.c_str(), req.size()) != (int) req.size() ) {
 | 
			
		||||
		CAPS_ERROR("could not send data request");
 | 
			
		||||
		disconnect();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Gempa::CAPS::ResponseHeader header;
 | 
			
		||||
	if ( !header.get(_socketBuf) ) {
 | 
			
		||||
		// Case to retry, connection closed by peer
 | 
			
		||||
		CAPS_ERROR("could not read data request response header");
 | 
			
		||||
		disconnect();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_socketBuf.set_read_limit(header.size);
 | 
			
		||||
	if ( header.id != 0 ) {
 | 
			
		||||
		CAPS_ERROR("invalid data request response header id, expected 0, got %d", header.id);
 | 
			
		||||
		disconnect();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	CAPS_DEBUG("data request response size: %lu", (unsigned long) header.size);
 | 
			
		||||
 | 
			
		||||
	istream is(&_socketBuf);
 | 
			
		||||
	// check line length
 | 
			
		||||
	if ( is.getline(_lineBuf, 200).fail() )
 | 
			
		||||
		CAPS_ERROR("data request response line exceeds maximum of 200 characters");
 | 
			
		||||
	// skip remaining header data
 | 
			
		||||
	else if ( !seekToReadLimit(false) ) {
 | 
			
		||||
		CAPS_ERROR("could not seek to data request response header end");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( strncasecmp(_lineBuf, "ERROR:", 6) == 0 )
 | 
			
		||||
		CAPS_ERROR("server responded to data request with: %s", _lineBuf);
 | 
			
		||||
	else if ( strncasecmp(_lineBuf, "STATUS OK", 9) != 0 )
 | 
			
		||||
		CAPS_ERROR("invalid data request response: %s", _lineBuf);
 | 
			
		||||
	else {
 | 
			
		||||
		CAPS_DEBUG("handshake complete");
 | 
			
		||||
		_state = Active;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disconnect();
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool Connection::seekToReadLimit(bool log) {
 | 
			
		||||
	if ( !_socket->isValid() ) {
 | 
			
		||||
		disconnect();
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Skip unread bytes from previous record
 | 
			
		||||
	int skippies = _socketBuf.read_limit();
 | 
			
		||||
	if ( skippies > 0 ) {
 | 
			
		||||
		if ( log )
 | 
			
		||||
			CAPS_WARNING("no seemless reading, skipping %d bytes", skippies);
 | 
			
		||||
		if ( _socketBuf.pubseekoff(skippies, ios_base::cur, ios_base::in) < 0 ) {
 | 
			
		||||
			CAPS_ERROR("could not seek to next header");
 | 
			
		||||
			disconnect();
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	_socketBuf.set_read_limit(-1);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::formatRequest(stringstream& req, RequestList::const_iterator it) {
 | 
			
		||||
	req << "STREAM ADD " << it->first << endl;
 | 
			
		||||
	req << "TIME ";
 | 
			
		||||
 | 
			
		||||
	int year, mon, day, hour, minute, second;
 | 
			
		||||
 | 
			
		||||
	if ( it->second.start.valid() ) {
 | 
			
		||||
		it->second.start.get(&year, &mon, &day, &hour, &minute, &second);
 | 
			
		||||
		req << year << "," << mon << "," << day << ","
 | 
			
		||||
		    << hour << "," << minute << "," << second;
 | 
			
		||||
		if ( it->second.start.microseconds() > 0 ) {
 | 
			
		||||
			req << "," << setfill('0') << setw(6)
 | 
			
		||||
			    << it->second.start.microseconds() << setw(0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req << ":";
 | 
			
		||||
 | 
			
		||||
	if ( it->second.end.valid() ) {
 | 
			
		||||
		it->second.end.get(&year, &mon, &day, &hour, &minute, &second);
 | 
			
		||||
		req << year << "," << mon << "," << day << ","
 | 
			
		||||
		    << hour << "," << minute << "," << second;
 | 
			
		||||
		if ( it->second.end.microseconds() > 0 ) {
 | 
			
		||||
			req << "," << setfill('0') << setw(6)
 | 
			
		||||
			    << it->second.end.microseconds() << setw(0);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req << endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::onItemAboutToBeRemoved(const SessionTableItem *item) {
 | 
			
		||||
	if ( _currentItem == item) {
 | 
			
		||||
		_currentID = -1;
 | 
			
		||||
		_currentItem = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// remove request since all data has been received
 | 
			
		||||
	if ( item != NULL ) _requests.erase(item->streamID);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::reset(bool clearStreams) {
 | 
			
		||||
	boost::mutex::scoped_lock l(_mutex);
 | 
			
		||||
	CAPS_DEBUG("resetting connection");
 | 
			
		||||
	if ( _state == Active ) {
 | 
			
		||||
		CAPS_WARNING("cannot reset an active connection, invoking close()");
 | 
			
		||||
		close();
 | 
			
		||||
	}
 | 
			
		||||
//	else if ( _state == Aborted ) {
 | 
			
		||||
//		fd_set set;
 | 
			
		||||
//		FD_ZERO(&set);
 | 
			
		||||
//		FD_SET(_socket->fd(), &set);
 | 
			
		||||
//		timeval t = (struct timeval) {0};
 | 
			
		||||
 | 
			
		||||
//		/* select returns 0 on timeout, 1 if input/output is available, -1 on error. */
 | 
			
		||||
//		while ( _socket->isValid() ) {
 | 
			
		||||
//			int retn = TEMP_FAILURE_RETRY(select(_socket->fd()+1, &set, NULL, NULL, &t));
 | 
			
		||||
//			if ( retn == 0 ) break;
 | 
			
		||||
 | 
			
		||||
//				if ( retn != 0 )  CAPS_ERROR("UUPS");
 | 
			
		||||
 | 
			
		||||
//	}
 | 
			
		||||
 | 
			
		||||
	_state = EOD;
 | 
			
		||||
	if ( clearStreams )
 | 
			
		||||
		_requests.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::setStartTime(const Time &stime) {
 | 
			
		||||
	_startTime = stime;
 | 
			
		||||
	CAPS_DEBUG("set global start time to %s", _startTime.toString("%F %T.%f").c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::setEndTime(const Time &etime) {
 | 
			
		||||
	_endTime = etime;
 | 
			
		||||
	CAPS_DEBUG("set global end time to %s", _endTime.toString("%F %T.%f").c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::setTimeWindow(const Time &stime, const Time &etime) {
 | 
			
		||||
	_startTime = stime;
 | 
			
		||||
	_endTime = etime;
 | 
			
		||||
	CAPS_DEBUG("set global timewindow to %s~%s", _startTime.toString("%F %T.%f").c_str(),
 | 
			
		||||
	           _endTime.toString("%F %T.%f").c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										180
									
								
								libs/gempa/caps/connection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								libs/gempa/caps/connection.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,180 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2014 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_CONNECTION_H
 | 
			
		||||
#define GEMPA_CAPS_CONNECTION_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
#include <gempa/caps/sessiontable.h>
 | 
			
		||||
#include <gempa/caps/socket.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/shared_ptr.hpp>
 | 
			
		||||
#include <boost/thread/condition.hpp>
 | 
			
		||||
#include <boost/thread/mutex.hpp>
 | 
			
		||||
 | 
			
		||||
//#include <iostream>
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class SessionTableItem;
 | 
			
		||||
class Time;
 | 
			
		||||
 | 
			
		||||
class Connection {
 | 
			
		||||
	public:
 | 
			
		||||
		//! ConnectionStates:
 | 
			
		||||
		//! EOD     -> connection not yet established or all streams finished (or aborted)
 | 
			
		||||
		//! Active  -> connection was successfully established, data request was sent
 | 
			
		||||
		//! Error   -> connection aborted due to server error
 | 
			
		||||
		//! Aborted -> connection aborted by user
 | 
			
		||||
		enum State { EOD, Active, Error, Aborted };
 | 
			
		||||
 | 
			
		||||
		//! Constructor
 | 
			
		||||
		Connection();
 | 
			
		||||
 | 
			
		||||
		//! Destructor
 | 
			
		||||
		virtual ~Connection();
 | 
			
		||||
 | 
			
		||||
		//! Sets server parameter
 | 
			
		||||
		bool setServer(const std::string &server);
 | 
			
		||||
 | 
			
		||||
		//! Enables SSL feature
 | 
			
		||||
		void enableSSL(bool enable) { _ssl = enable; }
 | 
			
		||||
 | 
			
		||||
		//! Sets user name and password
 | 
			
		||||
		void setCredentials(const std::string &user, const std::string &password);
 | 
			
		||||
 | 
			
		||||
		//! Sets meta mode. If enabled only the packet header information is
 | 
			
		||||
		//! transmitted.
 | 
			
		||||
		void setMetaMode(bool enable) { _metaMode = enable; }
 | 
			
		||||
 | 
			
		||||
		//! Sets realtime mode.
 | 
			
		||||
		void setRealtime(bool enable) { _realtime = enable; }
 | 
			
		||||
 | 
			
		||||
		//! Disconnect from server, connection unuseable until reset() is
 | 
			
		||||
		//! called. Thread safe.
 | 
			
		||||
		void close();
 | 
			
		||||
 | 
			
		||||
		//! Send abort command to server, keep socket open, requires reset.
 | 
			
		||||
		//! Thread safe.
 | 
			
		||||
		void abort();
 | 
			
		||||
 | 
			
		||||
		//! Adds a stream request
 | 
			
		||||
		bool addStream(const std::string &net, const std::string &sta,
 | 
			
		||||
		               const std::string &loc, const std::string &cha);
 | 
			
		||||
 | 
			
		||||
		//! Adds a seismic stream requests
 | 
			
		||||
		bool addStream(const std::string &net, const std::string &sta,
 | 
			
		||||
		               const std::string &loc, const std::string &cha,
 | 
			
		||||
		               const Time &stime,
 | 
			
		||||
		               const Time &etime);
 | 
			
		||||
 | 
			
		||||
		//! Resets connection state to eof
 | 
			
		||||
		void reset(bool clearStreams = false);
 | 
			
		||||
 | 
			
		||||
		//! Sets the given start time
 | 
			
		||||
		void setStartTime(const Time &stime);
 | 
			
		||||
 | 
			
		||||
		//! Sets the given end time
 | 
			
		||||
		void setEndTime(const Time &etime);
 | 
			
		||||
 | 
			
		||||
		//! Sets the given time window
 | 
			
		||||
		void setTimeWindow(const Time &stime, const Time &etime);
 | 
			
		||||
 | 
			
		||||
		//! Sets timeout
 | 
			
		||||
		bool setTimeout(int seconds);
 | 
			
		||||
 | 
			
		||||
		//! Returns the next record. If the record is NULL the caller has
 | 
			
		||||
		//! to check the state of the connection. Automatically creates a new
 | 
			
		||||
		//! connection if required, sends data requests and evaluates updates
 | 
			
		||||
		//! of session table. If the connection state is neither 'good' nor
 | 
			
		||||
		//!'eof' the connection has to be resetted before invoking this method.
 | 
			
		||||
		DataRecord* next();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		State state() { return _state; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	// protected methods
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	protected:
 | 
			
		||||
		virtual Socket* createSocket() const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		typedef boost::shared_ptr<SessionTable> SessionTablePtr;
 | 
			
		||||
 | 
			
		||||
		struct Request {
 | 
			
		||||
			std::string      net;
 | 
			
		||||
			std::string      sta;
 | 
			
		||||
			std::string      loc;
 | 
			
		||||
			std::string      cha;
 | 
			
		||||
			Time             start;
 | 
			
		||||
			Time             end;
 | 
			
		||||
			bool             receivedData;
 | 
			
		||||
		};
 | 
			
		||||
		typedef std::map<std::string, Request> RequestList;
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	// private methods
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	private:
 | 
			
		||||
		bool addRequest(const std::string &net, const std::string &sta,
 | 
			
		||||
		                const std::string &loc, const std::string &cha,
 | 
			
		||||
		                const Time &stime,
 | 
			
		||||
		                const Time &etime,
 | 
			
		||||
		                bool receivedData);
 | 
			
		||||
		void onItemAboutToBeRemoved(const SessionTableItem *item);
 | 
			
		||||
 | 
			
		||||
		void disconnect();
 | 
			
		||||
		bool handshake();
 | 
			
		||||
		bool sendRequest(const std::string &req);
 | 
			
		||||
 | 
			
		||||
		bool seekToReadLimit(bool log = true);
 | 
			
		||||
		void formatRequest(std::stringstream& req, RequestList::const_iterator it);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	// private data members
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	protected:
 | 
			
		||||
		SessionTablePtr                     _sessionTable;
 | 
			
		||||
		RequestList                         _requests;
 | 
			
		||||
		SocketPtr                           _socket;
 | 
			
		||||
		socketbuf<Socket, 512>              _socketBuf;
 | 
			
		||||
		char                                _lineBuf[201];
 | 
			
		||||
		volatile State                      _state;
 | 
			
		||||
		SessionTableItem                   *_currentItem;
 | 
			
		||||
		uint16_t                            _currentID;
 | 
			
		||||
		boost::mutex                        _mutex;
 | 
			
		||||
 | 
			
		||||
		std::string                         _server;
 | 
			
		||||
		int                                 _port;
 | 
			
		||||
		std::string                         _auth;
 | 
			
		||||
		Time                                _startTime;
 | 
			
		||||
		Time                                _endTime;
 | 
			
		||||
		bool                                _realtime;
 | 
			
		||||
		bool                                _metaMode;
 | 
			
		||||
		bool                                _ssl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef boost::shared_ptr<Connection> ConnectionPtr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1063
									
								
								libs/gempa/caps/datetime.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1063
									
								
								libs/gempa/caps/datetime.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										245
									
								
								libs/gempa/caps/datetime.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								libs/gempa/caps/datetime.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,245 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_DATETIME_H
 | 
			
		||||
#define GEMPA_CAPS_DATETIME_H
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
struct tm;
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TimeSpan {
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Xstruction
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		TimeSpan();
 | 
			
		||||
		TimeSpan(struct timeval*);
 | 
			
		||||
		TimeSpan(const struct timeval&);
 | 
			
		||||
		TimeSpan(double);
 | 
			
		||||
		TimeSpan(long secs, long usecs);
 | 
			
		||||
 | 
			
		||||
		//! Copy constructor
 | 
			
		||||
		TimeSpan(const TimeSpan&);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Operators
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		//! Comparison
 | 
			
		||||
		bool operator==(const TimeSpan&) const;
 | 
			
		||||
		bool operator!=(const TimeSpan&) const;
 | 
			
		||||
		bool operator< (const TimeSpan&) const;
 | 
			
		||||
		bool operator<=(const TimeSpan&) const;
 | 
			
		||||
		bool operator> (const TimeSpan&) const;
 | 
			
		||||
		bool operator>=(const TimeSpan&) const;
 | 
			
		||||
 | 
			
		||||
		//! Conversion
 | 
			
		||||
		operator double() const;
 | 
			
		||||
		operator const timeval&() const;
 | 
			
		||||
 | 
			
		||||
		//! Assignment
 | 
			
		||||
		TimeSpan& operator=(long t);
 | 
			
		||||
		TimeSpan& operator=(double t);
 | 
			
		||||
 | 
			
		||||
		//! Arithmetic
 | 
			
		||||
		TimeSpan operator+(const TimeSpan&) const;
 | 
			
		||||
		TimeSpan operator-(const TimeSpan&) const;
 | 
			
		||||
 | 
			
		||||
		TimeSpan& operator+=(const TimeSpan&);
 | 
			
		||||
		TimeSpan& operator-=(const TimeSpan&);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Interface
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		//! Returns the absolute value of time
 | 
			
		||||
		TimeSpan abs() const;
 | 
			
		||||
 | 
			
		||||
		//! Returns the seconds of the timespan
 | 
			
		||||
		long seconds() const;
 | 
			
		||||
		//! Returns the microseconds of the timespan
 | 
			
		||||
		long microseconds() const;
 | 
			
		||||
 | 
			
		||||
		//! Returns the (possibly negative) length of the timespan in seconds
 | 
			
		||||
		double length() const;
 | 
			
		||||
 | 
			
		||||
		//! Sets the seconds
 | 
			
		||||
		TimeSpan& set(long seconds);
 | 
			
		||||
 | 
			
		||||
		//! Sets the microseconds
 | 
			
		||||
		TimeSpan& setUSecs(long);
 | 
			
		||||
 | 
			
		||||
		//! Assigns the elapsed time to the passed out parameters
 | 
			
		||||
		void elapsedTime(int* days	, int* hours = NULL,
 | 
			
		||||
		                 int* minutes = NULL, int* seconds = NULL) const;
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Implementation
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	protected:
 | 
			
		||||
		struct timeval _timeval;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Time : public TimeSpan {
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	// Public static data members
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		static const Time Null;
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Xstruction
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		Time();
 | 
			
		||||
		Time(long secs, long usecs);
 | 
			
		||||
 | 
			
		||||
		explicit Time(const TimeSpan&);
 | 
			
		||||
		explicit Time(const struct timeval&);
 | 
			
		||||
		explicit Time(struct timeval*);
 | 
			
		||||
		explicit Time(double);
 | 
			
		||||
 | 
			
		||||
		Time(int year, int month, int day,
 | 
			
		||||
		     int hour = 0, int min = 0, int sec = 0,
 | 
			
		||||
		     int usec = 0);
 | 
			
		||||
 | 
			
		||||
		//! Copy constructor
 | 
			
		||||
		Time(const Time&);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Operators
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		//! Conversion
 | 
			
		||||
		operator bool() const;
 | 
			
		||||
		operator time_t() const;
 | 
			
		||||
 | 
			
		||||
		//! Assignment
 | 
			
		||||
		Time& operator=(const struct timeval& t);
 | 
			
		||||
		Time& operator=(struct timeval* t);
 | 
			
		||||
		Time& operator=(time_t t);
 | 
			
		||||
		Time& operator=(double t);
 | 
			
		||||
 | 
			
		||||
		//! Arithmetic
 | 
			
		||||
		Time operator+(const TimeSpan&) const;
 | 
			
		||||
		Time operator-(const TimeSpan&) const;
 | 
			
		||||
		TimeSpan operator-(const Time&) const;
 | 
			
		||||
 | 
			
		||||
		Time& operator+=(const TimeSpan&);
 | 
			
		||||
		Time& operator-=(const TimeSpan&);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	//  Interface
 | 
			
		||||
	// ----------------------------------------------------------------------
 | 
			
		||||
	public:
 | 
			
		||||
		//! Sets the time
 | 
			
		||||
		Time& set(int year, int month, int day,
 | 
			
		||||
		          int hour, int min, int sec,
 | 
			
		||||
		          int usec);
 | 
			
		||||
 | 
			
		||||
		//! Fill the parameters with the currently set time values
 | 
			
		||||
		//! @return The error flag
 | 
			
		||||
		bool get(int *year, int *month = NULL, int *day = NULL,
 | 
			
		||||
		         int *hour = NULL, int *min = NULL, int *sec = NULL,
 | 
			
		||||
		         int *usec = NULL) const;
 | 
			
		||||
 | 
			
		||||
		//! Fill the parameters with the currently set time values
 | 
			
		||||
		//! @return The error flag
 | 
			
		||||
		bool get2(int *year, int *yday = NULL,
 | 
			
		||||
		          int *hour = NULL, int *min = NULL, int *sec = NULL,
 | 
			
		||||
		          int *usec = NULL) const;
 | 
			
		||||
 | 
			
		||||
		//! Returns the current localtime
 | 
			
		||||
		static Time LocalTime();
 | 
			
		||||
 | 
			
		||||
		//! Returns the current gmtime
 | 
			
		||||
		static Time GMT();
 | 
			
		||||
 | 
			
		||||
		/** Creates a time from the year and the day of the year
 | 
			
		||||
		    @param year The year, including the century (for example, 1988)
 | 
			
		||||
		    @param year_day The day of the year [0..365]
 | 
			
		||||
		    @return The time value
 | 
			
		||||
		 */
 | 
			
		||||
		static Time FromYearDay(int year, int year_day);
 | 
			
		||||
 | 
			
		||||
		//! Saves the current localtime in the calling object
 | 
			
		||||
		Time& localtime();
 | 
			
		||||
 | 
			
		||||
		//! Saves the current gmtime in the calling object
 | 
			
		||||
		Time& gmt();
 | 
			
		||||
 | 
			
		||||
		//! Converts the time to localtime
 | 
			
		||||
		Time toLocalTime() const;
 | 
			
		||||
 | 
			
		||||
		//! Converts the time to gmtime
 | 
			
		||||
		Time toGMT() const;
 | 
			
		||||
 | 
			
		||||
		//! Returns whether the date is valid or not
 | 
			
		||||
		bool valid() const;
 | 
			
		||||
 | 
			
		||||
		/** Converts the time to string using format fmt.
 | 
			
		||||
		    @param fmt The format string can contain any specifiers
 | 
			
		||||
		               as allowed for strftime. Additional the '%f'
 | 
			
		||||
		               specifier is replaced by the fraction of the seconds.
 | 
			
		||||
		               Example:
 | 
			
		||||
		               toString("%FT%T.%fZ") = "1970-01-01T00:00:00.0000Z"
 | 
			
		||||
		    @return A formatted string
 | 
			
		||||
		 */
 | 
			
		||||
		std::string toString(const char* fmt) const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Converts the time to a string using the ISO time description
 | 
			
		||||
		 * @return A formatted string
 | 
			
		||||
		 */
 | 
			
		||||
		std::string iso() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Converts a string into a time representation.
 | 
			
		||||
		 * @param str The string representation of the time
 | 
			
		||||
		 * @param fmt The format string containing the conversion
 | 
			
		||||
		 *            specification (-> toString)
 | 
			
		||||
		 * @return The conversion result
 | 
			
		||||
		 */
 | 
			
		||||
		bool fromString(const char* str, const char* fmt);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Static method to create a time value from a string.
 | 
			
		||||
		 * The parameters are the same as in Time::fromString.
 | 
			
		||||
		 */
 | 
			
		||||
		static Time FromString(const char* str, const char* fmt);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										246
									
								
								libs/gempa/caps/encoderfactory.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								libs/gempa/caps/encoderfactory.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,246 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2016 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "encoderfactory.h"
 | 
			
		||||
 | 
			
		||||
#include "mseed/mseed.h"
 | 
			
		||||
#include "mseed/steim1.h"
 | 
			
		||||
#include "mseed/steim2.h"
 | 
			
		||||
#include "mseed/uncompressed.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
EncoderFactory::EncoderFactory() {}
 | 
			
		||||
 | 
			
		||||
EncoderFactory::~EncoderFactory() {}
 | 
			
		||||
 | 
			
		||||
const string& EncoderFactory::errorString() const {
 | 
			
		||||
	return _errorString;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MSEEDEncoderFactory::MSEEDEncoderFactory()
 | 
			
		||||
: _recordLength(9) {}
 | 
			
		||||
 | 
			
		||||
bool MSEEDEncoderFactory::setRecordLength(uint recordLength) {
 | 
			
		||||
	if ( recordLength < 7 || recordLength > 32) {
 | 
			
		||||
		_errorString = "MSEED record length out of range [7, 32]";
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_recordLength = uint8_t(recordLength);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SteimEncoderFactory::supportsRecord(DataRecord *rec) {
 | 
			
		||||
	/*
 | 
			
		||||
	DataType dt = rec->header()->dataType;
 | 
			
		||||
	if ( (dt == DT_INT64) || (dt == DT_FLOAT) ||
 | 
			
		||||
		 (dt == DT_DOUBLE) ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	*/
 | 
			
		||||
 | 
			
		||||
	PacketType type = rec->packetType();
 | 
			
		||||
	if ( type == RawDataPacket || type == FixedRawDataPacket ) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	else if ( type == MSEEDPacket ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool IdentityEncoderFactory::supportsRecord(DataRecord *rec) {
 | 
			
		||||
	PacketType type = rec->packetType();
 | 
			
		||||
	return type == RawDataPacket || type == FixedRawDataPacket;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Encoder* IdentityEncoderFactory::create(const std::string &networkCode,
 | 
			
		||||
                                        const std::string &stationCode,
 | 
			
		||||
                                        const std::string &locationCode,
 | 
			
		||||
                                        const std::string &channelCode,
 | 
			
		||||
                                        int dt,
 | 
			
		||||
                                        int samplingFrequencyNumerator,
 | 
			
		||||
                                        int samplingFrequencyDenominator) {
 | 
			
		||||
	if ( dt == DT_INT8 ) {
 | 
			
		||||
		MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
		                                      locationCode, channelCode,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator,
 | 
			
		||||
		                                      DE_ASCII,
 | 
			
		||||
		                                      _recordLength);
 | 
			
		||||
		if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
		return new UncompressedMSEED<int8_t>(format,
 | 
			
		||||
		                                     samplingFrequencyNumerator,
 | 
			
		||||
		                                     samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_INT16 ) {
 | 
			
		||||
		MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
		                                      locationCode, channelCode,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator,
 | 
			
		||||
		                                      DE_INT16,
 | 
			
		||||
		                                      _recordLength);
 | 
			
		||||
		if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
		return new UncompressedMSEED<int16_t>(format,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_INT32 ) {
 | 
			
		||||
		MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
		                                      locationCode, channelCode,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator,
 | 
			
		||||
		                                      DE_INT32,
 | 
			
		||||
		                                      _recordLength);
 | 
			
		||||
		if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
		return new UncompressedMSEED<int32_t>(format,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_FLOAT ) {
 | 
			
		||||
		MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
		                                      locationCode, channelCode,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator,
 | 
			
		||||
		                                      DE_FLOAT32,
 | 
			
		||||
		                                      _recordLength);
 | 
			
		||||
		if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
		return new UncompressedMSEED<float>(format,
 | 
			
		||||
		                                    samplingFrequencyNumerator,
 | 
			
		||||
		                                    samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_DOUBLE ) {
 | 
			
		||||
		MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
		                                      locationCode, channelCode,
 | 
			
		||||
		                                      samplingFrequencyNumerator,
 | 
			
		||||
		                                      samplingFrequencyDenominator,
 | 
			
		||||
		                                      DE_FLOAT64,
 | 
			
		||||
		                                      _recordLength);
 | 
			
		||||
		if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
		return new UncompressedMSEED<double>(format,
 | 
			
		||||
		                                     samplingFrequencyNumerator,
 | 
			
		||||
		                                     samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Encoder* Steim1EncoderFactory::create(const std::string &networkCode,
 | 
			
		||||
                                      const std::string &stationCode,
 | 
			
		||||
                                      const std::string &locationCode,
 | 
			
		||||
                                      const std::string &channelCode,
 | 
			
		||||
                                      int dt,
 | 
			
		||||
                                      int samplingFrequencyNumerator,
 | 
			
		||||
                                      int samplingFrequencyDenominator) {
 | 
			
		||||
	MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
	                                      locationCode, channelCode,
 | 
			
		||||
	                                      samplingFrequencyNumerator,
 | 
			
		||||
	                                      samplingFrequencyDenominator,
 | 
			
		||||
	                                      DE_STEIM1,
 | 
			
		||||
	                                      _recordLength);
 | 
			
		||||
	if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
	if ( dt == DT_INT8 ) {
 | 
			
		||||
		return new Steim1Encoder<int8_t>(format,
 | 
			
		||||
		                                 samplingFrequencyNumerator,
 | 
			
		||||
		                                 samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_INT16 ) {
 | 
			
		||||
		return new Steim1Encoder<int16_t>(format,
 | 
			
		||||
		                                  samplingFrequencyNumerator,
 | 
			
		||||
		                                  samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_INT32 ) {
 | 
			
		||||
		return new Steim1Encoder<int32_t>(format,
 | 
			
		||||
		                                  samplingFrequencyNumerator,
 | 
			
		||||
		                                  samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_FLOAT ) {
 | 
			
		||||
		return new Steim1Encoder<float>(format,
 | 
			
		||||
		                                samplingFrequencyNumerator,
 | 
			
		||||
		                                samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_DOUBLE ) {
 | 
			
		||||
		return new Steim1Encoder<double>(format,
 | 
			
		||||
		                                 samplingFrequencyNumerator,
 | 
			
		||||
		                                 samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete format;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Encoder* Steim2EncoderFactory::create(const std::string &networkCode,
 | 
			
		||||
                                      const std::string &stationCode,
 | 
			
		||||
                                      const std::string &locationCode,
 | 
			
		||||
                                      const std::string &channelCode,
 | 
			
		||||
                                      int dt,
 | 
			
		||||
                                      int samplingFrequencyNumerator,
 | 
			
		||||
                                      int samplingFrequencyDenominator) {
 | 
			
		||||
	MSEEDFormat *format = new MSEEDFormat(networkCode, stationCode,
 | 
			
		||||
	                                      locationCode, channelCode,
 | 
			
		||||
	                                      samplingFrequencyNumerator,
 | 
			
		||||
	                                      samplingFrequencyDenominator,
 | 
			
		||||
	                                      DE_STEIM2,
 | 
			
		||||
	                                      _recordLength);
 | 
			
		||||
	if ( format == NULL ) return NULL;
 | 
			
		||||
 | 
			
		||||
	if ( dt == DT_INT8 ) {
 | 
			
		||||
		return new Steim2Encoder<int8_t>(format,
 | 
			
		||||
		                                 samplingFrequencyNumerator,
 | 
			
		||||
		                                 samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_INT16 ) {
 | 
			
		||||
		return new Steim2Encoder<int16_t>(format,
 | 
			
		||||
		                                  samplingFrequencyNumerator,
 | 
			
		||||
		                                  samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_INT32 ) {
 | 
			
		||||
		return new Steim2Encoder<int32_t>(format,
 | 
			
		||||
		                                  samplingFrequencyNumerator,
 | 
			
		||||
		                                  samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_FLOAT ) {
 | 
			
		||||
		return new Steim2Encoder<float>(format,
 | 
			
		||||
		                                samplingFrequencyNumerator,
 | 
			
		||||
		                                samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
	else if ( dt == DT_DOUBLE ) {
 | 
			
		||||
		return new Steim2Encoder<double>(format,
 | 
			
		||||
		                                 samplingFrequencyNumerator,
 | 
			
		||||
		                                 samplingFrequencyDenominator);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	delete format;
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										164
									
								
								libs/gempa/caps/encoderfactory.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								libs/gempa/caps/encoderfactory.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,164 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2016 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_ENCODERFACTORY_H
 | 
			
		||||
#define GEMPA_CAPS_ENCODERFACTORY_H
 | 
			
		||||
 | 
			
		||||
#include "mseed/encoder.h"
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Abstract base class of the encoder factory. Each
 | 
			
		||||
 * derived class must implement the create and the
 | 
			
		||||
 * supportsRecord method.
 | 
			
		||||
 */
 | 
			
		||||
class EncoderFactory {
 | 
			
		||||
	public:
 | 
			
		||||
		EncoderFactory();
 | 
			
		||||
		virtual ~EncoderFactory();
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Creates encoder from given parameter set
 | 
			
		||||
		 * @param networkCode The nework code
 | 
			
		||||
		 * @param stationCode The station code
 | 
			
		||||
		 * @param locationCode The location code
 | 
			
		||||
		 * @param channelCode The channel code
 | 
			
		||||
		 * @param dt The data encoding
 | 
			
		||||
		 * @param samplingFrequencyNumerator The numerator
 | 
			
		||||
		 * @param samplingFrequencyDenominator The denominator
 | 
			
		||||
		 * @param samplingFrequencyDenominator The timing quality
 | 
			
		||||
		 * @return The encoder object or NULL if creation fails
 | 
			
		||||
		 */
 | 
			
		||||
		virtual Encoder* create(const std::string &networkCode,
 | 
			
		||||
		                        const std::string &stationCode,
 | 
			
		||||
		                        const std::string &locationCode,
 | 
			
		||||
		                        const std::string &channelCode,
 | 
			
		||||
		                        int dt,
 | 
			
		||||
		                        int samplingFrequencyNumerator,
 | 
			
		||||
		                        int samplingFrequencyDenominator) = 0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Checks if an encoder factory
 | 
			
		||||
		 * supports the given record.
 | 
			
		||||
		 * @param rec The record to check
 | 
			
		||||
		 * @return True if the data type is supported
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool supportsRecord(DataRecord *rec) = 0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns a human readable error description
 | 
			
		||||
		 * of the last error occured.
 | 
			
		||||
		 * @return Error description
 | 
			
		||||
		 */
 | 
			
		||||
		const std::string& errorString() const;
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		std::string    _errorString;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Base class for all MSEED encoders
 | 
			
		||||
 */
 | 
			
		||||
class MSEEDEncoderFactory : public EncoderFactory {
 | 
			
		||||
	public:
 | 
			
		||||
		MSEEDEncoderFactory();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the volume logical record length expressed as a
 | 
			
		||||
		 * power of 2. A 512 byte record would be 9.
 | 
			
		||||
		 * @param recLen The record length expressed as a power of 2
 | 
			
		||||
		 * @return True if the record length is valid
 | 
			
		||||
		 */
 | 
			
		||||
		bool setRecordLength(uint recordLength);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		uint8_t _recordLength;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Implements a general Steim encoder factory
 | 
			
		||||
 * interface which implements the supportsRecord method
 | 
			
		||||
 * only.
 | 
			
		||||
 */
 | 
			
		||||
class SteimEncoderFactory : public MSEEDEncoderFactory  {
 | 
			
		||||
	public:
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Checks if an encoder factory
 | 
			
		||||
		 * supports the given record. In case of data type float or double we
 | 
			
		||||
		 * return true but the values will casted implicitly to int32.
 | 
			
		||||
		 * @param rec The record to check
 | 
			
		||||
		 * @return True if the data type is supported
 | 
			
		||||
		 */
 | 
			
		||||
		bool supportsRecord(DataRecord *rec);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief The IdentiyEncoderFactory class implements the
 | 
			
		||||
 * encoder factory interface and supports the creation of
 | 
			
		||||
 * identiy encoders.
 | 
			
		||||
 */
 | 
			
		||||
class IdentityEncoderFactory : public MSEEDEncoderFactory {
 | 
			
		||||
	public:
 | 
			
		||||
		Encoder* create(const std::string &networkCode,
 | 
			
		||||
		                const std::string &stationCode,
 | 
			
		||||
		                const std::string &locationCode,
 | 
			
		||||
		                const std::string &channelCode,
 | 
			
		||||
		                int dt,
 | 
			
		||||
		                int samplingFrequencyNumerator,
 | 
			
		||||
		                int samplingFrequencyDenominator);
 | 
			
		||||
		bool supportsRecord(DataRecord *rec);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief The Steim1EncoderFactory class implements the
 | 
			
		||||
 * encoder factory interface and supports the creation of
 | 
			
		||||
 * Steim2 encoders.
 | 
			
		||||
 */
 | 
			
		||||
class Steim1EncoderFactory : public SteimEncoderFactory {
 | 
			
		||||
	public:
 | 
			
		||||
		Encoder* create(const std::string &networkCode,
 | 
			
		||||
		                const std::string &stationCode,
 | 
			
		||||
		                const std::string &locationCode,
 | 
			
		||||
		                const std::string &channelCode,
 | 
			
		||||
		                int dt,
 | 
			
		||||
		                int samplingFrequencyNumerator,
 | 
			
		||||
		                int samplingFrequencyDenominator);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief The Steim2EncoderFactory class implements the
 | 
			
		||||
 * encoder factory interface and supports the creation of
 | 
			
		||||
 * Steim2 encoders.
 | 
			
		||||
 */
 | 
			
		||||
class Steim2EncoderFactory : public SteimEncoderFactory {
 | 
			
		||||
	public:
 | 
			
		||||
		Encoder* create(const std::string &networkCode,
 | 
			
		||||
		                const std::string &stationCode,
 | 
			
		||||
		                const std::string &locationCode,
 | 
			
		||||
		                const std::string &channelCode,
 | 
			
		||||
		                int dt,
 | 
			
		||||
		                int samplingFrequencyNumerator,
 | 
			
		||||
		                int samplingFrequencyDenominator);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										210
									
								
								libs/gempa/caps/endianess.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								libs/gempa/caps/endianess.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,210 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_ENDIANESS_H
 | 
			
		||||
#define GEMPA_CAPS_ENDIANESS_H
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
namespace Endianess {
 | 
			
		||||
 | 
			
		||||
template <typename T1, typename T2> inline const T1* lvalue(const T2 &value) {
 | 
			
		||||
	return reinterpret_cast<const T1*>(&value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, int swap, int size>
 | 
			
		||||
struct Swapper {
 | 
			
		||||
	static T Take(const T &v) {
 | 
			
		||||
		return v;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void Take(T *ar, int len) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct Swapper<T,1,2> {
 | 
			
		||||
	static T Take(const T &v) {
 | 
			
		||||
		return *lvalue<T, uint16_t>((*reinterpret_cast<const uint16_t*>(&v) >> 0x08) |
 | 
			
		||||
		       (*reinterpret_cast<const uint16_t*>(&v) << 0x08));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void Take(T *ar, int len) {
 | 
			
		||||
		for ( int i = 0; i < len; ++i )
 | 
			
		||||
			ar[i] = Take(ar[i]);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct Swapper<T,1,4> {
 | 
			
		||||
	static T Take(const T &v) {
 | 
			
		||||
		return *lvalue<T, uint32_t>(((*reinterpret_cast<const uint32_t*>(&v) << 24) & 0xFF000000) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint32_t*>(&v) << 8)  & 0x00FF0000) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint32_t*>(&v) >> 8)  & 0x0000FF00) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint32_t*>(&v) >> 24) & 0x000000FF));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void Take(T *ar, int len) {
 | 
			
		||||
		for ( int i = 0; i < len; ++i )
 | 
			
		||||
			ar[i] = Take(ar[i]);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct Swapper<T,1,8> {
 | 
			
		||||
	static T Take(const T &v) {
 | 
			
		||||
		return *lvalue<T, uint64_t>(((*reinterpret_cast<const uint64_t*>(&v) << 56) & 0xFF00000000000000LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) << 40) & 0x00FF000000000000LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) << 24) & 0x0000FF0000000000LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) << 8)  & 0x000000FF00000000LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) >> 8)  & 0x00000000FF000000LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) >> 24) & 0x0000000000FF0000LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) >> 40) & 0x000000000000FF00LL) |
 | 
			
		||||
		       ((*reinterpret_cast<const uint64_t*>(&v) >> 56) & 0x00000000000000FFLL));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void Take(T *ar, int len) {
 | 
			
		||||
		for ( int i = 0; i < len; ++i )
 | 
			
		||||
			ar[i] = Take(ar[i]);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int size>
 | 
			
		||||
struct TypeMap {
 | 
			
		||||
	typedef void ValueType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct TypeMap<1> {
 | 
			
		||||
	typedef uint8_t ValueType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct TypeMap<2> {
 | 
			
		||||
	typedef uint16_t ValueType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct TypeMap<4> {
 | 
			
		||||
	typedef uint32_t ValueType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct TypeMap<8> {
 | 
			
		||||
	typedef uint64_t ValueType;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int swap, int size>
 | 
			
		||||
struct ByteSwapper {
 | 
			
		||||
	static void Take(void *ar, int len) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int size>
 | 
			
		||||
struct ByteSwapper<1,size> {
 | 
			
		||||
	static void Take(void *ar, int len) {
 | 
			
		||||
		typedef typename TypeMap<size>::ValueType T;
 | 
			
		||||
		Swapper<T,1,size>::Take(reinterpret_cast<T*>(ar), len);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct Current {
 | 
			
		||||
	enum {
 | 
			
		||||
		LittleEndian = ((0x1234 >> 8) == 0x12?1:0),
 | 
			
		||||
		BigEndian = 1-LittleEndian
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct Converter {
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	static T ToLittleEndian(const T &v) {
 | 
			
		||||
		return Swapper<T,Current::BigEndian,sizeof(T)>::Take(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	static void ToLittleEndian(T *data, int len) {
 | 
			
		||||
		Swapper<T,Current::BigEndian,sizeof(T)>::Take(data, len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	static T FromLittleEndian(const T &v) {
 | 
			
		||||
		return Swapper<T,Current::BigEndian,sizeof(T)>::Take(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	static T ToBigEndian(const T &v) {
 | 
			
		||||
		return Swapper<T,Current::LittleEndian,sizeof(T)>::Take(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	static T FromBigEndian(const T &v) {
 | 
			
		||||
		return Swapper<T,Current::LittleEndian,sizeof(T)>::Take(v);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Reader {
 | 
			
		||||
	Reader(std::streambuf &input) : stream(input), good(true) {}
 | 
			
		||||
 | 
			
		||||
	void operator()(void *data, int size) {
 | 
			
		||||
		good = stream.sgetn((char*)data, size) == size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	void operator()(T &v) {
 | 
			
		||||
		good = stream.sgetn((char*)&v, sizeof(T)) == sizeof(T);
 | 
			
		||||
		v = Converter::FromLittleEndian(v);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::streambuf &stream;
 | 
			
		||||
	bool good;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Writer {
 | 
			
		||||
	Writer(std::streambuf &output) : stream(output), good(true) {}
 | 
			
		||||
 | 
			
		||||
	bool operator()(const void *data, int size) {
 | 
			
		||||
		return (good = stream.sputn((char*)data, size) == size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template <typename T>
 | 
			
		||||
	bool operator()(T &v) {
 | 
			
		||||
		T tmp = Converter::ToLittleEndian(v);
 | 
			
		||||
		return (good = stream.sputn((char*)&tmp, sizeof(T)) == sizeof(T));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::streambuf &stream;
 | 
			
		||||
	bool good;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										31
									
								
								libs/gempa/caps/log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								libs/gempa/caps/log.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SetLogHandler(LogLevel l, LogOutput o) {
 | 
			
		||||
	LogHandler[l] = o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LogOutput LogHandler[LL_QUANTITY] = { NULL, NULL, NULL, NULL, NULL, NULL };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								libs/gempa/caps/log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								libs/gempa/caps/log.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_LOG_H
 | 
			
		||||
#define GEMPA_CAPS_LOG_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum LogLevel {
 | 
			
		||||
	LL_UNDEFINED = 0,
 | 
			
		||||
	LL_ERROR,
 | 
			
		||||
	LL_WARNING,
 | 
			
		||||
	LL_NOTICE,
 | 
			
		||||
	LL_INFO,
 | 
			
		||||
	LL_DEBUG,
 | 
			
		||||
	LL_QUANTITY
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CAPS_LOG_MSG(LogLevel, ...) \
 | 
			
		||||
	do {\
 | 
			
		||||
		if ( Gempa::CAPS::LogHandler[LogLevel] != NULL )\
 | 
			
		||||
			Gempa::CAPS::LogHandler[LogLevel](__VA_ARGS__);\
 | 
			
		||||
	} while(0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CAPS_ERROR(...) CAPS_LOG_MSG(Gempa::CAPS::LL_ERROR, __VA_ARGS__)
 | 
			
		||||
#define CAPS_WARNING(...) CAPS_LOG_MSG(Gempa::CAPS::LL_WARNING, __VA_ARGS__)
 | 
			
		||||
#define CAPS_NOTICE(...) CAPS_LOG_MSG(Gempa::CAPS::LL_NOTICE, __VA_ARGS__)
 | 
			
		||||
#define CAPS_INFO(...) CAPS_LOG_MSG(Gempa::CAPS::LL_INFO, __VA_ARGS__)
 | 
			
		||||
#define CAPS_DEBUG(...) CAPS_LOG_MSG(Gempa::CAPS::LL_DEBUG, __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef void (*LogOutput)(const char *, ...);
 | 
			
		||||
 | 
			
		||||
extern LogOutput LogHandler[LL_QUANTITY];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void SetLogHandler(LogLevel, LogOutput);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										81
									
								
								libs/gempa/caps/metapacket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								libs/gempa/caps/metapacket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/metapacket.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/riff.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
void MetaDataRecord::MetaHeader::setEndTime(const Time &ts) {
 | 
			
		||||
	int year, yday, hour, min, sec, usec;
 | 
			
		||||
	ts.get2(&year, &yday, &hour, &min, &sec, &usec);
 | 
			
		||||
	endTime.year = year;
 | 
			
		||||
	endTime.yday = yday;
 | 
			
		||||
	endTime.hour = hour;
 | 
			
		||||
	endTime.minute = min;
 | 
			
		||||
	endTime.second = sec;
 | 
			
		||||
	endTime.usec = usec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MetaDataRecord::MetaDataRecord() {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MetaDataRecord::Buffer *MetaDataRecord::data() {
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *MetaDataRecord::formatName() const {
 | 
			
		||||
	return "META";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DataRecord::Header *MetaDataRecord::header() const {
 | 
			
		||||
	return &_header.dataHeader;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time MetaDataRecord::startTime() const {
 | 
			
		||||
	return _startTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time MetaDataRecord::endTime() const {
 | 
			
		||||
	return _endTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t MetaDataRecord::dataSize(bool /*withHeader*/) const {
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DataRecord::ReadStatus MetaDataRecord::get(std::streambuf &buf, int size,
 | 
			
		||||
                                          const Time &start, const Time &end,
 | 
			
		||||
                                          int maxBytes) {
 | 
			
		||||
	return RS_Error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MetaDataRecord::setHeader(const MetaHeader &header) {
 | 
			
		||||
	_header = header;
 | 
			
		||||
	_startTime = timestampToTime(header.dataHeader.samplingTime);
 | 
			
		||||
	_endTime = timestampToTime(header.endTime);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										143
									
								
								libs/gempa/caps/metapacket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								libs/gempa/caps/metapacket.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,143 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_METAPACKET_H
 | 
			
		||||
#define GEMPA_CAPS_METAPACKET_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/api.h>
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API MetaResponseHeader {
 | 
			
		||||
	struct Time {
 | 
			
		||||
		int64_t seconds;
 | 
			
		||||
		int32_t microSeconds;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Time  startTime;
 | 
			
		||||
	Time  endTime;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
		get(startTime.seconds);
 | 
			
		||||
		get(startTime.microSeconds);
 | 
			
		||||
 | 
			
		||||
		get(endTime.seconds);
 | 
			
		||||
		get(endTime.microSeconds);
 | 
			
		||||
 | 
			
		||||
		return get.good;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int dataSize() const {
 | 
			
		||||
		return sizeof(startTime.seconds) + sizeof(startTime.microSeconds) +
 | 
			
		||||
		       sizeof(endTime.seconds) + sizeof(endTime.microSeconds);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MetaDataRecord : public DataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		struct MetaHeader {
 | 
			
		||||
			Header    dataHeader;
 | 
			
		||||
			TimeStamp endTime;
 | 
			
		||||
 | 
			
		||||
			bool get(std::streambuf &buf) {
 | 
			
		||||
				Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
				get(endTime.year);
 | 
			
		||||
				get(endTime.yday);
 | 
			
		||||
				get(endTime.hour);
 | 
			
		||||
				get(endTime.minute);
 | 
			
		||||
				get(endTime.second);
 | 
			
		||||
				get(endTime.usec);
 | 
			
		||||
 | 
			
		||||
				return get.good;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool put(std::streambuf &buf) const;
 | 
			
		||||
 | 
			
		||||
			int dataSize() const {
 | 
			
		||||
				return dataHeader.dataSize() +
 | 
			
		||||
				       sizeof(endTime.year) +
 | 
			
		||||
				       sizeof(endTime.yday) +
 | 
			
		||||
				       sizeof(endTime.hour) +
 | 
			
		||||
				       sizeof(endTime.minute) +
 | 
			
		||||
				       sizeof(endTime.second) +
 | 
			
		||||
				       sizeof(endTime.usec);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			void setEndTime(const Time ×tamp);
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		MetaDataRecord();
 | 
			
		||||
 | 
			
		||||
		//! Returns the data vector to be filled by the caller
 | 
			
		||||
		Buffer *data();
 | 
			
		||||
 | 
			
		||||
		virtual const char *formatName() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
		                          Header &header,
 | 
			
		||||
		                          Time &startTime, Time &endTime) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual const Header *header() const;
 | 
			
		||||
 | 
			
		||||
		//! Sets a custom header and updates all internal structures
 | 
			
		||||
		//! based on the current data. If the data has changed, make
 | 
			
		||||
		//! sure to call this method again. If the flag skip reading
 | 
			
		||||
		//! is set get will not read the header information from stream
 | 
			
		||||
		void setHeader(const MetaHeader &header);
 | 
			
		||||
 | 
			
		||||
		virtual Time startTime() const;
 | 
			
		||||
		virtual Time endTime() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool canTrim() const { return false; }
 | 
			
		||||
		virtual bool canMerge() const { return false; }
 | 
			
		||||
 | 
			
		||||
		virtual bool trim(const Time &start, const Time &end) const { return false; }
 | 
			
		||||
 | 
			
		||||
		virtual size_t dataSize(bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		virtual ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		                       const Time &start, const Time &end,
 | 
			
		||||
		                       int maxBytes);
 | 
			
		||||
 | 
			
		||||
		virtual bool put(std::streambuf &buf, bool withHeader) const { return false; }
 | 
			
		||||
 | 
			
		||||
		PacketType packetType() const { return MetaDataPacket; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		MetaHeader      _header;
 | 
			
		||||
 | 
			
		||||
		mutable Time    _startTime;
 | 
			
		||||
		mutable Time    _endTime;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										75
									
								
								libs/gempa/caps/mseed/encoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								libs/gempa/caps/mseed/encoder.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * encoder.h
 | 
			
		||||
 *
 | 
			
		||||
 * Abstract Encoder interface
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_ENCODER_H
 | 
			
		||||
#define CAPS_MSEED_ENCODER_H
 | 
			
		||||
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
#include "spclock.h"
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
#include <gempa/caps/pluginpacket.h>
 | 
			
		||||
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class Encoder {
 | 
			
		||||
	public:
 | 
			
		||||
		Encoder(int freqn, int freqd) : _clk(freqn, freqd),
 | 
			
		||||
		    _sampleCount(0), _timingQuality(-1) {}
 | 
			
		||||
		virtual ~Encoder() {}
 | 
			
		||||
 | 
			
		||||
		virtual void push(void *sample) = 0;
 | 
			
		||||
		virtual void flush() = 0;
 | 
			
		||||
		virtual void reset() { _sampleCount = 0; }
 | 
			
		||||
		virtual int type() const = 0;
 | 
			
		||||
 | 
			
		||||
		const SPClock& clk() { return _clk; }
 | 
			
		||||
 | 
			
		||||
		void setStartTime(const SPClock::INT_TIME &time) { _clk.sync_time(time); }
 | 
			
		||||
		const SPClock::INT_TIME currentTime() const { return _clk.get_time(0); }
 | 
			
		||||
 | 
			
		||||
		int timingQuality() { return _timingQuality; }
 | 
			
		||||
		void setTimingQuality(int quality) { _timingQuality = quality; }
 | 
			
		||||
 | 
			
		||||
		PacketPtr pop() {
 | 
			
		||||
			if ( _packetQueue.empty() ) return PacketPtr();
 | 
			
		||||
 | 
			
		||||
			PacketPtr rec = _packetQueue.front();
 | 
			
		||||
			_packetQueue.pop_front(); 
 | 
			
		||||
			return rec;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		typedef std::list<PacketPtr>  PacketQueue;
 | 
			
		||||
		SPClock      _clk;
 | 
			
		||||
		int          _sampleCount;
 | 
			
		||||
		PacketQueue  _packetQueue;
 | 
			
		||||
		int          _timingQuality;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // __ENCODER_H__
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										162
									
								
								libs/gempa/caps/mseed/mseed.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								libs/gempa/caps/mseed/mseed.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,162 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * mseed.cpp
 | 
			
		||||
 *
 | 
			
		||||
 * Mini-SEED format implementation
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
#include <gempa/caps/rawpacket.h>
 | 
			
		||||
 | 
			
		||||
#include "mseed.h"
 | 
			
		||||
#include "slink.h"
 | 
			
		||||
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
MSEEDFormat::MSEEDFormat(const std::string &netcode, const std::string &stacode,
 | 
			
		||||
                         const std::string &loccode, const std::string &chacode,
 | 
			
		||||
                         unsigned short freqn, unsigned short freqd,
 | 
			
		||||
                         unsigned short packtype_init,
 | 
			
		||||
                         uint8_t recordLength)
 | 
			
		||||
    : networkCode(netcode), stationCode(stacode), locationCode(loccode),
 | 
			
		||||
      channelCode(chacode), packType(packtype_init), recordLength(recordLength)
 | 
			
		||||
{
 | 
			
		||||
	if(freqn == 0 || freqd == 0) {
 | 
			
		||||
		sample_rate_factor = 0;
 | 
			
		||||
		sample_rate_multiplier = 0;
 | 
			
		||||
	}
 | 
			
		||||
	else if(!(freqn % freqd)) {
 | 
			
		||||
		sample_rate_factor = freqn / freqd;
 | 
			
		||||
		sample_rate_multiplier = 1;
 | 
			
		||||
	}
 | 
			
		||||
	else if(!(freqd % freqn)) {
 | 
			
		||||
		sample_rate_factor = -freqd / freqn;
 | 
			
		||||
		sample_rate_multiplier = 1;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		sample_rate_factor = -freqd;
 | 
			
		||||
		sample_rate_multiplier = freqn;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MSEEDDataRecord *MSEEDFormat::get_buffer(const SPClock::INT_TIME &it, int usec_correction,
 | 
			
		||||
                                         int timing_quality, void *&dataptr, int &datalen) {
 | 
			
		||||
	size_t buflen = 1 << recordLength;
 | 
			
		||||
	MSEEDDataRecord *record = new MSEEDDataRecord();
 | 
			
		||||
	record->data()->resize(buflen);
 | 
			
		||||
 | 
			
		||||
	char *buf = record->data()->data();
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	sl_fsdh_s* fsdh = (sl_fsdh_s *)buf;
 | 
			
		||||
 | 
			
		||||
	memset(fsdh, 0, buflen);
 | 
			
		||||
 | 
			
		||||
	const int start_frames = (sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s) +
 | 
			
		||||
	sizeof(sl_blkt_1001_s) + 63) & 0xffffffc0;    // align to 64 bytes
 | 
			
		||||
 | 
			
		||||
	dataptr = (void *)((char *) fsdh + start_frames);
 | 
			
		||||
	datalen = buflen - start_frames;
 | 
			
		||||
 | 
			
		||||
	fsdh->dhq_indicator = 'D';
 | 
			
		||||
	fsdh->reserved = ' ';
 | 
			
		||||
 | 
			
		||||
	strncpy(fsdh->station, stationCode.c_str(), 5);
 | 
			
		||||
	if((n = stationCode.length()) < 5) memset(fsdh->station + n, 32, 5 - n);
 | 
			
		||||
	strncpy(fsdh->location, locationCode.c_str(), 2);
 | 
			
		||||
	if((n = locationCode.length()) < 2) memset(fsdh->location + n, 32, 2 - n);
 | 
			
		||||
	strncpy(fsdh->channel, channelCode.c_str(), 3);
 | 
			
		||||
	if((n = channelCode.length()) < 3) memset(fsdh->channel + n, 32, 3 - n);
 | 
			
		||||
	strncpy(fsdh->network, networkCode.c_str(), 2);
 | 
			
		||||
	if((n = networkCode.length()) < 2) memset(fsdh->network + n, 32, 2 - n);
 | 
			
		||||
 | 
			
		||||
	int year, doy, hour, min, sec;
 | 
			
		||||
	it.get2(&year, &doy, &hour, &min, &sec);
 | 
			
		||||
 | 
			
		||||
	fsdh->start_time.year = htons(year);
 | 
			
		||||
	fsdh->start_time.day = htons(doy+1);
 | 
			
		||||
	fsdh->start_time.hour = hour;
 | 
			
		||||
	fsdh->start_time.min = min;
 | 
			
		||||
	fsdh->start_time.sec = sec;
 | 
			
		||||
	fsdh->start_time.fract = htons(it.microseconds() / 100);
 | 
			
		||||
	fsdh->samprate_fact = (int16_t)htons(sample_rate_factor);
 | 
			
		||||
	fsdh->samprate_mult = (int16_t)htons(sample_rate_multiplier);
 | 
			
		||||
	fsdh->num_blockettes = 1;
 | 
			
		||||
 | 
			
		||||
	div_t d_corr = div(usec_correction + ((usec_correction < 0) ? -50: 50), 100);
 | 
			
		||||
	fsdh->time_correct = (int32_t)htonl(d_corr.quot);
 | 
			
		||||
 | 
			
		||||
	fsdh->begin_data = htons(start_frames);
 | 
			
		||||
	fsdh->begin_blockette = htons(sizeof(sl_fsdh_s));
 | 
			
		||||
 | 
			
		||||
	sl_blkt_1000_s* blkt_1000 = (sl_blkt_1000_s *)((char *) fsdh + sizeof(sl_fsdh_s));
 | 
			
		||||
	blkt_1000->blkt_type = htons(1000);          // Data Only SEED Blockette
 | 
			
		||||
 | 
			
		||||
	blkt_1000->encoding = packType;
 | 
			
		||||
	blkt_1000->word_swap = 1;                    // big endian
 | 
			
		||||
	blkt_1000->rec_len = recordLength; // 9 = 512 bytes
 | 
			
		||||
 | 
			
		||||
	if ( timing_quality >= 0 ) {
 | 
			
		||||
		blkt_1000->next_blkt = htons(sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s));
 | 
			
		||||
		++fsdh->num_blockettes;
 | 
			
		||||
 | 
			
		||||
		sl_blkt_1001_s* blkt_1001 = (sl_blkt_1001_s *)((char *) fsdh +
 | 
			
		||||
		  sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s));
 | 
			
		||||
 | 
			
		||||
		blkt_1001->blkt_type = htons(1001);      // Data Extension Blockette
 | 
			
		||||
		blkt_1001->timing_qual = timing_quality;
 | 
			
		||||
 | 
			
		||||
		blkt_1001->usec = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return record;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void MSEEDFormat::updateBuffer(MSEEDDataRecord *rec, int samples, int frames) {
 | 
			
		||||
	sl_fsdh_s* fsdh = (sl_fsdh_s *)rec->data()->data();
 | 
			
		||||
	char temp[7];
 | 
			
		||||
 | 
			
		||||
	sprintf(temp, "%06d", (int)0);
 | 
			
		||||
	memcpy(fsdh->sequence_number,temp,6);
 | 
			
		||||
	fsdh->dhq_indicator = 'D';
 | 
			
		||||
	fsdh->num_samples = htons(samples);
 | 
			
		||||
 | 
			
		||||
	sl_blkt_1000_s* blkt_1000 = (sl_blkt_1000_s *)((char *) fsdh + sizeof(sl_fsdh_s));
 | 
			
		||||
 | 
			
		||||
	if ( ntohs(blkt_1000->next_blkt) != 0 ) {
 | 
			
		||||
		sl_blkt_1001_s* blkt_1001 = (sl_blkt_1001_s *)((char *) fsdh +
 | 
			
		||||
		                             sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s));
 | 
			
		||||
 | 
			
		||||
		blkt_1001->frame_cnt = frames;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rec->unpackHeader();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								libs/gempa/caps/mseed/mseed.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								libs/gempa/caps/mseed/mseed.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * mseed.h
 | 
			
		||||
 *
 | 
			
		||||
 * Mini-SEED format implementation
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_MSEED_H
 | 
			
		||||
#define CAPS_MSEED_MSEED_H
 | 
			
		||||
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
#include "spclock.h"
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
/* SEED data encoding types */
 | 
			
		||||
enum SEEDDataEncodingType {
 | 
			
		||||
	DE_ASCII       = 0,
 | 
			
		||||
	DE_INT16       = 1,
 | 
			
		||||
	DE_INT32       = 3,
 | 
			
		||||
	DE_FLOAT32     = 4,
 | 
			
		||||
	DE_FLOAT64     = 5,
 | 
			
		||||
	DE_STEIM1      = 10,
 | 
			
		||||
	DE_STEIM2      = 11,
 | 
			
		||||
	DE_GEOSCOPE24  = 12,
 | 
			
		||||
	DE_GEOSCOPE163 = 13,
 | 
			
		||||
	DE_GEOSCOPE164 = 14,
 | 
			
		||||
	DE_CDSN        = 16,
 | 
			
		||||
	DE_SRO         = 30,
 | 
			
		||||
	DE_DWWSSN      = 32
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct MSEEDFormat {
 | 
			
		||||
	MSEEDFormat(const std::string &networkCode, const std::string &stationCode,
 | 
			
		||||
	            const std::string &locationCode, const std::string &channelCode,
 | 
			
		||||
	            unsigned short freqn, unsigned short freqd,
 | 
			
		||||
	            unsigned short packtype_init,
 | 
			
		||||
	            uint8_t recLen);
 | 
			
		||||
 | 
			
		||||
	template<class T>
 | 
			
		||||
	MSEEDEncoderPacket<T>
 | 
			
		||||
	get_packet(const SPClock::INT_TIME &it, int usec_correction, int timing_quality) {
 | 
			
		||||
		void *dataptr = NULL;
 | 
			
		||||
		int datalen = 0;
 | 
			
		||||
		unsigned int size = 0;
 | 
			
		||||
		MSEEDDataRecord *rec = get_buffer(it, usec_correction, timing_quality, dataptr, datalen);
 | 
			
		||||
 | 
			
		||||
		return MSEEDEncoderPacket<T>(rec, size, dataptr, datalen);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MSEEDDataRecord *get_buffer(const SPClock::INT_TIME &it, int usec_correction,
 | 
			
		||||
	                 int timing_quality,
 | 
			
		||||
	                 void *&dataptr, int &datalen);
 | 
			
		||||
 | 
			
		||||
	void updateBuffer(MSEEDDataRecord *rec, int samples, int frames);
 | 
			
		||||
 | 
			
		||||
	std::string    networkCode;
 | 
			
		||||
	std::string    stationCode;
 | 
			
		||||
	std::string    locationCode;
 | 
			
		||||
	std::string    channelCode;
 | 
			
		||||
	int            sample_rate_factor;
 | 
			
		||||
	int            sample_rate_multiplier;
 | 
			
		||||
	unsigned short packType;
 | 
			
		||||
	int            timingQuality;
 | 
			
		||||
	uint8_t        recordLength;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										44
									
								
								libs/gempa/caps/mseed/packet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								libs/gempa/caps/mseed/packet.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2012 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_PACKET_H
 | 
			
		||||
#define CAPS_MSEED_PACKET_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
template<typename T> struct MSEEDEncoderPacket {
 | 
			
		||||
	MSEEDEncoderPacket(): record(NULL), data(NULL), datalen(0) {}
 | 
			
		||||
	MSEEDEncoderPacket(MSEEDDataRecord *rec, unsigned int size_init,
 | 
			
		||||
	       void *data_init, unsigned short datalen_init)
 | 
			
		||||
	    : record(rec), data(static_cast<T*>(data_init)),
 | 
			
		||||
	      datalen(datalen_init) {}
 | 
			
		||||
	~MSEEDEncoderPacket() {}
 | 
			
		||||
 | 
			
		||||
	void reset() { record = NULL; data = NULL; datalen = 0; }
 | 
			
		||||
	bool valid() const { return record != NULL; }
 | 
			
		||||
 | 
			
		||||
	MSEEDDataRecord *record;
 | 
			
		||||
	T               *data;
 | 
			
		||||
	unsigned short   datalen;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										131
									
								
								libs/gempa/caps/mseed/slink.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								libs/gempa/caps/mseed/slink.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,131 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * slink.h
 | 
			
		||||
 *
 | 
			
		||||
 * SeedLink protocol constants
 | 
			
		||||
 *
 | 
			
		||||
 * Token from libslink
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_SLINK_H
 | 
			
		||||
#define CAPS_MSEED_SLINK_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /* Portability to the XScale (ARM) architecture
 | 
			
		||||
   * requires a packed attribute in certain places
 | 
			
		||||
   * but this only works with GCC for now.
 | 
			
		||||
   */
 | 
			
		||||
#if defined (__GNUC__)
 | 
			
		||||
  #define SLP_PACKED __attribute__ ((packed))
 | 
			
		||||
#else
 | 
			
		||||
  #define SLP_PACKED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SIGNATURE           "SL"     /* SeedLink header signature */
 | 
			
		||||
#define INFOSIGNATURE       "SLINFO" /* SeedLink INFO packet signature */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* SeedLink packet types */
 | 
			
		||||
#define SLDATA 0     /* waveform data record */
 | 
			
		||||
#define SLDET  1     /* detection record */
 | 
			
		||||
#define SLCAL  2     /* calibration record */
 | 
			
		||||
#define SLTIM  3     /* timing record */
 | 
			
		||||
#define SLMSG  4     /* message record */
 | 
			
		||||
#define SLBLK  5     /* general record */
 | 
			
		||||
#define SLNUM  6     /* used as the error indicator (same as SLCHA) */
 | 
			
		||||
#define SLCHA  6     /* for requesting channel info or detectors */
 | 
			
		||||
#define SLINF  7     /* a non-terminating XML formatted message in a miniSEED
 | 
			
		||||
                        log record, used for INFO responses */
 | 
			
		||||
#define SLINFT 8     /* a terminating XML formatted message in a miniSEED log
 | 
			
		||||
                        record, used for INFO responses */
 | 
			
		||||
#define SLKEEP 9     /* an XML formatted message in a miniSEED log
 | 
			
		||||
                        record, used for keepalive/heartbeat responses */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* SEED binary time (10 bytes) */
 | 
			
		||||
struct sl_btime_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  year;
 | 
			
		||||
  uint16_t  day;
 | 
			
		||||
  uint8_t   hour;
 | 
			
		||||
  uint8_t   min;
 | 
			
		||||
  uint8_t   sec;
 | 
			
		||||
  uint8_t   unused;
 | 
			
		||||
  uint16_t  fract;
 | 
			
		||||
} SLP_PACKED;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Fixed section data of header (48 bytes) */
 | 
			
		||||
struct sl_fsdh_s
 | 
			
		||||
{
 | 
			
		||||
  char        sequence_number[6];
 | 
			
		||||
  char        dhq_indicator;
 | 
			
		||||
  char        reserved;
 | 
			
		||||
  char        station[5];
 | 
			
		||||
  char        location[2];
 | 
			
		||||
  char        channel[3];
 | 
			
		||||
  char        network[2];
 | 
			
		||||
  struct sl_btime_s start_time;
 | 
			
		||||
  uint16_t    num_samples;
 | 
			
		||||
  int16_t     samprate_fact;
 | 
			
		||||
  int16_t     samprate_mult;
 | 
			
		||||
  uint8_t     act_flags;
 | 
			
		||||
  uint8_t     io_flags;
 | 
			
		||||
  uint8_t     dq_flags;
 | 
			
		||||
  uint8_t     num_blockettes;
 | 
			
		||||
  int32_t     time_correct;
 | 
			
		||||
  uint16_t    begin_data;
 | 
			
		||||
  uint16_t    begin_blockette;
 | 
			
		||||
} SLP_PACKED;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* 1000 Blockette (8 bytes) */
 | 
			
		||||
struct sl_blkt_1000_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  blkt_type;
 | 
			
		||||
  uint16_t  next_blkt;
 | 
			
		||||
  uint8_t   encoding;
 | 
			
		||||
  uint8_t   word_swap;
 | 
			
		||||
  uint8_t   rec_len;
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
} SLP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* 1001 Blockette (8 bytes) */
 | 
			
		||||
struct sl_blkt_1001_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  blkt_type;
 | 
			
		||||
  uint16_t  next_blkt;
 | 
			
		||||
  int8_t    timing_qual;
 | 
			
		||||
  int8_t    usec;
 | 
			
		||||
  uint8_t   reserved;
 | 
			
		||||
  int8_t    frame_cnt;
 | 
			
		||||
} SLP_PACKED;
 | 
			
		||||
 | 
			
		||||
/* Generic struct for head of blockettes */
 | 
			
		||||
struct sl_blkt_head_s
 | 
			
		||||
{
 | 
			
		||||
  uint16_t  blkt_type;
 | 
			
		||||
  uint16_t  next_blkt;
 | 
			
		||||
} SLP_PACKED;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										78
									
								
								libs/gempa/caps/mseed/spclock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								libs/gempa/caps/mseed/spclock.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * spclock.h
 | 
			
		||||
 *
 | 
			
		||||
 * Stream Processor Clock
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_SPCLOCK_H
 | 
			
		||||
#define CAPS_MSEED_SPCLOCK_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SPClock
 | 
			
		||||
  {
 | 
			
		||||
  public:
 | 
			
		||||
    typedef Gempa::CAPS::Time INT_TIME;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    INT_TIME itime;
 | 
			
		||||
    int ticks;
 | 
			
		||||
    int corr;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    const int freqn;
 | 
			
		||||
    const int freqd;
 | 
			
		||||
 | 
			
		||||
    SPClock(int freqn_init, int freqd_init): ticks(0), corr(0),
 | 
			
		||||
      freqn(freqn_init), freqd(freqd_init)
 | 
			
		||||
      {}
 | 
			
		||||
 | 
			
		||||
    void sync_time(const INT_TIME &time)
 | 
			
		||||
      {
 | 
			
		||||
        itime = time;
 | 
			
		||||
        ticks = 0;
 | 
			
		||||
        corr = 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    void tick()
 | 
			
		||||
      {
 | 
			
		||||
        ++ticks;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    INT_TIME get_time(int tick_diff) const
 | 
			
		||||
      {
 | 
			
		||||
        int64_t correctness = (double)freqd / (double)freqn * 1000000 * (ticks - tick_diff - corr);
 | 
			
		||||
        return itime + Gempa::CAPS::TimeSpan(long(correctness/1000000),long(correctness%1000000));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    int correction() const
 | 
			
		||||
      {
 | 
			
		||||
        return corr;
 | 
			
		||||
      }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // SPCLOCK_H
 | 
			
		||||
							
								
								
									
										90
									
								
								libs/gempa/caps/mseed/steim1.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								libs/gempa/caps/mseed/steim1.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
/***************************************************************************** 
 | 
			
		||||
 * steim1.h
 | 
			
		||||
 *
 | 
			
		||||
 * Steim1 encoder
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_STEIM1_H
 | 
			
		||||
#define CAPS_MSEED_STEIM1_H
 | 
			
		||||
 | 
			
		||||
#include "encoder.h"
 | 
			
		||||
#include "mseed.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
// Steim1Frame
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
 | 
			
		||||
struct Steim1Frame {
 | 
			
		||||
	u_int32_t nibble_word;
 | 
			
		||||
	u_int32_t sample_word[15];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
// Steim1Encoder
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
class Steim1Encoder: public Encoder {
 | 
			
		||||
	private:
 | 
			
		||||
		MSEEDFormat *format;
 | 
			
		||||
		int frame_count;
 | 
			
		||||
		int bp;
 | 
			
		||||
		int fp;
 | 
			
		||||
		int spw;
 | 
			
		||||
		int32_t last_sample;
 | 
			
		||||
		int32_t buf[5];
 | 
			
		||||
		u_int32_t nibble_word;
 | 
			
		||||
		MSEEDEncoderPacket<Steim1Frame> current_packet;
 | 
			
		||||
 | 
			
		||||
		void update_spw(int bp);
 | 
			
		||||
		void store(int32_t value);
 | 
			
		||||
		void init_packet();
 | 
			
		||||
		void finish_packet();
 | 
			
		||||
		void update_packet();
 | 
			
		||||
 | 
			
		||||
		MSEEDEncoderPacket<Steim1Frame> get_packet() {
 | 
			
		||||
			return format->get_packet<Steim1Frame>(_clk.get_time(bp),
 | 
			
		||||
			                                       _clk.correction(), _timingQuality);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void queue_packet(MSEEDEncoderPacket<Steim1Frame> &pckt);
 | 
			
		||||
 | 
			
		||||
		int number_of_frames(const MSEEDEncoderPacket<Steim1Frame> &packet) {
 | 
			
		||||
			return (packet.datalen >> 6);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Steim1Encoder(MSEEDFormat *format, int freqn, int freqd)
 | 
			
		||||
		    : Encoder(freqn, freqd), format(format), frame_count(0),
 | 
			
		||||
		      bp(0), fp(0), spw(4), last_sample(0), nibble_word(0) {}
 | 
			
		||||
		virtual ~Steim1Encoder();
 | 
			
		||||
		virtual void flush();
 | 
			
		||||
		virtual void push(void *value);
 | 
			
		||||
		virtual int type() const { return DE_STEIM1; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "steim1.ipp"
 | 
			
		||||
 | 
			
		||||
#endif // __STEIM1_H__
 | 
			
		||||
							
								
								
									
										184
									
								
								libs/gempa/caps/mseed/steim1.ipp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								libs/gempa/caps/mseed/steim1.ipp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,184 @@
 | 
			
		||||
/***************************************************************************** 
 | 
			
		||||
 * steim1.cc
 | 
			
		||||
 *
 | 
			
		||||
 * Steim1 encoder
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
template<typename T> Steim1Encoder<T>::~Steim1Encoder() {
 | 
			
		||||
	if ( format != NULL ) delete format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::update_spw(int bp) {
 | 
			
		||||
	int spw1 = 4;
 | 
			
		||||
 | 
			
		||||
	assert(bp < 4);
 | 
			
		||||
	if(buf[bp] < -32768 || buf[bp] > 32767) spw1 = 1;
 | 
			
		||||
	else if(buf[bp] < -128 || buf[bp] > 127) spw1 = 2;
 | 
			
		||||
	if(spw1 < spw) spw = spw1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::store(int32_t value) {
 | 
			
		||||
	assert(bp < 4);
 | 
			
		||||
	buf[bp] = value - last_sample;
 | 
			
		||||
	last_sample = value;
 | 
			
		||||
	update_spw(bp);
 | 
			
		||||
	++bp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::init_packet() {
 | 
			
		||||
	int i;
 | 
			
		||||
	int32_t begin_sample = last_sample;
 | 
			
		||||
 | 
			
		||||
	for(i = 1; i < bp; ++i) {
 | 
			
		||||
		begin_sample -= buf[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
	current_packet.data[0].sample_word[0] = htonl(begin_sample);
 | 
			
		||||
	frame_count = 0;
 | 
			
		||||
	nibble_word = 0;
 | 
			
		||||
	fp = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::finish_packet() {
 | 
			
		||||
	int i;
 | 
			
		||||
	int32_t end_sample = last_sample;
 | 
			
		||||
 | 
			
		||||
	for(i = 0; i < bp; ++i) {
 | 
			
		||||
		end_sample -= buf[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	current_packet.data[0].sample_word[1] = htonl(end_sample);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::update_packet() {
 | 
			
		||||
	unsigned int nibble = 0;
 | 
			
		||||
	u_int32_t sample_word = 0;
 | 
			
		||||
 | 
			
		||||
	assert(bp < 5);
 | 
			
		||||
 | 
			
		||||
	int used = bp;
 | 
			
		||||
 | 
			
		||||
	while(used > spw) {
 | 
			
		||||
		--used;
 | 
			
		||||
		spw = 4;
 | 
			
		||||
		for(int i = 0; i < used; ++i) update_spw(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while(used < spw) spw >>= 1;
 | 
			
		||||
 | 
			
		||||
	used = spw;
 | 
			
		||||
 | 
			
		||||
	switch(spw) {
 | 
			
		||||
		case 4:
 | 
			
		||||
			nibble = 1;
 | 
			
		||||
			sample_word = ((buf[0] & 0xff) << 24) | ((buf[1] & 0xff) << 16) |
 | 
			
		||||
			              ((buf[2] & 0xff) <<  8) | (buf[3] & 0xff);
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			nibble = 2;
 | 
			
		||||
			sample_word = ((buf[0] & 0xffff) << 16) | (buf[1] & 0xffff);
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			nibble = 3;
 | 
			
		||||
			sample_word = buf[0];
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			assert(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nibble_word |= (nibble << (30 - ((fp + 1) << 1)));
 | 
			
		||||
 | 
			
		||||
	spw = 4;
 | 
			
		||||
	for(int i = 0; i < bp - used; ++i) {
 | 
			
		||||
		buf[i] = buf[i + used];
 | 
			
		||||
		update_spw(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bp -= used;
 | 
			
		||||
	_sampleCount += used;
 | 
			
		||||
 | 
			
		||||
	current_packet.data[frame_count].nibble_word = htonl(nibble_word);
 | 
			
		||||
	current_packet.data[frame_count].sample_word[fp] = htonl(sample_word);
 | 
			
		||||
	if(++fp < 15) return;
 | 
			
		||||
 | 
			
		||||
	nibble_word = 0;
 | 
			
		||||
	fp = 0;
 | 
			
		||||
	++frame_count;
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::queue_packet(MSEEDEncoderPacket<Steim1Frame> &pckt) {
 | 
			
		||||
	format->updateBuffer(pckt.record, _sampleCount, frame_count + (fp > 0));
 | 
			
		||||
 | 
			
		||||
	Packet *packet = new Packet(DataRecordPtr(pckt.record), format->networkCode, format->stationCode,
 | 
			
		||||
	                            format->locationCode, format->channelCode);
 | 
			
		||||
	_packetQueue.push_back(PacketPtr(packet));
 | 
			
		||||
	pckt.reset();
 | 
			
		||||
	reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::push(void *value) {
 | 
			
		||||
	int32_t sample_val = *static_cast<T*>(value);
 | 
			
		||||
	store(sample_val);
 | 
			
		||||
	_clk.tick();
 | 
			
		||||
 | 
			
		||||
	while(bp >= spw) {
 | 
			
		||||
		if(!current_packet.valid()) {
 | 
			
		||||
			current_packet = get_packet();
 | 
			
		||||
			init_packet();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		update_packet();
 | 
			
		||||
		if(frame_count == number_of_frames(current_packet)) {
 | 
			
		||||
			finish_packet();
 | 
			
		||||
			queue_packet(current_packet);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim1Encoder<T>::flush() {
 | 
			
		||||
	while(bp) {
 | 
			
		||||
		if(!current_packet.valid()) {
 | 
			
		||||
			current_packet = get_packet();
 | 
			
		||||
			init_packet();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		update_packet();
 | 
			
		||||
		if(frame_count == number_of_frames(current_packet)) {
 | 
			
		||||
			finish_packet();
 | 
			
		||||
			queue_packet(current_packet);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(current_packet.valid()) {
 | 
			
		||||
		finish_packet();
 | 
			
		||||
		queue_packet(current_packet);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								libs/gempa/caps/mseed/steim2.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								libs/gempa/caps/mseed/steim2.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * steim2.h
 | 
			
		||||
 *
 | 
			
		||||
 * Steim2 encoder
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2000 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_STEIM2_H
 | 
			
		||||
#define CAPS_MSEED_STEIM2_H
 | 
			
		||||
 | 
			
		||||
#include "encoder.h"
 | 
			
		||||
#include "mseed.h"
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
// Steim2Frame
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
 | 
			
		||||
struct Steim2Frame {
 | 
			
		||||
	u_int32_t nibble_word;
 | 
			
		||||
	u_int32_t sample_word[15];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
// Steim2Encoder
 | 
			
		||||
//*****************************************************************************
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
class Steim2Encoder : public Encoder {
 | 
			
		||||
	public:
 | 
			
		||||
		Steim2Encoder(MSEEDFormat *format, int freqn, int freqd)
 | 
			
		||||
		    : Encoder(freqn, freqd), format(format), frame_count(0),
 | 
			
		||||
		  bp(0), fp(0), spw(4), last_sample(0), nibble_word(0) {
 | 
			
		||||
		}
 | 
			
		||||
		virtual ~Steim2Encoder();
 | 
			
		||||
		virtual void flush();
 | 
			
		||||
 | 
			
		||||
		virtual void push(void *value);
 | 
			
		||||
		virtual int type() const { return DE_STEIM2; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void update_spw(int bp);
 | 
			
		||||
		void store(int32_t value);
 | 
			
		||||
		void init_packet();
 | 
			
		||||
		void finish_packet();
 | 
			
		||||
		void update_packet();
 | 
			
		||||
 | 
			
		||||
		MSEEDEncoderPacket<Steim2Frame> get_packet() {
 | 
			
		||||
			return format->get_packet<Steim2Frame>(_clk.get_time(bp),
 | 
			
		||||
			                                       _clk.correction(), _timingQuality);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void queue_packet(MSEEDEncoderPacket<Steim2Frame> &pckt);
 | 
			
		||||
 | 
			
		||||
		int number_of_frames(const MSEEDEncoderPacket<Steim2Frame> &packet) {
 | 
			
		||||
			return (packet.datalen >> 6);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		MSEEDFormat *format;
 | 
			
		||||
		int frame_count;
 | 
			
		||||
		int bp;
 | 
			
		||||
		int fp;
 | 
			
		||||
		int32_t last_s;
 | 
			
		||||
		int spw;
 | 
			
		||||
		int32_t last_sample;
 | 
			
		||||
		int32_t buf[8];
 | 
			
		||||
		u_int32_t nibble_word;
 | 
			
		||||
		MSEEDEncoderPacket<Steim2Frame> current_packet;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "steim2.ipp"
 | 
			
		||||
 | 
			
		||||
#endif // __STEIM2_H__
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										241
									
								
								libs/gempa/caps/mseed/steim2.ipp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								libs/gempa/caps/mseed/steim2.ipp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,241 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * steim2.cc
 | 
			
		||||
 *
 | 
			
		||||
 * Steim2 encoder
 | 
			
		||||
 *
 | 
			
		||||
 * (c) 2004 Andres Heinloo, GFZ Potsdam
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any later
 | 
			
		||||
 * version. For more information, see http://www.gnu.org/
 | 
			
		||||
 *
 | 
			
		||||
 * ================
 | 
			
		||||
 * Change log
 | 
			
		||||
 * ===============
 | 
			
		||||
 *
 | 
			
		||||
 * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "../log.h"
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template<typename T> Steim2Encoder<T>::~Steim2Encoder() {
 | 
			
		||||
	if ( format != NULL ) delete format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::update_spw(int bp) {
 | 
			
		||||
	assert(bp < 7);
 | 
			
		||||
 | 
			
		||||
	if(buf[bp] < -536870912) {
 | 
			
		||||
		CAPS_WARNING("%s.%s.%s.%s: value %d is too large for Steim2 encoding",
 | 
			
		||||
		             format->networkCode.c_str(), format->stationCode.c_str(),
 | 
			
		||||
		             format->locationCode.c_str(), format->channelCode.c_str(),
 | 
			
		||||
		             buf[bp]);
 | 
			
		||||
		buf[bp] = -536870912;
 | 
			
		||||
		spw = 1;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(buf[bp] > 536870911) {
 | 
			
		||||
		CAPS_WARNING("%s.%s.%s.%s: value %d is too large for Steim2 encoding",
 | 
			
		||||
		             format->networkCode.c_str(), format->stationCode.c_str(),
 | 
			
		||||
		             format->locationCode.c_str(), format->channelCode.c_str(),
 | 
			
		||||
		             buf[bp]);
 | 
			
		||||
		buf[bp] = 536870911;
 | 
			
		||||
		spw = 1;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int spw1 = 7;
 | 
			
		||||
	if(buf[bp] < -16384 || buf[bp] > 16383) spw1 = 1;
 | 
			
		||||
	else if(buf[bp] < -512 || buf[bp] > 511) spw1 = 2;
 | 
			
		||||
	else if(buf[bp] < -128 || buf[bp] > 127) spw1 = 3;
 | 
			
		||||
	else if(buf[bp] < -32 || buf[bp] > 31) spw1 = 4;
 | 
			
		||||
	else if(buf[bp] < -16 || buf[bp] > 15) spw1 = 5;
 | 
			
		||||
	else if(buf[bp] < -8  || buf[bp] > 7) spw1 = 6;
 | 
			
		||||
	if(spw1 < spw) spw = spw1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::store(int32_t value) {
 | 
			
		||||
	assert(bp < 7);
 | 
			
		||||
	buf[bp] = value - last_sample;
 | 
			
		||||
	last_sample = value;
 | 
			
		||||
	update_spw(bp);
 | 
			
		||||
	++bp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::init_packet() {
 | 
			
		||||
	int i;
 | 
			
		||||
	int32_t begin_sample = last_sample;
 | 
			
		||||
 | 
			
		||||
	for(i = 1; i < bp; ++i) {
 | 
			
		||||
		begin_sample -= buf[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	reset();
 | 
			
		||||
	current_packet.data[0].sample_word[0] = htonl(begin_sample);
 | 
			
		||||
	frame_count = 0;
 | 
			
		||||
	nibble_word = 0;
 | 
			
		||||
	fp = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::finish_packet() {
 | 
			
		||||
	int i;
 | 
			
		||||
	int32_t end_sample = last_sample;
 | 
			
		||||
 | 
			
		||||
	for(i = 0; i < bp; ++i) {
 | 
			
		||||
		end_sample -= buf[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	current_packet.data[0].sample_word[1] = htonl(end_sample);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::update_packet() {
 | 
			
		||||
	unsigned int nibble = 0;
 | 
			
		||||
	u_int32_t sample_word = 0;
 | 
			
		||||
 | 
			
		||||
	assert(bp < 8);
 | 
			
		||||
 | 
			
		||||
	int used = bp;
 | 
			
		||||
 | 
			
		||||
	while(used > spw) {
 | 
			
		||||
		--used;
 | 
			
		||||
		spw = 7;
 | 
			
		||||
		for(int i = 0; i < used; ++i) update_spw(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	spw = used;
 | 
			
		||||
 | 
			
		||||
	switch(spw) {
 | 
			
		||||
		case 7:
 | 
			
		||||
			nibble = 3;
 | 
			
		||||
			sample_word = (2U << 30) | ((buf[0] & 0xf) << 24) |
 | 
			
		||||
				((buf[1] & 0xf) << 20) | ((buf[2] & 0xf) << 16) |
 | 
			
		||||
				((buf[3] & 0xf) << 12) | ((buf[4] & 0xf) << 8) |
 | 
			
		||||
				((buf[5] & 0xf) << 4) | (buf[6] & 0xf);
 | 
			
		||||
			break;
 | 
			
		||||
		case 6:
 | 
			
		||||
			nibble = 3;
 | 
			
		||||
			sample_word = (1U << 30) | ((buf[0] & 0x1f) << 25) |
 | 
			
		||||
				((buf[1] & 0x1f) << 20) | ((buf[2] & 0x1f) << 15) |
 | 
			
		||||
				((buf[3] & 0x1f) << 10) | ((buf[4] & 0x1f) << 5) |
 | 
			
		||||
				(buf[5] & 0x1f);
 | 
			
		||||
			break;
 | 
			
		||||
		case 5:
 | 
			
		||||
			nibble = 3;
 | 
			
		||||
			sample_word = ((buf[0] & 0x3f) << 24) | ((buf[1] & 0x3f) << 18) |
 | 
			
		||||
				((buf[2] & 0x3f) << 12) | ((buf[3] & 0x3f) << 6) |
 | 
			
		||||
				(buf[4] & 0x3f);
 | 
			
		||||
			break;
 | 
			
		||||
		case 4:
 | 
			
		||||
			nibble = 1;
 | 
			
		||||
			sample_word = ((buf[0] & 0xff) << 24) | ((buf[1] & 0xff) << 16) |
 | 
			
		||||
				((buf[2] & 0xff) <<  8) | (buf[3] & 0xff);
 | 
			
		||||
			break;
 | 
			
		||||
		case 3:
 | 
			
		||||
			nibble = 2;
 | 
			
		||||
			sample_word = (3U << 30) | ((buf[0] & 0x3ff) << 20) |
 | 
			
		||||
				((buf[1] & 0x3ff) << 10) | (buf[2] & 0x3ff);
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			nibble = 2;
 | 
			
		||||
			sample_word = (2U << 30) | ((buf[0] & 0x7fff) << 15) |
 | 
			
		||||
				(buf[1] & 0x7fff);
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			nibble = 2;
 | 
			
		||||
			sample_word = (1U << 30) | (buf[0] & 0x3fffffff);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			assert(0);
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nibble_word |= (nibble << (30 - ((fp + 1) << 1)));
 | 
			
		||||
 | 
			
		||||
	spw = 7;
 | 
			
		||||
	for(int i = 0; i < bp - used; ++i) {
 | 
			
		||||
		buf[i] = buf[i + used];
 | 
			
		||||
		update_spw(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bp -= used;
 | 
			
		||||
	_sampleCount += used;
 | 
			
		||||
 | 
			
		||||
	current_packet.data[frame_count].nibble_word = htonl(nibble_word);
 | 
			
		||||
	current_packet.data[frame_count].sample_word[fp] = htonl(sample_word);
 | 
			
		||||
	if(++fp < 15) return;
 | 
			
		||||
 | 
			
		||||
	nibble_word = 0;
 | 
			
		||||
	fp = 0;
 | 
			
		||||
	++frame_count;
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::queue_packet(MSEEDEncoderPacket<Steim2Frame> &pckt) {
 | 
			
		||||
	format->updateBuffer(pckt.record, _sampleCount, frame_count + (fp > 0));
 | 
			
		||||
 | 
			
		||||
	Packet *packet = new Packet(DataRecordPtr(pckt.record), format->networkCode, format->stationCode,
 | 
			
		||||
	                            format->locationCode, format->channelCode);
 | 
			
		||||
	_packetQueue.push_back(PacketPtr(packet));
 | 
			
		||||
	pckt.reset();
 | 
			
		||||
	reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::push(void *value) {
 | 
			
		||||
	int32_t sample_val = *static_cast<T*>(value);
 | 
			
		||||
	store(sample_val);
 | 
			
		||||
	_clk.tick();
 | 
			
		||||
 | 
			
		||||
	while ( bp >= spw ) {
 | 
			
		||||
		if( !current_packet.valid() ) {
 | 
			
		||||
			current_packet = get_packet();
 | 
			
		||||
			init_packet();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		update_packet();
 | 
			
		||||
		if ( frame_count == number_of_frames(current_packet) ) {
 | 
			
		||||
			finish_packet();
 | 
			
		||||
			queue_packet(current_packet);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void Steim2Encoder<T>::flush() {
 | 
			
		||||
	while ( bp ) {
 | 
			
		||||
		if ( !current_packet.valid() ) {
 | 
			
		||||
			current_packet = get_packet();
 | 
			
		||||
			init_packet();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		update_packet();
 | 
			
		||||
		if( frame_count == number_of_frames(current_packet) ) {
 | 
			
		||||
			finish_packet();
 | 
			
		||||
			queue_packet(current_packet);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( current_packet.valid() ) {
 | 
			
		||||
		finish_packet();
 | 
			
		||||
		queue_packet(current_packet);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										84
									
								
								libs/gempa/caps/mseed/uncompressed.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								libs/gempa/caps/mseed/uncompressed.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_MSEED_UNCOMPRESSED_H
 | 
			
		||||
#define CAPS_MSEED_UNCOMPRESSED_H
 | 
			
		||||
 | 
			
		||||
#include "encoder.h"
 | 
			
		||||
#include "mseed.h"
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/endianess.h>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
template<typename T> class UncompressedMSEED : public Encoder {
 | 
			
		||||
	MSEEDEncoderPacket<T> get_packet() {
 | 
			
		||||
		return _format->get_packet<T>(_clk.get_time(-_bp),
 | 
			
		||||
		                              _clk.correction(), _timingQuality);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void queue_packet(MSEEDEncoderPacket<T> &pckt) {
 | 
			
		||||
		_format->updateBuffer(pckt.record, _sampleCount, 1);
 | 
			
		||||
 | 
			
		||||
		Packet *packet = new Packet(DataRecordPtr(pckt.record), _format->networkCode, _format->stationCode,
 | 
			
		||||
		                            _format->locationCode, _format->channelCode);
 | 
			
		||||
		_packetQueue.push_back(PacketPtr(packet));
 | 
			
		||||
		pckt.reset();
 | 
			
		||||
		reset();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		UncompressedMSEED(MSEEDFormat *format, int freqn, int freqd)
 | 
			
		||||
		    : Encoder(freqn, freqd),
 | 
			
		||||
		      _format(format), _bp(0) {
 | 
			
		||||
		}
 | 
			
		||||
		virtual ~UncompressedMSEED() { if ( _format ) delete _format; }
 | 
			
		||||
		virtual void flush() {
 | 
			
		||||
			if ( _current_packet.valid() ) {
 | 
			
		||||
				queue_packet(_current_packet);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual void push(void *value) {
 | 
			
		||||
			if ( !_current_packet.valid() )
 | 
			
		||||
				_current_packet = get_packet();
 | 
			
		||||
			else if ( _sampleCount * sizeof(T) >= _current_packet.datalen ) {
 | 
			
		||||
				flush();
 | 
			
		||||
				_current_packet = get_packet();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_current_packet.data[_sampleCount] =
 | 
			
		||||
			    Gempa::CAPS::Endianess::Converter::ToBigEndian<T>(*(T*)value);
 | 
			
		||||
			++_sampleCount;
 | 
			
		||||
			++_bp;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual int type() const { return _format->packType; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		MSEEDFormat               *_format;
 | 
			
		||||
		MSEEDEncoderPacket<T>      _current_packet;
 | 
			
		||||
		int                        _bp;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // __STEIM1_H__
 | 
			
		||||
							
								
								
									
										491
									
								
								libs/gempa/caps/mseedpacket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										491
									
								
								libs/gempa/caps/mseedpacket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,491 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <libmseed.h>
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
#define LOG_SID(FUNC, format,...)\
 | 
			
		||||
do {\
 | 
			
		||||
	char n[6];\
 | 
			
		||||
	char s[6];\
 | 
			
		||||
	char c[6];\
 | 
			
		||||
	char l[6];\
 | 
			
		||||
	ms_strncpclean(n, head.network, 2);\
 | 
			
		||||
	ms_strncpclean(s, head.station, 5);\
 | 
			
		||||
	ms_strncpclean(l, head.location, 2);\
 | 
			
		||||
	ms_strncpclean(c, head.channel, 3);\
 | 
			
		||||
	FUNC("[%s.%s.%s.%s] " format, n, s, l, c, ##__VA_ARGS__);\
 | 
			
		||||
} while(0)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MSEEDDataRecord::MSEEDDataRecord() {}
 | 
			
		||||
 | 
			
		||||
const char *MSEEDDataRecord::formatName() const {
 | 
			
		||||
	return "MSEED";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool MSEEDDataRecord::readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
                                   Header &header,
 | 
			
		||||
                                   Time &startTime,
 | 
			
		||||
                                   Time &endTime) {
 | 
			
		||||
#if 1 // Set this to 1 to enable no-malloc fast MSeed meta parser
 | 
			
		||||
	fsdh_s head;
 | 
			
		||||
 | 
			
		||||
	if ( size <= 0 ) {
 | 
			
		||||
		CAPS_WARNING("read metadata: invalid size of record: %d", size);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( size < MINRECLEN || size > MAXRECLEN ) {
 | 
			
		||||
		CAPS_WARNING("read metadata: invalid MSEED record size: %d", size);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Read first 32 byte
 | 
			
		||||
	size_t read = buf.sgetn((char*)&head, sizeof(head));
 | 
			
		||||
	if ( read < sizeof(head) ) {
 | 
			
		||||
		CAPS_WARNING("read metadata: input buffer underflow: only %d/%d bytes read",
 | 
			
		||||
		             (int)read, (int)sizeof(head));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !MS_ISVALIDHEADER(((char*)&head)) ) {
 | 
			
		||||
		CAPS_WARNING("read metadata: invalid MSEED header");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool headerswapflag = false;
 | 
			
		||||
	if ( !MS_ISVALIDYEARDAY(head.start_time.year, head.start_time.day) )
 | 
			
		||||
		headerswapflag = true;
 | 
			
		||||
 | 
			
		||||
	/* Swap byte order? */
 | 
			
		||||
	if ( headerswapflag ) {
 | 
			
		||||
		MS_SWAPBTIME(&head.start_time);
 | 
			
		||||
		ms_gswap2a(&head.numsamples);
 | 
			
		||||
		ms_gswap2a(&head.samprate_fact);
 | 
			
		||||
		ms_gswap2a(&head.samprate_mult);
 | 
			
		||||
		ms_gswap4a(&head.time_correct);
 | 
			
		||||
		ms_gswap2a(&head.data_offset);
 | 
			
		||||
		ms_gswap2a(&head.blockette_offset);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	header.dataType = DT_Unknown;
 | 
			
		||||
 | 
			
		||||
	hptime_t hptime = ms_btime2hptime(&head.start_time);
 | 
			
		||||
	if ( hptime == HPTERROR ) {
 | 
			
		||||
		LOG_SID(CAPS_DEBUG, "read metadata: invalid start time");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	header.quality.ID = 0;
 | 
			
		||||
	header.quality.str[0] = head.dataquality;
 | 
			
		||||
 | 
			
		||||
	if ( head.time_correct != 0 && !(head.act_flags & 0x02) )
 | 
			
		||||
		hptime += (hptime_t)head.time_correct * (HPTMODULUS / 10000);
 | 
			
		||||
 | 
			
		||||
	// Parse blockettes
 | 
			
		||||
	uint32_t blkt_offset = head.blockette_offset;
 | 
			
		||||
	uint32_t blkt_length;
 | 
			
		||||
	uint16_t blkt_type;
 | 
			
		||||
	uint16_t next_blkt;
 | 
			
		||||
 | 
			
		||||
	if ( blkt_offset < sizeof(head) ) {
 | 
			
		||||
		LOG_SID(CAPS_DEBUG, "read metadata: blockette "
 | 
			
		||||
		        "offset points into header");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint32_t coffs = 0;
 | 
			
		||||
 | 
			
		||||
	while ( (blkt_offset != 0) && ((int)blkt_offset < size) &&
 | 
			
		||||
	        (blkt_offset < MAXRECLEN) ) {
 | 
			
		||||
		char bhead[6];
 | 
			
		||||
		int seek_ofs = blkt_offset-sizeof(head)-coffs;
 | 
			
		||||
		buf.pubseekoff(seek_ofs, std::ios_base::cur, std::ios_base::in);
 | 
			
		||||
		coffs += seek_ofs;
 | 
			
		||||
		if ( buf.sgetn(bhead, 6) != 6 ) {
 | 
			
		||||
			LOG_SID(CAPS_DEBUG, "read metadata: "
 | 
			
		||||
			        "failed to read blockette header");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		coffs += 6;
 | 
			
		||||
 | 
			
		||||
		memcpy(&blkt_type, bhead, 2);
 | 
			
		||||
		memcpy(&next_blkt, bhead+2, 2);
 | 
			
		||||
 | 
			
		||||
		if ( headerswapflag ) {
 | 
			
		||||
			ms_gswap2(&blkt_type);
 | 
			
		||||
			ms_gswap2(&next_blkt);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		blkt_length = ms_blktlen(blkt_type, bhead, headerswapflag);
 | 
			
		||||
 | 
			
		||||
		if ( blkt_length == 0 ) {
 | 
			
		||||
			LOG_SID(CAPS_DEBUG, "read metadata: "
 | 
			
		||||
			        "unknown blockette length for type %d",
 | 
			
		||||
			        blkt_type);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Make sure blockette is contained within the msrecord buffer */
 | 
			
		||||
		if ( (int)(blkt_offset - 4 + blkt_length) > size ) {
 | 
			
		||||
			LOG_SID(CAPS_DEBUG, "read metadata: blockette "
 | 
			
		||||
			        "%d extends beyond record size, truncated?",
 | 
			
		||||
			        blkt_type);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ( blkt_type == 1000 ) {
 | 
			
		||||
			switch ( (int)bhead[4] ) {
 | 
			
		||||
				case DE_ASCII:
 | 
			
		||||
					header.dataType = DT_INT8;
 | 
			
		||||
					break;
 | 
			
		||||
				case DE_INT16:
 | 
			
		||||
					header.dataType = DT_INT16;
 | 
			
		||||
					break;
 | 
			
		||||
				case DE_INT32:
 | 
			
		||||
				case DE_STEIM1:
 | 
			
		||||
				case DE_STEIM2:
 | 
			
		||||
				case DE_CDSN:
 | 
			
		||||
				case DE_DWWSSN:
 | 
			
		||||
				case DE_SRO:
 | 
			
		||||
					header.dataType = DT_INT32;
 | 
			
		||||
					break;
 | 
			
		||||
				case DE_FLOAT32:
 | 
			
		||||
					header.dataType = DT_FLOAT;
 | 
			
		||||
					break;
 | 
			
		||||
				case DE_FLOAT64:
 | 
			
		||||
					header.dataType = DT_DOUBLE;
 | 
			
		||||
					break;
 | 
			
		||||
				case DE_GEOSCOPE24:
 | 
			
		||||
				case DE_GEOSCOPE163:
 | 
			
		||||
				case DE_GEOSCOPE164:
 | 
			
		||||
					header.dataType = DT_FLOAT;
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if ( blkt_type == 1001 ) {
 | 
			
		||||
			// Add usec correction
 | 
			
		||||
			hptime += ((hptime_t)bhead[5]) * (HPTMODULUS / 1000000);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Check that the next blockette offset is beyond the current blockette */
 | 
			
		||||
		if ( next_blkt && next_blkt < (blkt_offset + blkt_length - 4) ) {
 | 
			
		||||
			LOG_SID(CAPS_DEBUG, "read metadata: offset to "
 | 
			
		||||
			        "next blockette (%d) is within current blockette "
 | 
			
		||||
			        "ending at byte %d",
 | 
			
		||||
			        blkt_type, (blkt_offset + blkt_length - 4));
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		/* Check that the offset is within record length */
 | 
			
		||||
		else if ( next_blkt && next_blkt > size ) {
 | 
			
		||||
			LOG_SID(CAPS_DEBUG, "read metadata: offset to "
 | 
			
		||||
			        "next blockette (%d) from type %d is beyond record "
 | 
			
		||||
			        "length", next_blkt, blkt_type);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			blkt_offset = next_blkt;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	startTime = Time((hptime_t)hptime/HPTMODULUS,(hptime_t)hptime%HPTMODULUS);
 | 
			
		||||
	endTime = startTime;
 | 
			
		||||
 | 
			
		||||
	if ( head.samprate_fact > 0 ) {
 | 
			
		||||
		header.samplingFrequencyNumerator = head.samprate_fact;
 | 
			
		||||
		header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		header.samplingFrequencyNumerator = 1;
 | 
			
		||||
		header.samplingFrequencyDenominator = -head.samprate_fact;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( head.samprate_mult > 0 )
 | 
			
		||||
		header.samplingFrequencyNumerator *= head.samprate_mult;
 | 
			
		||||
	else
 | 
			
		||||
		header.samplingFrequencyDenominator *= -head.samprate_mult;
 | 
			
		||||
 | 
			
		||||
	if ( header.samplingFrequencyNumerator > 0.0 && head.numsamples > 0 ) {
 | 
			
		||||
		hptime = (hptime_t)head.numsamples * HPTMODULUS * header.samplingFrequencyDenominator / header.samplingFrequencyNumerator;
 | 
			
		||||
		endTime += TimeSpan((hptime_t)hptime/HPTMODULUS,(hptime_t)hptime%HPTMODULUS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeToTimestamp(_header.samplingTime, startTime);
 | 
			
		||||
#else
 | 
			
		||||
	std::vector<char> data(size);
 | 
			
		||||
	size_t read = buf.sgetn(&data[0], data.size());
 | 
			
		||||
	if ( read != data.size() ) {
 | 
			
		||||
		CAPS_WARNING("read metadata: input buffer underflow: only %d/%d bytes read",
 | 
			
		||||
		                 (int)read, (int)data.size());
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unpackHeader(&data[0], data.size());
 | 
			
		||||
 | 
			
		||||
	header = _header;
 | 
			
		||||
	startTime = _startTime;
 | 
			
		||||
	endTime = _endTime;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const DataRecord::Header *MSEEDDataRecord::header() const {
 | 
			
		||||
	return &_header;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time MSEEDDataRecord::startTime() const {
 | 
			
		||||
	return _startTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time MSEEDDataRecord::endTime() const {
 | 
			
		||||
	return _endTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool MSEEDDataRecord::canTrim() const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool MSEEDDataRecord::canMerge() const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool MSEEDDataRecord::trim(const Time &start,
 | 
			
		||||
                           const Time &end) const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
size_t MSEEDDataRecord::dataSize(bool /*withHeader*/) const {
 | 
			
		||||
	return _data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DataRecord::ReadStatus MSEEDDataRecord::get(std::streambuf &buf, int size,
 | 
			
		||||
                                            const Time &start,
 | 
			
		||||
                                            const Time &end,
 | 
			
		||||
                                            int) {
 | 
			
		||||
	//MSRecord *ms_rec = NULL;
 | 
			
		||||
 | 
			
		||||
	if ( size <= 0 ) {
 | 
			
		||||
		CAPS_WARNING("get: invalid size of record: %d", size);
 | 
			
		||||
		return RS_Error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_data.resize(size);
 | 
			
		||||
	size_t read = buf.sgetn(&_data[0], _data.size());
 | 
			
		||||
	if ( read != _data.size() ) {
 | 
			
		||||
		CAPS_WARNING("get: input buffer underflow: only %d/%d bytes read",
 | 
			
		||||
		             (int)read, (int)_data.size());
 | 
			
		||||
		return RS_Error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	arraybuf tmp(&_data[0], size);
 | 
			
		||||
	readMetaData(tmp, size, _header, _startTime, _endTime);
 | 
			
		||||
 | 
			
		||||
	if ( start.valid() || end.valid() ) {
 | 
			
		||||
		// Out of scope?
 | 
			
		||||
		if ( end.valid() && (end <= _startTime) )
 | 
			
		||||
			return RS_AfterTimeWindow;
 | 
			
		||||
 | 
			
		||||
		if ( start.valid() && (start >= _endTime) )
 | 
			
		||||
			return RS_BeforeTimeWindow;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return RS_Complete;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	// Only unpack the header structure
 | 
			
		||||
	int state = msr_unpack(&_data[0], _data.size(), &ms_rec, 0, 0);
 | 
			
		||||
	if ( state != MS_NOERROR ) {
 | 
			
		||||
		switch ( state ) {
 | 
			
		||||
			case MS_GENERROR:
 | 
			
		||||
				CAPS_WARNING("get: generic libmseed error");
 | 
			
		||||
				break;
 | 
			
		||||
			case MS_NOTSEED:
 | 
			
		||||
				CAPS_WARNING("get: input data is not seed");
 | 
			
		||||
				break;
 | 
			
		||||
			case MS_WRONGLENGTH:
 | 
			
		||||
				CAPS_WARNING("get: length of data read was not correct");
 | 
			
		||||
				break;
 | 
			
		||||
			case MS_OUTOFRANGE:
 | 
			
		||||
				CAPS_WARNING("get: SEED record length out of range");
 | 
			
		||||
				break;
 | 
			
		||||
			case MS_UNKNOWNFORMAT:
 | 
			
		||||
				CAPS_WARNING("get: unknown data encoding format");
 | 
			
		||||
				break;
 | 
			
		||||
			case MS_STBADCOMPFLAG:
 | 
			
		||||
				CAPS_WARNING("get: invalid Steim compression flag(s)");
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		if ( ms_rec != NULL )
 | 
			
		||||
			msr_free(&ms_rec);
 | 
			
		||||
		return RS_Error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hptime_t hptime = msr_starttime(ms_rec);
 | 
			
		||||
	_startTime = Time((hptime_t)hptime/HPTMODULUS,(hptime_t)hptime%HPTMODULUS);
 | 
			
		||||
	_endTime = _startTime;
 | 
			
		||||
 | 
			
		||||
	if ( ms_rec->samprate > 0.0 && ms_rec->samplecnt > 0 ) {
 | 
			
		||||
		hptime = (hptime_t)(((double)(ms_rec->samplecnt) / ms_rec->samprate * HPTMODULUS) + 0.5);
 | 
			
		||||
		_endTime += TimeSpan((hptime_t)hptime/HPTMODULUS,(hptime_t)hptime%HPTMODULUS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_header.dataType = DT_Unknown;
 | 
			
		||||
	timeToTimestamp(_header.samplingTime, _startTime);
 | 
			
		||||
 | 
			
		||||
	if ( ms_rec->fsdh->samprate_fact > 0 ) {
 | 
			
		||||
		_header.samplingFrequencyNumerator = ms_rec->fsdh->samprate_fact;
 | 
			
		||||
		_header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		_header.samplingFrequencyNumerator = 1;
 | 
			
		||||
		_header.samplingFrequencyDenominator = -ms_rec->fsdh->samprate_fact;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( ms_rec->fsdh->samprate_mult > 0 )
 | 
			
		||||
		_header.samplingFrequencyNumerator *= ms_rec->fsdh->samprate_mult;
 | 
			
		||||
	else
 | 
			
		||||
		_header.samplingFrequencyDenominator *= -ms_rec->fsdh->samprate_mult;
 | 
			
		||||
 | 
			
		||||
	switch ( ms_rec->sampletype ) {
 | 
			
		||||
		case 'a':
 | 
			
		||||
			_header.dataType = DT_INT8;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'i':
 | 
			
		||||
			_header.dataType = DT_INT32;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'f':
 | 
			
		||||
			_header.dataType = DT_FLOAT;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'd':
 | 
			
		||||
			_header.dataType = DT_DOUBLE;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			_header.dataType = DT_Unknown;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msr_free(&ms_rec);
 | 
			
		||||
 | 
			
		||||
	if ( start.valid() || end.valid() ) {
 | 
			
		||||
		// Out of scope?
 | 
			
		||||
		if ( end.valid() && (end <= _startTime) )
 | 
			
		||||
			return RS_AfterTimeWindow;
 | 
			
		||||
 | 
			
		||||
		if ( start.valid() && (start >= _endTime) )
 | 
			
		||||
			return RS_BeforeTimeWindow;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return RS_Complete;
 | 
			
		||||
	*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool MSEEDDataRecord::put(std::streambuf &buf, bool /*withHeader*/) const {
 | 
			
		||||
	return buf.sputn(&_data[0], _data.size()) == (int)_data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MSEEDDataRecord::setData(const void *data, size_t size) {
 | 
			
		||||
	_data.resize(size);
 | 
			
		||||
	memcpy(_data.data(), data, size);
 | 
			
		||||
	unpackHeader();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MSEEDDataRecord::unpackHeader(char *data, size_t size) {
 | 
			
		||||
	// Only unpack the header structure
 | 
			
		||||
	MSRecord *ms_rec = NULL;
 | 
			
		||||
	int state = msr_unpack(data, size, &ms_rec, 0, 0);
 | 
			
		||||
	if ( state != MS_NOERROR ) {
 | 
			
		||||
		CAPS_WARNING("read metadata: read error: %d", state);
 | 
			
		||||
		if ( ms_rec != NULL )
 | 
			
		||||
			msr_free(&ms_rec);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hptime_t hptime = msr_starttime(ms_rec);
 | 
			
		||||
	_startTime = Time((hptime_t)hptime/HPTMODULUS,(hptime_t)hptime%HPTMODULUS);
 | 
			
		||||
	_endTime = _startTime;
 | 
			
		||||
 | 
			
		||||
	if ( ms_rec->samprate > 0.0 && ms_rec->samplecnt > 0 ) {
 | 
			
		||||
		hptime = (hptime_t)(((double)(ms_rec->samplecnt) / ms_rec->samprate * HPTMODULUS) + 0.5);
 | 
			
		||||
		_endTime += TimeSpan((hptime_t)hptime/HPTMODULUS,(hptime_t)hptime%HPTMODULUS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_header.dataType = DT_Unknown;
 | 
			
		||||
	timeToTimestamp(_header.samplingTime, _startTime);
 | 
			
		||||
 | 
			
		||||
	if ( ms_rec->fsdh->samprate_fact > 0 ) {
 | 
			
		||||
		_header.samplingFrequencyNumerator = ms_rec->fsdh->samprate_fact;
 | 
			
		||||
		_header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		_header.samplingFrequencyNumerator = 1;
 | 
			
		||||
		_header.samplingFrequencyDenominator = -ms_rec->fsdh->samprate_fact;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( ms_rec->fsdh->samprate_mult > 0 )
 | 
			
		||||
		_header.samplingFrequencyNumerator *= ms_rec->fsdh->samprate_mult;
 | 
			
		||||
	else
 | 
			
		||||
		_header.samplingFrequencyDenominator *= -ms_rec->fsdh->samprate_mult;
 | 
			
		||||
 | 
			
		||||
	switch ( ms_rec->sampletype ) {
 | 
			
		||||
		case 'a':
 | 
			
		||||
			_header.dataType = DT_INT8;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'i':
 | 
			
		||||
			_header.dataType = DT_INT32;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'f':
 | 
			
		||||
			_header.dataType = DT_FLOAT;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'd':
 | 
			
		||||
			_header.dataType = DT_DOUBLE;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			_header.dataType = DT_Unknown;
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msr_free(&ms_rec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								libs/gempa/caps/mseedpacket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								libs/gempa/caps/mseedpacket.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_MSEEDPACKET_H
 | 
			
		||||
#define GEMPA_CAPS_MSEEDPACKET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MSEEDDataRecord : public DataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		MSEEDDataRecord();
 | 
			
		||||
 | 
			
		||||
		virtual const char *formatName() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
		                          Header &header,
 | 
			
		||||
		                          Time &startTime,
 | 
			
		||||
		                          Time &endTime);
 | 
			
		||||
 | 
			
		||||
		virtual const Header *header() const;
 | 
			
		||||
		virtual Time startTime() const;
 | 
			
		||||
		virtual Time endTime() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool canTrim() const;
 | 
			
		||||
		virtual bool canMerge() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool trim(const Time &start,
 | 
			
		||||
		                  const Time &end) const;
 | 
			
		||||
 | 
			
		||||
		virtual size_t dataSize(bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		virtual ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		                       const Time &start = Time(),
 | 
			
		||||
		                       const Time &end = Time(),
 | 
			
		||||
		                       int maxSize = -1);
 | 
			
		||||
 | 
			
		||||
		virtual bool put(std::streambuf &buf, bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the packet type
 | 
			
		||||
		 * @return The packet type
 | 
			
		||||
		 */
 | 
			
		||||
		PacketType packetType() const { return MSEEDPacket; }
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Initializes the internal data vector from the given buffer
 | 
			
		||||
		 * @param The buffer to read the data from
 | 
			
		||||
		 * @param The buffer size
 | 
			
		||||
		 */
 | 
			
		||||
		virtual void setData(const void *data, size_t size);
 | 
			
		||||
 | 
			
		||||
		void unpackHeader() { unpackHeader(_data.data(), _data.size()); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		Header               _header;
 | 
			
		||||
 | 
			
		||||
		Time                 _startTime;
 | 
			
		||||
		Time                 _endTime;
 | 
			
		||||
 | 
			
		||||
		int                  _dataType;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void unpackHeader(char *data, size_t size);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										125
									
								
								libs/gempa/caps/packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								libs/gempa/caps/packet.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool PacketDataHeader::setUOM(const char *type) {
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if ( type != NULL ) {
 | 
			
		||||
		for ( i = 0; i < 4; ++i ) {
 | 
			
		||||
			if ( type[i] == '\0' ) break;
 | 
			
		||||
			unitOfMeasurement.str[i] = type[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Input type must not have more than 4 characters
 | 
			
		||||
		if ( i == 3 && type[i] != '\0' && type[i+1] != '\0' ) {
 | 
			
		||||
			memset(unitOfMeasurement.str, '\0', 4);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		i = 0;
 | 
			
		||||
 | 
			
		||||
	// Pad with null bytes
 | 
			
		||||
	for ( ; i < 4; ++i )
 | 
			
		||||
		unitOfMeasurement.str[i] = '\0';
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
std::string PacketDataHeader::uom(char fill) const {
 | 
			
		||||
	std::string s;
 | 
			
		||||
	for ( int i = 0; i < 4; ++i ) {
 | 
			
		||||
		if ( unitOfMeasurement.str[i] == '\0' ) break;
 | 
			
		||||
		s += unitOfMeasurement.str[i];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( s.size() < 4 && fill != '\0' ) {
 | 
			
		||||
		for ( int i = s.size(); i < 4; ++i )
 | 
			
		||||
			s += fill;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool PacketDataHeader::operator!=(const PacketDataHeader &other) const {
 | 
			
		||||
	return version != other.version ||
 | 
			
		||||
	       packetType != other.packetType ||
 | 
			
		||||
	       unitOfMeasurement.ID != other.unitOfMeasurement.ID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PacketDataHeaderV2::operator!=(const PacketDataHeaderV2 &other) const {
 | 
			
		||||
	return PacketDataHeader::operator!=(other) ||
 | 
			
		||||
	       samplingFrequencyNumerator != other.samplingFrequencyNumerator ||
 | 
			
		||||
	       samplingFrequencyDenominator != other.samplingFrequencyDenominator ||
 | 
			
		||||
	       quality.ID != other.quality.ID;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DataRecord::Header::put(std::streambuf &buf) const {
 | 
			
		||||
	Endianess::Writer put(buf);
 | 
			
		||||
	char dt = (char)dataType;
 | 
			
		||||
	put(dt);
 | 
			
		||||
 | 
			
		||||
	put(samplingTime.year);
 | 
			
		||||
	put(samplingTime.yday);
 | 
			
		||||
	put(samplingTime.hour);
 | 
			
		||||
	put(samplingTime.minute);
 | 
			
		||||
	put(samplingTime.second);
 | 
			
		||||
	put(samplingTime.usec);
 | 
			
		||||
	put(samplingFrequencyNumerator);
 | 
			
		||||
	put(samplingFrequencyDenominator);
 | 
			
		||||
 | 
			
		||||
	return put.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void DataRecord::Header::setSamplingTime(const Time &ts) {
 | 
			
		||||
	int year, yday, hour, min, sec, usec;
 | 
			
		||||
	ts.get2(&year, &yday, &hour, &min, &sec, &usec);
 | 
			
		||||
	samplingTime.year = year;
 | 
			
		||||
	samplingTime.yday = yday;
 | 
			
		||||
	samplingTime.hour = hour;
 | 
			
		||||
	samplingTime.minute = min;
 | 
			
		||||
	samplingTime.second = sec;
 | 
			
		||||
	samplingTime.usec = usec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool DataRecord::Header::compatible(const Header &other) const {
 | 
			
		||||
	return dataType == other.dataType &&
 | 
			
		||||
	       samplingFrequencyNumerator == other.samplingFrequencyNumerator &&
 | 
			
		||||
	       samplingFrequencyDenominator == other.samplingFrequencyDenominator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool DataRecord::Header::operator!=(const Header &other) const {
 | 
			
		||||
	return dataType != other.dataType ||
 | 
			
		||||
	       samplingFrequencyNumerator != other.samplingFrequencyNumerator ||
 | 
			
		||||
	       samplingFrequencyDenominator != other.samplingFrequencyDenominator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataRecord::~DataRecord() {}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										420
									
								
								libs/gempa/caps/packet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								libs/gempa/caps/packet.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,420 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_PACKET_H
 | 
			
		||||
#define GEMPA_CAPS_PACKET_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/api.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/endianess.h>
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <boost/shared_ptr.hpp>
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum PacketType {
 | 
			
		||||
	UnknownPacket = 0,
 | 
			
		||||
	RawDataPacket,
 | 
			
		||||
	MSEEDPacket,
 | 
			
		||||
	ANYPacket,
 | 
			
		||||
	RTCM2Packet,
 | 
			
		||||
	MetaDataPacket,
 | 
			
		||||
	FixedRawDataPacket,
 | 
			
		||||
	PacketTypeCount
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum DataType {
 | 
			
		||||
	DT_Unknown = 0,
 | 
			
		||||
	DT_DOUBLE  = 1,
 | 
			
		||||
	DT_FLOAT   = 2,
 | 
			
		||||
	DT_INT64   = 100,
 | 
			
		||||
	DT_INT32   = 101,
 | 
			
		||||
	DT_INT16   = 102,
 | 
			
		||||
	DT_INT8    = 103
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
union UOM {
 | 
			
		||||
	char    str[4];
 | 
			
		||||
	int32_t ID;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
union Quality {
 | 
			
		||||
	char    str[4];
 | 
			
		||||
	int32_t ID;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API TimeStamp {
 | 
			
		||||
	int16_t  year;   /* year, eg. 2003                   */
 | 
			
		||||
	uint16_t yday;   /* day of year (1-366)              */
 | 
			
		||||
	uint8_t  hour;   /* hour (0-23)                      */
 | 
			
		||||
	uint8_t  minute; /* minute (0-59)                    */
 | 
			
		||||
	uint8_t  second; /* second (0-59), 60 if leap second */
 | 
			
		||||
	uint8_t  unused; /* unused byte */
 | 
			
		||||
	int32_t  usec;   /* microsecond (0-999999)           */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API PacketDataHeader {
 | 
			
		||||
	PacketDataHeader()
 | 
			
		||||
	: version(1), packetType(UnknownPacket) {
 | 
			
		||||
		unitOfMeasurement.ID = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PacketDataHeader(uint16_t version)
 | 
			
		||||
	: version(version)
 | 
			
		||||
	, packetType(UnknownPacket) {
 | 
			
		||||
		unitOfMeasurement.ID = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint16_t   version;
 | 
			
		||||
	PacketType packetType;
 | 
			
		||||
	UOM        unitOfMeasurement;
 | 
			
		||||
 | 
			
		||||
	bool setUOM(const char *type);
 | 
			
		||||
	std::string uom(char fill = '\0') const;
 | 
			
		||||
 | 
			
		||||
	bool operator!=(const PacketDataHeader &other) const;
 | 
			
		||||
 | 
			
		||||
	int dataSize() const {
 | 
			
		||||
		return sizeof(version) + sizeof((char)packetType) +
 | 
			
		||||
		       sizeof(unitOfMeasurement.ID);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool put(std::streambuf &buf) const {
 | 
			
		||||
		Endianess::Writer put(buf);
 | 
			
		||||
 | 
			
		||||
		char type = char(packetType);
 | 
			
		||||
 | 
			
		||||
		put(version);
 | 
			
		||||
		put(type);
 | 
			
		||||
		put(unitOfMeasurement.ID);
 | 
			
		||||
 | 
			
		||||
		return put.good;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
		char type;
 | 
			
		||||
 | 
			
		||||
		get(version);
 | 
			
		||||
		get(type); packetType = PacketType(type);
 | 
			
		||||
		get(unitOfMeasurement.ID);
 | 
			
		||||
 | 
			
		||||
		return get.good;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API PacketDataHeaderV2 : PacketDataHeader {
 | 
			
		||||
	PacketDataHeaderV2()
 | 
			
		||||
	: PacketDataHeader(2)
 | 
			
		||||
	, samplingFrequencyNumerator(0)
 | 
			
		||||
	, samplingFrequencyDenominator(0) {}
 | 
			
		||||
 | 
			
		||||
	uint16_t   samplingFrequencyNumerator;
 | 
			
		||||
	uint16_t   samplingFrequencyDenominator;
 | 
			
		||||
	Quality    quality;
 | 
			
		||||
 | 
			
		||||
	bool operator!=(const PacketDataHeaderV2 &other) const;
 | 
			
		||||
 | 
			
		||||
	int dataSize() const {
 | 
			
		||||
		return PacketDataHeader::dataSize() +
 | 
			
		||||
		       sizeof(samplingFrequencyNumerator) +
 | 
			
		||||
		       sizeof(samplingFrequencyDenominator) +
 | 
			
		||||
		       sizeof(quality);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool put(std::streambuf &buf) const {
 | 
			
		||||
		Endianess::Writer put(buf);
 | 
			
		||||
 | 
			
		||||
		PacketDataHeader::put(buf);
 | 
			
		||||
 | 
			
		||||
		put(samplingFrequencyNumerator);
 | 
			
		||||
		put(samplingFrequencyDenominator);
 | 
			
		||||
		put(quality);
 | 
			
		||||
 | 
			
		||||
		return put.good;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
		PacketDataHeader::get(buf);
 | 
			
		||||
 | 
			
		||||
		get(samplingFrequencyNumerator);
 | 
			
		||||
		get(samplingFrequencyDenominator);
 | 
			
		||||
		get(quality);
 | 
			
		||||
 | 
			
		||||
		return get.good;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum StreamIDComponent {
 | 
			
		||||
	NetworkCode  = 0,
 | 
			
		||||
	StationCode  = 1,
 | 
			
		||||
	LocationCode = 2,
 | 
			
		||||
	ChannelCode  = 3,
 | 
			
		||||
	StreamIDComponentSize
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API PacketHeaderV1 {
 | 
			
		||||
	uint8_t          SIDSize[4]; /* number of bytes of stream ID components */
 | 
			
		||||
	uint16_t         size;   /* number of data bytes */
 | 
			
		||||
 | 
			
		||||
	bool put(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Writer put(buf);
 | 
			
		||||
		for ( int i = 0; i < 4; ++i )
 | 
			
		||||
			put(SIDSize[i]);
 | 
			
		||||
 | 
			
		||||
		put(size);
 | 
			
		||||
 | 
			
		||||
		return put.good;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t dataSize() const {
 | 
			
		||||
		return sizeof(uint8_t) * 4  + sizeof(size);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API PacketHeaderV2 {
 | 
			
		||||
	uint8_t          SIDSize[4]; /* number of bytes of stream ID components */
 | 
			
		||||
	uint32_t         size;   /* number of data bytes */
 | 
			
		||||
 | 
			
		||||
	bool put(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Writer put(buf);
 | 
			
		||||
		for ( int i = 0; i < 4; ++i )
 | 
			
		||||
			put(SIDSize[i]);
 | 
			
		||||
 | 
			
		||||
		put(size);
 | 
			
		||||
 | 
			
		||||
		return put.good;
 | 
			
		||||
	}
 | 
			
		||||
	size_t dataSize() const {
 | 
			
		||||
		return sizeof(uint8_t) * 4  + sizeof(size);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API ResponseHeader {
 | 
			
		||||
	uint16_t id;
 | 
			
		||||
	int32_t  size;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
		get(id);
 | 
			
		||||
		get(size);
 | 
			
		||||
 | 
			
		||||
		return get.good;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API DataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef std::vector<char> Buffer;
 | 
			
		||||
 | 
			
		||||
		struct Header {
 | 
			
		||||
			DataType   dataType{DT_Unknown};
 | 
			
		||||
			TimeStamp  samplingTime;
 | 
			
		||||
			uint16_t   samplingFrequencyNumerator;
 | 
			
		||||
			uint16_t   samplingFrequencyDenominator;
 | 
			
		||||
			Quality    quality{};
 | 
			
		||||
 | 
			
		||||
			Header() = default;
 | 
			
		||||
 | 
			
		||||
			bool get(std::streambuf &buf) {
 | 
			
		||||
				Endianess::Reader get(buf);
 | 
			
		||||
				char dt;
 | 
			
		||||
				get(dt);
 | 
			
		||||
				dataType = (DataType)dt;
 | 
			
		||||
				quality.ID = 0; // Quality is not yet part of the header stream
 | 
			
		||||
 | 
			
		||||
				get(samplingTime.year);
 | 
			
		||||
				get(samplingTime.yday);
 | 
			
		||||
				get(samplingTime.hour);
 | 
			
		||||
				get(samplingTime.minute);
 | 
			
		||||
				get(samplingTime.second);
 | 
			
		||||
				get(samplingTime.usec);
 | 
			
		||||
				get(samplingFrequencyNumerator);
 | 
			
		||||
				get(samplingFrequencyDenominator);
 | 
			
		||||
 | 
			
		||||
				return get.good;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool put(std::streambuf &buf) const;
 | 
			
		||||
 | 
			
		||||
			int dataSize() const {
 | 
			
		||||
				return sizeof(samplingTime.year) +
 | 
			
		||||
				       sizeof(samplingTime.yday) +
 | 
			
		||||
				       sizeof(samplingTime.hour) +
 | 
			
		||||
				       sizeof(samplingTime.minute) +
 | 
			
		||||
				       sizeof(samplingTime.second) +
 | 
			
		||||
				       sizeof(samplingTime.usec) +
 | 
			
		||||
				       sizeof(samplingFrequencyNumerator) +
 | 
			
		||||
				       sizeof(samplingFrequencyDenominator) +
 | 
			
		||||
				       sizeof(char);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool compatible(const Header &other) const;
 | 
			
		||||
			bool operator!=(const Header &other) const;
 | 
			
		||||
 | 
			
		||||
			void setSamplingTime(const Time ×tamp);
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		enum ReadStatusCode {
 | 
			
		||||
			RS_Error = 0,
 | 
			
		||||
			RS_Complete = 1,
 | 
			
		||||
			RS_Partial = 2,
 | 
			
		||||
			RS_BeforeTimeWindow = 3,
 | 
			
		||||
			RS_AfterTimeWindow = 4,
 | 
			
		||||
			RS_Max
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		class ReadStatus {
 | 
			
		||||
			public:
 | 
			
		||||
				ReadStatus() {}
 | 
			
		||||
				ReadStatus(ReadStatusCode code) : _code(code) {}
 | 
			
		||||
				ReadStatus(const ReadStatus &other) : _code(other._code) {}
 | 
			
		||||
 | 
			
		||||
			public:
 | 
			
		||||
				ReadStatus &operator=(const ReadStatus &other) { _code = other._code; return *this; }
 | 
			
		||||
				operator ReadStatusCode() const { return _code; }
 | 
			
		||||
 | 
			
		||||
			private:
 | 
			
		||||
				operator bool() { return _code != RS_Error; }
 | 
			
		||||
 | 
			
		||||
			private:
 | 
			
		||||
				ReadStatusCode _code;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		virtual ~DataRecord();
 | 
			
		||||
 | 
			
		||||
		virtual const char *formatName() const = 0;
 | 
			
		||||
 | 
			
		||||
		virtual bool readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
		                          Header &header,
 | 
			
		||||
		                          Time &startTime, Time &endTime) = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns if data trimming is supported
 | 
			
		||||
		virtual bool canTrim() const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns if data merging is possible without modifying
 | 
			
		||||
		//! preceding data
 | 
			
		||||
		virtual bool canMerge() const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Trims a record to start and end time. Trimming
 | 
			
		||||
		//! should not modify any data but give access to trimmed
 | 
			
		||||
		//! start and end times and the resulting data size. The trimming
 | 
			
		||||
		//! also influences writing the record to a stream.
 | 
			
		||||
		//! Trimming requires the resulting start time being greater
 | 
			
		||||
		//! or equal than the requested start time.
 | 
			
		||||
		//! (Un)Trimming to the original record is semantically
 | 
			
		||||
		//! equal to passing an invalid start and end time.
 | 
			
		||||
		//! It returns true if trimming has been done or false
 | 
			
		||||
		//! if an error occured or trimming is not supported.
 | 
			
		||||
		virtual bool trim(const Time &start, const Time &end) const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns the data size in bytes if the current state would
 | 
			
		||||
		//! be written to a stream. Trimming has also to be taken into
 | 
			
		||||
		//! account while calculating the size.
 | 
			
		||||
		virtual size_t dataSize(bool withHeader = true) const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Reads the packet from a streambuf and trims the data
 | 
			
		||||
		//! if possible to start and end. If maxBytes is greater
 | 
			
		||||
		//! than 0 then the record should not use more than this
 | 
			
		||||
		//! size of memory (in bytes). If not the complete record
 | 
			
		||||
		//! has been read, RS_Partial must be returned, RS_Complete
 | 
			
		||||
		//! otherwise.
 | 
			
		||||
		virtual ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		                       const Time &start = Time(), const Time &end = Time(),
 | 
			
		||||
		                       int maxBytes = -1) = 0;
 | 
			
		||||
 | 
			
		||||
		//! writes the packet to a streambuf and trims the data
 | 
			
		||||
		//! if possible to start and end
 | 
			
		||||
		virtual bool put(std::streambuf &buf, bool withHeader = true) const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns the meta information of the data if supported
 | 
			
		||||
		virtual const Header *header() const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns the start time of the record
 | 
			
		||||
		virtual Time startTime() const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns the end time of the record
 | 
			
		||||
		virtual Time endTime() const = 0;
 | 
			
		||||
 | 
			
		||||
		//! Returns the packet type of the record
 | 
			
		||||
		virtual PacketType packetType() const = 0;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the data vector to be filled by the caller
 | 
			
		||||
		 * @return The pointer to the internal buffer
 | 
			
		||||
		 */
 | 
			
		||||
		virtual Buffer *buffer() { return &_data; }
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns pointer to raw data. If the record
 | 
			
		||||
		 * is compressed it will be uncompressed
 | 
			
		||||
		 * @return The pointer to the raw data
 | 
			
		||||
		 */
 | 
			
		||||
		virtual Buffer *data() { return &_data; }
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		Buffer _data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef boost::shared_ptr<DataRecord> DataRecordPtr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct RawPacket {
 | 
			
		||||
	PacketDataHeader  header;
 | 
			
		||||
	std::string       SID[4];
 | 
			
		||||
	std::vector<char> data;
 | 
			
		||||
	DataRecord       *record;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MetaPacket {
 | 
			
		||||
	std::string        SID[4];
 | 
			
		||||
	PacketDataHeader   packetDataHeader;
 | 
			
		||||
	DataRecord        *record;
 | 
			
		||||
	DataRecord::Header recordHeader;
 | 
			
		||||
	Time               startTime;
 | 
			
		||||
	Time               endTime;
 | 
			
		||||
	Time               timestamp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1120
									
								
								libs/gempa/caps/plugin.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1120
									
								
								libs/gempa/caps/plugin.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										324
									
								
								libs/gempa/caps/plugin.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								libs/gempa/caps/plugin.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,324 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_PLUGIN_H
 | 
			
		||||
#define GEMPA_CAPS_PLUGIN_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
// Enable/disable journal 
 | 
			
		||||
#define CAPS_FEATURES_JOURNAL     1
 | 
			
		||||
// Enable/disable backfilling of packets
 | 
			
		||||
#define CAPS_FEATURES_BACKFILLING 1
 | 
			
		||||
#define CAPS_FEATURES_SSL         1
 | 
			
		||||
 | 
			
		||||
// Supportted CAPS packets
 | 
			
		||||
#define CAPS_FEATURES_ANY         1
 | 
			
		||||
#define CAPS_FEATURES_MSEED       1
 | 
			
		||||
#define CAPS_FEATURES_RAW         1
 | 
			
		||||
#define CAPS_FEATURES_RTCM2       1
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "encoderfactory.h"
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
#include <gempa/caps/socket.h>
 | 
			
		||||
#include <gempa/caps/version.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/pluginpacket.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/function.hpp>
 | 
			
		||||
#include <boost/shared_ptr.hpp>
 | 
			
		||||
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <list>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API Plugin {
 | 
			
		||||
	public:
 | 
			
		||||
		enum Status {
 | 
			
		||||
			Success,
 | 
			
		||||
			PacketSize,        /* Packet is bigger than the buffer size */
 | 
			
		||||
			PacketLoss,        /* The other end didn't acknowledge
 | 
			
		||||
			                      transmitted data after some time */
 | 
			
		||||
			PacketNotValid,    /* Read meta data failed*/
 | 
			
		||||
			PacketNotSupported,
 | 
			
		||||
			MaxFutureEndTimeExceeded
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct Stats {
 | 
			
		||||
			Stats() : maxBytesBuffered(0) {}
 | 
			
		||||
			size_t maxBytesBuffered;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		typedef std::vector<char>                       Buffer;
 | 
			
		||||
		typedef boost::shared_ptr<Buffer>               BufferPtr;
 | 
			
		||||
 | 
			
		||||
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
 | 
			
		||||
		typedef std::list<PacketPtr>                    BackfillingBuffer;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		struct StreamState {
 | 
			
		||||
			Time              lastEndTime;
 | 
			
		||||
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
 | 
			
		||||
			Time              lastCommitEndTime;
 | 
			
		||||
			BackfillingBuffer backfillingBuffer;
 | 
			
		||||
#endif
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		typedef std::map<std::string, StreamState>      StreamStates;
 | 
			
		||||
 | 
			
		||||
		typedef boost::function<void (const std::string &, const CAPS::Time &,
 | 
			
		||||
		                              const CAPS::Time &)> PacketAckFunc;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Plugin(const std::string &name, const std::string &options = "",
 | 
			
		||||
		       const std::string &description = "");
 | 
			
		||||
		~Plugin();
 | 
			
		||||
 | 
			
		||||
		void close();
 | 
			
		||||
		void quit();
 | 
			
		||||
 | 
			
		||||
		void enableLogging();
 | 
			
		||||
 | 
			
		||||
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
 | 
			
		||||
		void setBackfillingBufferSize(int secs) { _backfillingBufferSize = secs; }
 | 
			
		||||
		int backfillingBufferSize() const { return _backfillingBufferSize; }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns whether the plugin has been
 | 
			
		||||
		 *  requested to quit or not.
 | 
			
		||||
		 * @return True, if the plugin has been requested to quit.
 | 
			
		||||
		 */
 | 
			
		||||
		bool isExitRequested() {
 | 
			
		||||
			return _isExitRequested;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the stat object
 | 
			
		||||
		 * @return The stat object
 | 
			
		||||
		 */
 | 
			
		||||
		const Stats& stats() const {
 | 
			
		||||
			return _stats;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Resets the max bytes buffered counter
 | 
			
		||||
		 */
 | 
			
		||||
		void resetMaxBytesBuffered() {
 | 
			
		||||
			_stats.maxBytesBuffered = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the encoder factory used to created encoders for packet
 | 
			
		||||
		 *        encoding, e.g. miniSEED.
 | 
			
		||||
		 * @param factory The ownership of the factory goes to the plugin and
 | 
			
		||||
		 *        will be deleted if necessary.
 | 
			
		||||
		 */
 | 
			
		||||
		void setEncoderFactory(EncoderFactory *factory);
 | 
			
		||||
 | 
			
		||||
		void setHost(const std::string &host) { _host = host; }
 | 
			
		||||
		const std::string &host() const { return _host; }
 | 
			
		||||
 | 
			
		||||
		void setPort(unsigned short port) { _port = port; }
 | 
			
		||||
		unsigned short port() const { return _port; }
 | 
			
		||||
 | 
			
		||||
		void setBufferSize(size_t bufferSize) { _bufferSize = bufferSize; }
 | 
			
		||||
		size_t bufferSize() const { return _bufferSize; }
 | 
			
		||||
 | 
			
		||||
		//! Enables SSL feature
 | 
			
		||||
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
 | 
			
		||||
		void setSSLEnabled(bool enable) { _useSSL = enable; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets username and password
 | 
			
		||||
		 * @param user The username
 | 
			
		||||
		 * @param password The password
 | 
			
		||||
		 */
 | 
			
		||||
		void setCredentials(const std::string &user, const std::string &password) {
 | 
			
		||||
			_user = user;
 | 
			
		||||
			_password = password;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the maximum allowed relative end time for packets. If
 | 
			
		||||
		 * the packet end time is greater than the current time plus this
 | 
			
		||||
		 * value the packet will be discarded. By default this value is
 | 
			
		||||
		 * set to 120 seconds.
 | 
			
		||||
		 * @param time The time span
 | 
			
		||||
		 */
 | 
			
		||||
		void setMaxFutureEndTime(const TimeSpan &span) {
 | 
			
		||||
			_maxFutureEndTime = span;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void setPacketAckFunc(const PacketAckFunc &func) { _packetAckFunc = func; }
 | 
			
		||||
 | 
			
		||||
		void setSendTimeout(int timeout) {
 | 
			
		||||
			_sendTimeout = timeout;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void setTimeouts(int ack, int lastAck) {
 | 
			
		||||
			_ackTimeout = ack;
 | 
			
		||||
			_lastAckTimeout = lastAck;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void setTimeouts(int ack, int lastAck, int send) {
 | 
			
		||||
			_ackTimeout = ack;
 | 
			
		||||
			_lastAckTimeout = lastAck;
 | 
			
		||||
			_sendTimeout = send;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
 | 
			
		||||
		bool readJournal();
 | 
			
		||||
		void setJournal(const std::string &filename) { _journalFile = filename; }
 | 
			
		||||
		void setFlushInterval(int interval) { _flushInterval = interval; }
 | 
			
		||||
 | 
			
		||||
		const StreamStates &streamStates() const { return _states; }
 | 
			
		||||
		bool writeJournal();
 | 
			
		||||
		bool writeJournal(std::ostream &ostream);
 | 
			
		||||
#endif
 | 
			
		||||
		Status push(const std::string &net, const std::string &sta,
 | 
			
		||||
		            const std::string &loc, const std::string &cha,
 | 
			
		||||
		            DataRecordPtr rec, const std::string &uom,
 | 
			
		||||
		            int timingQuality = -1);
 | 
			
		||||
 | 
			
		||||
		Status push(const std::string &net, const std::string &sta,
 | 
			
		||||
		            const std::string &loc, const std::string &cha,
 | 
			
		||||
		            const Time &stime,
 | 
			
		||||
		            uint16_t numerator, uint16_t denominator,
 | 
			
		||||
		            const std::string &uom,
 | 
			
		||||
		            void *data, size_t count,
 | 
			
		||||
		            DataType dt, int timingQuality = -1);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Sends given data as any packet. Before sending the data will be 
 | 
			
		||||
		 * copied into an internal buffer. We introduced this method
 | 
			
		||||
		 * to simplify the creation of the python wrappers.
 | 
			
		||||
		 */
 | 
			
		||||
#if !defined(CAPS_FEATURES_ANY) || CAPS_FEATURES_ANY
 | 
			
		||||
		Status push(const std::string &net, const std::string &sta,
 | 
			
		||||
		            const std::string &loc, const std::string &cha,
 | 
			
		||||
		            const Time &stime, uint16_t numerator,
 | 
			
		||||
		            uint16_t denominator, const std::string &format,
 | 
			
		||||
		            char *data, size_t count);
 | 
			
		||||
 | 
			
		||||
		Status push(const std::string &net, const std::string &sta,
 | 
			
		||||
		            const std::string &loc, const std::string &cha,
 | 
			
		||||
		            const Time &stime, uint16_t numerator,
 | 
			
		||||
		            uint16_t denominator, const std::string &format,
 | 
			
		||||
		            const std::string &data);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		const char *version() {
 | 
			
		||||
			return LIB_CAPS_VERSION_NAME;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		typedef std::deque<PacketPtr> PacketBuffer;
 | 
			
		||||
		typedef boost::shared_ptr<Encoder> EncoderPtr;
 | 
			
		||||
 | 
			
		||||
		struct EncoderItem {
 | 
			
		||||
			EncoderItem() : dataType(DT_Unknown) {}
 | 
			
		||||
			EncoderPtr        encoder;
 | 
			
		||||
			DataType          dataType;
 | 
			
		||||
		};
 | 
			
		||||
		typedef std::map<std::string, EncoderItem> EncoderItems;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		bool connect();
 | 
			
		||||
		void disconnect();
 | 
			
		||||
		bool isConnected() const;
 | 
			
		||||
		Encoder* getEncoder(PacketPtr packet);
 | 
			
		||||
		bool readResponse(unsigned int sec = 0);
 | 
			
		||||
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
 | 
			
		||||
		bool readJournal(std::istream &istream);
 | 
			
		||||
		void updateJournal();
 | 
			
		||||
#endif
 | 
			
		||||
		void sendBye();
 | 
			
		||||
		bool commitPacket(PacketPtr packet);
 | 
			
		||||
		bool encodePacket(PacketPtr packet);
 | 
			
		||||
		bool sendPacket(Packet *packet);
 | 
			
		||||
		void serializePacket(Packet *packet);
 | 
			
		||||
		void tryFlushBackfillingBuffer(StreamState &state);
 | 
			
		||||
		void trimBackfillingBuffer(StreamState &state);
 | 
			
		||||
		bool flush();
 | 
			
		||||
		void flushEncoders();
 | 
			
		||||
		bool send(char *data, int len, int timeout = 60);
 | 
			
		||||
		void wait();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		SocketPtr                 _socket;
 | 
			
		||||
		std::string               _name;
 | 
			
		||||
		std::string               _options;
 | 
			
		||||
		std::string               _description;
 | 
			
		||||
		size_t                    _bufferSize;
 | 
			
		||||
		StreamStates              _states;
 | 
			
		||||
		PacketBuffer              _packetBuffer;
 | 
			
		||||
		bool                      _packetBufferDirty;
 | 
			
		||||
		size_t                    _bytesBuffered;
 | 
			
		||||
		std::string               _host;
 | 
			
		||||
		unsigned short            _port;
 | 
			
		||||
		char                      _responseBuf[512];
 | 
			
		||||
		int                       _responseBufIdx;
 | 
			
		||||
		fd_set                    _readFDs;
 | 
			
		||||
		fd_set                    _writeFDs;
 | 
			
		||||
		int                       _sendTimeout;
 | 
			
		||||
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
 | 
			
		||||
		std::string               _journalFile;
 | 
			
		||||
		bool                      _journalDirty;
 | 
			
		||||
		Time                      _lastWrite;
 | 
			
		||||
		int                       _flushInterval;
 | 
			
		||||
#endif
 | 
			
		||||
		bool                      _isExitRequested;
 | 
			
		||||
		bool                      _closed;
 | 
			
		||||
		bool                      _wasConnected;
 | 
			
		||||
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
 | 
			
		||||
		int                       _backfillingBufferSize;
 | 
			
		||||
#endif
 | 
			
		||||
		int                       _ackTimeout;
 | 
			
		||||
		int                       _lastAckTimeout;
 | 
			
		||||
 | 
			
		||||
		EncoderFactory           *_encoderFactory;
 | 
			
		||||
		EncoderItems              _encoderItems;
 | 
			
		||||
 | 
			
		||||
		PacketAckFunc             _packetAckFunc;
 | 
			
		||||
 | 
			
		||||
		std::string               _user;
 | 
			
		||||
		std::string               _password;
 | 
			
		||||
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
 | 
			
		||||
		bool                      _useSSL;
 | 
			
		||||
#endif
 | 
			
		||||
		Stats                     _stats;
 | 
			
		||||
		TimeSpan                  _maxFutureEndTime;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef boost::shared_ptr<Plugin> PluginPtr;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										383
									
								
								libs/gempa/caps/pluginapplication.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										383
									
								
								libs/gempa/caps/pluginapplication.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,383 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2015 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_COMPONENT PluginApplication
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/pluginapplication.h>
 | 
			
		||||
#include <gempa/caps/encoderfactory.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <seiscomp3/core/system.h>
 | 
			
		||||
#include <seiscomp3/logging/log.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/algorithm/string.hpp>
 | 
			
		||||
 | 
			
		||||
#ifdef SC_GEMPA_SEATTLE
 | 
			
		||||
#include <seiscomp3/system/environment.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <seiscomp3/config/environment.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
namespace sc = Seiscomp::Core;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
#ifdef SEISCOMP_LOG_VA
 | 
			
		||||
#define LOG_CAPS_CHANNEL(out, fmt) \
 | 
			
		||||
	va_list ap;\
 | 
			
		||||
	va_start(ap, fmt);\
 | 
			
		||||
	out(fmt, ap);\
 | 
			
		||||
	va_end(ap)
 | 
			
		||||
#else
 | 
			
		||||
#define LOG_CAPS_CHANNEL(out, fmt) \
 | 
			
		||||
	va_list ap;\
 | 
			
		||||
	va_start(ap, fmt);\
 | 
			
		||||
	fprintf(stderr, #out"  "); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n");\
 | 
			
		||||
	va_end(ap)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void LogError(const char *fmt, ...) {
 | 
			
		||||
	LOG_CAPS_CHANNEL(SEISCOMP_VERROR, fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LogWarning(const char *fmt, ...) {
 | 
			
		||||
	LOG_CAPS_CHANNEL(SEISCOMP_VWARNING, fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LogNotice(const char *fmt, ...) {
 | 
			
		||||
	LOG_CAPS_CHANNEL(SEISCOMP_VNOTICE, fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LogInfo(const char *fmt, ...) {
 | 
			
		||||
	LOG_CAPS_CHANNEL(SEISCOMP_VINFO, fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LogDebug(const char *fmt, ...) {
 | 
			
		||||
	LOG_CAPS_CHANNEL(SEISCOMP_VDEBUG, fmt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const size_t MIN_BUFFER_SIZE = 1024*16;
 | 
			
		||||
const uint16_t DEFAULT_PORT = 18003;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
PluginApplication::PluginApplication(int argc, char **argv, const string &desc)
 | 
			
		||||
: Seiscomp::Client::StreamApplication(argc, argv)
 | 
			
		||||
, _plugin(Plugin(desc)) {
 | 
			
		||||
	_bufferSize = 1 << 20;
 | 
			
		||||
	_backfillingBufferSize = 180;
 | 
			
		||||
	_flushInterval = 10;
 | 
			
		||||
	_ackTimeout = 60;
 | 
			
		||||
	_lastAckTimeout = 5;
 | 
			
		||||
	_sendTimeout = 60;
 | 
			
		||||
	_logStatus = false;
 | 
			
		||||
	_statusFlushInterval = 10;
 | 
			
		||||
 | 
			
		||||
	_host = "localhost";
 | 
			
		||||
	_port = DEFAULT_PORT;
 | 
			
		||||
 | 
			
		||||
	_strAddr = "localhost:" + sc::toString(DEFAULT_PORT);
 | 
			
		||||
 | 
			
		||||
	SC_FS_DECLARE_PATH(path, "@ROOTDIR@/var/run/" + SCCoreApp->name() + "/journal");
 | 
			
		||||
	_journalFile = path.string();
 | 
			
		||||
 | 
			
		||||
	_mseedEnabled = false;
 | 
			
		||||
	_mseedEncoding = Steim2;
 | 
			
		||||
	_mseedRecordLength = 9;
 | 
			
		||||
	_strMseedEncoding = "Steim2";
 | 
			
		||||
	_maxFutureEndTime = 120;
 | 
			
		||||
 | 
			
		||||
	// By default we disable the acquisition autostart because not all plugins
 | 
			
		||||
	// require this feature. It must be enabled explicitly if required.
 | 
			
		||||
	setAutoAcquisitionStart(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PluginApplication::createCommandLineDescription() {
 | 
			
		||||
	Seiscomp::Client::StreamApplication::createCommandLineDescription();
 | 
			
		||||
	commandline().addGroup("Output");
 | 
			
		||||
	commandline().addOption("Output", "addr,a", "Data output address, format is [HOST:PORT]", &_strAddr);
 | 
			
		||||
	commandline().addOption("Output", "buffer-size,b", "Size (bytes) of the packet buffer", &_bufferSize);
 | 
			
		||||
	commandline().addOption("Output", "backfilling",
 | 
			
		||||
	                        "Enable backfilling for out-of-order records. The backfilling buffer size is "
 | 
			
		||||
	                        "in seconds", &_backfillingBufferSize);
 | 
			
		||||
	commandline().addOption("Output", "mseed", "Enable on-the-fly MiniSeed "
 | 
			
		||||
	                        "encoding. If the encoder does not support the input"
 | 
			
		||||
	                        "type of a packet it will be forwarded. Re encoding of"
 | 
			
		||||
	                        "MiniSEED packets is not supported.");
 | 
			
		||||
	commandline().addOption("Output", "encoding", "MiniSEED encoding to use. (Uncompressed, Steim1 or Steim2)",
 | 
			
		||||
	                        &_strMseedEncoding);
 | 
			
		||||
	commandline().addOption("Output", "rec-len", "MiniSEED record length expressed as a power of 2."
 | 
			
		||||
	                                             "A 512 byte record would be 9.",
 | 
			
		||||
	                        &_mseedRecordLength);
 | 
			
		||||
	commandline().addOption("Output", "max-future-endtime", "Maximum allowed relative end time for packets. If "
 | 
			
		||||
	                        "the packet end time is greater than the current time plus this "
 | 
			
		||||
	                        "value the packet will be discarded. By default this value is set to 120 seconds.",
 | 
			
		||||
	                        &_maxFutureEndTime);
 | 
			
		||||
	commandline().addGroup("Journal");
 | 
			
		||||
	commandline().addOption("Journal", "journal,j",
 | 
			
		||||
	                        "File to store stream states. Use an empty string to disable this feature.", &_journalFile);
 | 
			
		||||
	commandline().addOption("Journal", "flush",
 | 
			
		||||
	                        "Flush stream states every n seconds to disk", &_flushInterval);
 | 
			
		||||
	commandline().addOption("Journal", "wait-for-ack",
 | 
			
		||||
	                        "Wait when a sync has been forced, up to n seconds", &_ackTimeout);
 | 
			
		||||
	commandline().addOption("Journal", "wait-for-last-ack,w",
 | 
			
		||||
	                        "Wait on shutdown to receive acknownledgement messages, up to n seconds", &_lastAckTimeout);
 | 
			
		||||
 | 
			
		||||
	commandline().addGroup("Status");
 | 
			
		||||
	commandline().addOption("Status", "status-log", "Log information status "
 | 
			
		||||
	                        "information e.g. max bytes buffered");
 | 
			
		||||
	commandline().addOption("Status", "status-flush", "Flush status every n "
 | 
			
		||||
	                        "seconds to disk",
 | 
			
		||||
	                        &_statusFlushInterval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PluginApplication::done() {
 | 
			
		||||
	LogInfo("Statistics of transmitted data:\n"
 | 
			
		||||
	        "  records   : %d\n"
 | 
			
		||||
	        "  samples   : %d\n"
 | 
			
		||||
	        "  gaps      : %d\n"
 | 
			
		||||
	        "  start time: %s\n"
 | 
			
		||||
	        "  end time  : %s\n"
 | 
			
		||||
	        "  files     : %d",
 | 
			
		||||
	        _stats.records, _stats.samples, _stats.gaps,
 | 
			
		||||
	        _stats.startTime.valid()?_stats.startTime.iso().c_str():"",
 | 
			
		||||
	        _stats.endTime.valid()?_stats.endTime.iso().c_str():"",
 | 
			
		||||
	        _stats.files);
 | 
			
		||||
 | 
			
		||||
	Seiscomp::Client::StreamApplication::done();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PluginApplication::exit(int returnCode) {
 | 
			
		||||
	Seiscomp::Client::StreamApplication::exit(returnCode);
 | 
			
		||||
 | 
			
		||||
	_plugin.quit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PluginApplication::handleTimeout() {
 | 
			
		||||
	sc::Time time = sc::Time::GMT().toLocalTime();
 | 
			
		||||
 | 
			
		||||
	Plugin::Stats stats = _plugin.stats();
 | 
			
		||||
	_statusFile.stream() << time.toString("%Y/%m/%d %T") << " " << stats.maxBytesBuffered << endl;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	_plugin.resetMaxBytesBuffered();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PluginApplication::init() {
 | 
			
		||||
	if ( !Seiscomp::Client::StreamApplication::init() ) return false;
 | 
			
		||||
 | 
			
		||||
	// Setup log handlers
 | 
			
		||||
	Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_ERROR, LogError);
 | 
			
		||||
	Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_WARNING, LogWarning);
 | 
			
		||||
	Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_NOTICE, LogNotice);
 | 
			
		||||
	Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_INFO, LogInfo);
 | 
			
		||||
	Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_DEBUG, LogDebug);
 | 
			
		||||
 | 
			
		||||
	_plugin.setHost(_host);
 | 
			
		||||
	_plugin.setPort(_port);
 | 
			
		||||
	_plugin.setBufferSize(_bufferSize);
 | 
			
		||||
	_plugin.setFlushInterval(_flushInterval);
 | 
			
		||||
	_plugin.setTimeouts(_ackTimeout, _lastAckTimeout, _sendTimeout);
 | 
			
		||||
	_plugin.setMaxFutureEndTime(_maxFutureEndTime);
 | 
			
		||||
 | 
			
		||||
	if ( _mseedEnabled ) {
 | 
			
		||||
		MSEEDEncoderFactory *factory = nullptr;
 | 
			
		||||
		if ( _mseedEncoding == Uncompressed ) {
 | 
			
		||||
			SEISCOMP_INFO("Output stream encoding set to MiniSEED/Uncompressed");
 | 
			
		||||
			factory = new IdentityEncoderFactory();
 | 
			
		||||
			_plugin.setEncoderFactory(factory);
 | 
			
		||||
		}
 | 
			
		||||
		else if ( _mseedEncoding == Steim1 ) {
 | 
			
		||||
			SEISCOMP_INFO("Output stream encoding set to MiniSEED/Steim1");
 | 
			
		||||
			factory = new Steim1EncoderFactory();
 | 
			
		||||
			_plugin.setEncoderFactory(factory);
 | 
			
		||||
		}
 | 
			
		||||
		if ( _mseedEncoding == Steim2 ) {
 | 
			
		||||
			SEISCOMP_INFO("Output stream encoding set to MiniSEED/Steim2");
 | 
			
		||||
			factory = new Steim2EncoderFactory();
 | 
			
		||||
			_plugin.setEncoderFactory(factory);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			SEISCOMP_ERROR("Unsupported MiniSEED encoding");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ( !factory->setRecordLength(_mseedRecordLength) ) {
 | 
			
		||||
			SEISCOMP_ERROR("%s", factory->errorString().c_str());
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		SEISCOMP_INFO("MiniSEED encoding is disabled.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( _backfillingBufferSize > 0 ) {
 | 
			
		||||
		_plugin.setBackfillingBufferSize(_backfillingBufferSize);
 | 
			
		||||
		LogInfo("Backfilling buffer size set to %d", _backfillingBufferSize);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !_journalFile.empty() ) {
 | 
			
		||||
		_journalFile = Seiscomp::Environment::Instance()->absolutePath(_journalFile);
 | 
			
		||||
		// Recover states
 | 
			
		||||
		LogInfo("Reading journal from %s", _journalFile.c_str());
 | 
			
		||||
		_plugin.setJournal(_journalFile);
 | 
			
		||||
		_plugin.readJournal();
 | 
			
		||||
		LogInfo("Recovered %d streams", (int)_plugin.streamStates().size());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( _logStatus ) {
 | 
			
		||||
		string filename =  Seiscomp::Environment::Instance()->logDir() + "/" + SCCoreApp->name() + "-stats.log";
 | 
			
		||||
		if ( !_statusFile.open(filename.c_str()) ) {
 | 
			
		||||
			LogError("Could not open status file %s.", filename.c_str());
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		enableTimer(_statusFlushInterval);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PluginApplication::initConfiguration() {
 | 
			
		||||
	if ( !Seiscomp::Client::StreamApplication::initConfiguration() ) return false;
 | 
			
		||||
 | 
			
		||||
	try { _host = configGetString("output.host"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _port = configGetInt("output.port"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _sendTimeout = configGetInt("output.timeout"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		string addr = configGetString("output.addr");
 | 
			
		||||
		if ( !splitAddress(_host, _port, addr, DEFAULT_PORT) ) {
 | 
			
		||||
			SEISCOMP_ERROR("%s: Invalid CAPS address, format is [HOST:PORT]",
 | 
			
		||||
			               addr.c_str());
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch ( ... ) {}
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		_mseedEnabled = configGetBool("output.mseed.enable");
 | 
			
		||||
	}
 | 
			
		||||
	catch ( ... ) {}
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		int length = configGetInt("output.mseed.recordLength");
 | 
			
		||||
		if ( length < 0 ) {
 | 
			
		||||
			SEISCOMP_ERROR("'output.mseed.recordLength' must be a positive integer");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_mseedRecordLength = uint(length);
 | 
			
		||||
	}
 | 
			
		||||
	catch ( ... ) {}
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		string str = configGetString("output.mseed.encoding");
 | 
			
		||||
		if ( !fromString(_mseedEncoding, str)) return false;
 | 
			
		||||
	}
 | 
			
		||||
	catch ( ... ) {}
 | 
			
		||||
 | 
			
		||||
	try { _bufferSize = configGetInt("output.bufferSize"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _backfillingBufferSize = configGetInt("output.backfillingBufferSize"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _journalFile = configGetString("journal.file"); }
 | 
			
		||||
	catch ( ... ) {}
 | 
			
		||||
 | 
			
		||||
	try { _flushInterval = configGetInt("journal.flush"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _ackTimeout = configGetInt("journal.waitForAck"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _lastAckTimeout = configGetInt("journal.waitForLastAck"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _logStatus = configGetBool("statusLog.enable"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	try { _statusFlushInterval = configGetInt("statusLog.flush"); }
 | 
			
		||||
	catch ( ... ) {}
 | 
			
		||||
 | 
			
		||||
	try { _maxFutureEndTime= configGetInt("output.maxFutureEndTime"); }
 | 
			
		||||
	catch ( ... ) { }
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PluginApplication::validateParameters() {
 | 
			
		||||
	if ( !Seiscomp::Client::StreamApplication::validateParameters() ) return false;
 | 
			
		||||
 | 
			
		||||
	if ( commandline().hasOption("mseed") ) {
 | 
			
		||||
		_mseedEnabled = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( commandline().hasOption("status-log") ) {
 | 
			
		||||
		_logStatus = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( commandline().hasOption("encoding") ) {
 | 
			
		||||
		if ( !fromString(_mseedEncoding, _strMseedEncoding)) return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( _bufferSize < MIN_BUFFER_SIZE ) {
 | 
			
		||||
		SEISCOMP_ERROR("The plugin buffer size must be at least %ld bytes.",
 | 
			
		||||
		               MIN_BUFFER_SIZE);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( commandline().hasOption("addr") ) {
 | 
			
		||||
		if ( !splitAddress(_host, _port, _strAddr, DEFAULT_PORT) ) {
 | 
			
		||||
			SEISCOMP_ERROR("%s: Invalid CAPS address, format is [HOST:PORT]",
 | 
			
		||||
			               _strAddr.c_str());
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PluginApplication::fromString(MseedEncoding &enc, string str) {
 | 
			
		||||
	boost::to_lower(str);
 | 
			
		||||
	if( str == "uncompressed" )
 | 
			
		||||
		enc = Uncompressed;
 | 
			
		||||
	else if ( str == "steim1" )
 | 
			
		||||
		enc = Steim1;
 | 
			
		||||
	else if ( str == "steim2" )
 | 
			
		||||
		enc = Steim2;
 | 
			
		||||
	else {
 | 
			
		||||
		SEISCOMP_ERROR("Unsupported encoding %s", str.c_str());
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								libs/gempa/caps/pluginapplication.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								libs/gempa/caps/pluginapplication.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2015 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_PLUGINAPPLICATION_H
 | 
			
		||||
#define GEMPA_CAPS_PLUGINAPPLICATION_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/api.h>
 | 
			
		||||
#include <gempa/caps/plugin.h>
 | 
			
		||||
 | 
			
		||||
#include <seiscomp3/client/streamapplication.h>
 | 
			
		||||
#include <seiscomp3/logging/filerotator.h>
 | 
			
		||||
#include <seiscomp3/utils/timer.h>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API PluginApplication : public Seiscomp::Client::StreamApplication {
 | 
			
		||||
	public:
 | 
			
		||||
		PluginApplication(int argc, char **argv,
 | 
			
		||||
		                  const std::string &desc = "");
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Adds common plugin commandline options.
 | 
			
		||||
		*/
 | 
			
		||||
		virtual void createCommandLineDescription();
 | 
			
		||||
 | 
			
		||||
		virtual void done();
 | 
			
		||||
 | 
			
		||||
		virtual void exit(int returnCode);
 | 
			
		||||
 | 
			
		||||
		virtual void handleRecord(Seiscomp::Record *record) {}
 | 
			
		||||
		virtual void handleTimeout();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Initialization method.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool init();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Reads common plugin configuration options.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool initConfiguration();
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Validates command line parameters.
 | 
			
		||||
		 */
 | 
			
		||||
		virtual bool validateParameters();
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		struct Statistics {
 | 
			
		||||
			uint32_t records;
 | 
			
		||||
			uint32_t samples;
 | 
			
		||||
			Time     startTime;
 | 
			
		||||
			Time     endTime;
 | 
			
		||||
			uint32_t gaps;
 | 
			
		||||
			uint32_t files;
 | 
			
		||||
 | 
			
		||||
			Statistics() : records(0), samples(0), gaps(0), files(0) {}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		enum MseedEncoding {Uncompressed, Steim1, Steim2};
 | 
			
		||||
 | 
			
		||||
		bool fromString(MseedEncoding &enc, std::string str);
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		class FileRotator : public Seiscomp::Logging::FileRotatorOutput {
 | 
			
		||||
			public:
 | 
			
		||||
				std::ofstream& stream() { return _stream; }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		Plugin                    _plugin;
 | 
			
		||||
		std::string               _host;
 | 
			
		||||
		ushort                    _port;
 | 
			
		||||
		std::string               _strAddr;
 | 
			
		||||
		size_t                    _bufferSize;
 | 
			
		||||
		size_t                    _backfillingBufferSize;
 | 
			
		||||
		bool                      _mseed;
 | 
			
		||||
		std::string               _journalFile;
 | 
			
		||||
		int                       _flushInterval;
 | 
			
		||||
		int                       _ackTimeout;
 | 
			
		||||
		int                       _lastAckTimeout;
 | 
			
		||||
		int                       _sendTimeout;
 | 
			
		||||
		int                       _maxFutureEndTime;
 | 
			
		||||
		Statistics                _stats;
 | 
			
		||||
		bool                      _mseedEnabled;
 | 
			
		||||
		MseedEncoding             _mseedEncoding;
 | 
			
		||||
		uint                      _mseedRecordLength;
 | 
			
		||||
		std::string               _strMseedEncoding;
 | 
			
		||||
		std::string               _strPacketType;
 | 
			
		||||
		Seiscomp::Util::Timer     _timer;
 | 
			
		||||
		FileRotator               _statusFile;
 | 
			
		||||
		bool                      _logStatus;
 | 
			
		||||
		uint                      _statusFlushInterval;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										69
									
								
								libs/gempa/caps/pluginpacket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								libs/gempa/caps/pluginpacket.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2016 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_PLUGINPACKET_H
 | 
			
		||||
#define GEMPA_CAPS_PLUGINPACKET_H
 | 
			
		||||
 | 
			
		||||
#include "mseed/encoder.h"
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
struct Packet {
 | 
			
		||||
	Packet() : timingQuality(-1) {}
 | 
			
		||||
	Packet(DataRecordPtr rec,
 | 
			
		||||
	       const std::string &networkCode, const std::string &stationCode,
 | 
			
		||||
	       const std::string &locationCode, const std::string &channelCode)
 | 
			
		||||
	: record(rec), networkCode(networkCode), stationCode(stationCode),
 | 
			
		||||
	  locationCode(locationCode), channelCode(channelCode), timingQuality(-1) {
 | 
			
		||||
		streamID = networkCode + "." + stationCode + "." +
 | 
			
		||||
		           locationCode + "." + channelCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Packet* clone() {
 | 
			
		||||
		Packet *packet = new Packet(record, networkCode, stationCode,
 | 
			
		||||
		                            locationCode, channelCode);
 | 
			
		||||
		packet->buffer = buffer;
 | 
			
		||||
		packet->dt_us = dt_us;
 | 
			
		||||
		packet->streamID = streamID;
 | 
			
		||||
 | 
			
		||||
		return packet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typedef std::vector<char>                       Buffer;
 | 
			
		||||
	typedef boost::shared_ptr<Buffer>               BufferPtr;
 | 
			
		||||
 | 
			
		||||
	BufferPtr            buffer;    // PacketDataHeader, PacketHeader[V1|V2], Data
 | 
			
		||||
	DataRecordPtr        record;
 | 
			
		||||
	std::string          networkCode;
 | 
			
		||||
	std::string          stationCode;
 | 
			
		||||
	std::string          locationCode;
 | 
			
		||||
	std::string          channelCode;
 | 
			
		||||
	std::string          streamID;
 | 
			
		||||
	DataType             dataType;
 | 
			
		||||
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
 | 
			
		||||
	int64_t              dt_us;     // Length of one sample in microseconds
 | 
			
		||||
#endif
 | 
			
		||||
	std::string          uom;
 | 
			
		||||
	int                  timingQuality;
 | 
			
		||||
	size_t size() const { return buffer->size(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef boost::shared_ptr<Packet>   PacketPtr;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										418
									
								
								libs/gempa/caps/rawpacket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										418
									
								
								libs/gempa/caps/rawpacket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,418 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/rawpacket.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/riff.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
#define DT2STR(prefix, dt)             \
 | 
			
		||||
	do {                               \
 | 
			
		||||
		switch ( dt ) {                \
 | 
			
		||||
			case DT_DOUBLE:            \
 | 
			
		||||
				return prefix"DOUBLE"; \
 | 
			
		||||
			case DT_FLOAT:             \
 | 
			
		||||
				return prefix"FLOAT";  \
 | 
			
		||||
			case DT_INT64:             \
 | 
			
		||||
				return prefix"INT64";  \
 | 
			
		||||
			case DT_INT32:             \
 | 
			
		||||
				return prefix"INT32";  \
 | 
			
		||||
			case DT_INT16:             \
 | 
			
		||||
				return prefix"INT16";  \
 | 
			
		||||
			case DT_INT8:              \
 | 
			
		||||
				return prefix"INT8";   \
 | 
			
		||||
			default:                   \
 | 
			
		||||
				break;                 \
 | 
			
		||||
		}                              \
 | 
			
		||||
	}                                  \
 | 
			
		||||
	while (0);                         \
 | 
			
		||||
	return prefix"UNKWN";              \
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
inline int sizeOf(DataType dt) {
 | 
			
		||||
	switch ( dt ) {
 | 
			
		||||
		case DT_DOUBLE:
 | 
			
		||||
			return sizeof(double);
 | 
			
		||||
		case DT_FLOAT:
 | 
			
		||||
			return sizeof(float);
 | 
			
		||||
		case DT_INT64:
 | 
			
		||||
			return sizeof(int64_t);
 | 
			
		||||
		case DT_INT32:
 | 
			
		||||
			return sizeof(int32_t);
 | 
			
		||||
		case DT_INT16:
 | 
			
		||||
			return sizeof(int16_t);
 | 
			
		||||
		case DT_INT8:
 | 
			
		||||
			return sizeof(int8_t);
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Time getEndTime(const Time &stime, size_t count, const DataRecord::Header &header) {
 | 
			
		||||
	if ( header.samplingFrequencyNumerator == 0 ||
 | 
			
		||||
	     header.samplingFrequencyDenominator == 0 ) return stime;
 | 
			
		||||
 | 
			
		||||
	return stime + samplesToTimeSpan(header, count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RawDataRecord::RawDataRecord() : _dataOfs(0), _dataSize(0), _dirty(false) {}
 | 
			
		||||
 | 
			
		||||
const char *RawDataRecord::formatName() const {
 | 
			
		||||
	DT2STR("RAW/", _currentHeader.dataType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RawDataRecord::readMetaData(std::streambuf &buf, int size, Header &header,
 | 
			
		||||
                                 Time &startTime, Time &endTime) {
 | 
			
		||||
	if ( !header.get(buf) ) return false;
 | 
			
		||||
 | 
			
		||||
	_currentHeader.dataType = header.dataType;
 | 
			
		||||
 | 
			
		||||
	size -= header.dataSize();
 | 
			
		||||
	int dtsize = sizeOf(header.dataType);
 | 
			
		||||
	if ( dtsize == 0 ) {
 | 
			
		||||
		CAPS_WARNING("unknown data type: %d", header.dataType);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int count = size / dtsize;
 | 
			
		||||
 | 
			
		||||
	startTime = timestampToTime(header.samplingTime);
 | 
			
		||||
	endTime = getEndTime(startTime, count, header);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RawDataRecord::setHeader(const Header &header) {
 | 
			
		||||
	_header = header;
 | 
			
		||||
	_currentHeader = _header;
 | 
			
		||||
	_startTime = timestampToTime(_header.samplingTime);
 | 
			
		||||
	_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DataRecord::Header *RawDataRecord::header() const {
 | 
			
		||||
	return &_header;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RawDataRecord::setDataType(DataType dt) {
 | 
			
		||||
	_header.dataType = dt;
 | 
			
		||||
	_currentHeader = _header;
 | 
			
		||||
	_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RawDataRecord::setStartTime(const Time &time) {
 | 
			
		||||
	_header.setSamplingTime(time);
 | 
			
		||||
	_currentHeader = _header;
 | 
			
		||||
	_startTime = time;
 | 
			
		||||
	_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RawDataRecord::setSamplingFrequency(uint16_t numerator, uint16_t denominator) {
 | 
			
		||||
	_header.samplingFrequencyNumerator = numerator;
 | 
			
		||||
	_header.samplingFrequencyDenominator = denominator;
 | 
			
		||||
	_currentHeader = _header;
 | 
			
		||||
	_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Time RawDataRecord::startTime() const {
 | 
			
		||||
	return _startTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Time RawDataRecord::endTime() const {
 | 
			
		||||
	if ( _dirty ) {
 | 
			
		||||
		_endTime = getEndTime(_startTime, _data.size() / sizeOf(_header.dataType), _header);
 | 
			
		||||
		_dirty = false;
 | 
			
		||||
	}
 | 
			
		||||
	return _endTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RawDataRecord::canTrim() const {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RawDataRecord::canMerge() const {
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RawDataRecord::trim(const Time &start, const Time &end) const {
 | 
			
		||||
	if ( _header.samplingFrequencyNumerator <= 0 || _header.samplingFrequencyDenominator <= 0 )
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	// If the start time is behind the end time return false
 | 
			
		||||
	if ( start > end ) return false;
 | 
			
		||||
 | 
			
		||||
	// Initialize original values
 | 
			
		||||
	int dataTypeSize = sizeOf(_header.dataType);
 | 
			
		||||
	_dataSize = _data.size();
 | 
			
		||||
	if ( dataTypeSize == 0 ) {
 | 
			
		||||
		CAPS_WARNING("unknown data type: %d", _header.dataType);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_startTime = timestampToTime(_header.samplingTime);
 | 
			
		||||
	_endTime = _startTime + samplesToTimeSpan(_header, _dataSize / dataTypeSize);
 | 
			
		||||
	_dirty = false;
 | 
			
		||||
 | 
			
		||||
	// Trim front
 | 
			
		||||
	if ( start > _startTime ) {
 | 
			
		||||
		TimeSpan ofs = start - _startTime;
 | 
			
		||||
		int sampleOfs = timeSpanToSamplesCeil(_header, ofs);
 | 
			
		||||
		_dataOfs = sampleOfs * dataTypeSize;
 | 
			
		||||
		if ( _dataSize > _dataOfs )
 | 
			
		||||
			_dataSize -= _dataOfs;
 | 
			
		||||
		else
 | 
			
		||||
			_dataSize = 0;
 | 
			
		||||
		_startTime += samplesToTimeSpan(_header, sampleOfs);
 | 
			
		||||
		timeToTimestamp(_currentHeader.samplingTime, _startTime);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		_currentHeader.samplingTime = _header.samplingTime;
 | 
			
		||||
		_dataOfs = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Trim back
 | 
			
		||||
	if ( end.valid() && (end < _endTime) ) {
 | 
			
		||||
		TimeSpan ofs = _endTime - end;
 | 
			
		||||
		int sampleOfs = timeSpanToSamplesFloor(_header, ofs);
 | 
			
		||||
		_dataSize -= sampleOfs * dataTypeSize;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size_t sampleCount = _dataSize / dataTypeSize;
 | 
			
		||||
	_endTime = _startTime + samplesToTimeSpan(_currentHeader, sampleCount);
 | 
			
		||||
 | 
			
		||||
	CAPS_DEBUG("trimmed: %s ~ %s: %d samples",
 | 
			
		||||
	            _startTime.iso().c_str(),
 | 
			
		||||
	            _endTime.iso().c_str(), (int)sampleCount);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t RawDataRecord::dataSize(bool withHeader) const {
 | 
			
		||||
	if ( withHeader )
 | 
			
		||||
		return _dataSize + _header.dataSize();
 | 
			
		||||
	else
 | 
			
		||||
		return _dataSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataRecord::ReadStatus RawDataRecord::get(streambuf &buf, int size,
 | 
			
		||||
                                          const Time &start, const Time &end,
 | 
			
		||||
                                          int maxBytes) {
 | 
			
		||||
	size -= _header.dataSize();
 | 
			
		||||
	if ( size < 0 ) return RS_Error;
 | 
			
		||||
	if ( !_header.get(buf) ) {
 | 
			
		||||
		CAPS_WARNING("invalid raw header");
 | 
			
		||||
		return RS_Error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return getData(buf, size, start, end, maxBytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
 | 
			
		||||
                                              const Time &start, const Time &end,
 | 
			
		||||
                                              int maxBytes) {
 | 
			
		||||
	bool partial = false;
 | 
			
		||||
	int sampleOfs;
 | 
			
		||||
	int sampleCount;
 | 
			
		||||
	int dataTypeSize = sizeOf(_header.dataType);
 | 
			
		||||
	if ( dataTypeSize == 0 ) {
 | 
			
		||||
		CAPS_WARNING("unknown data type: %d", _header.dataType);
 | 
			
		||||
		return RS_Error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sampleCount = size / dataTypeSize;
 | 
			
		||||
 | 
			
		||||
	_startTime = timestampToTime(_header.samplingTime);
 | 
			
		||||
 | 
			
		||||
	if ( _header.samplingFrequencyDenominator > 0 &&
 | 
			
		||||
	     _header.samplingFrequencyNumerator > 0 )
 | 
			
		||||
		_endTime = _startTime + samplesToTimeSpan(_header, sampleCount);
 | 
			
		||||
	else
 | 
			
		||||
		_endTime = Time();
 | 
			
		||||
 | 
			
		||||
	if ( (start.valid() || end.valid()) && _endTime.valid() ) {
 | 
			
		||||
		// Out of bounds?
 | 
			
		||||
		if ( end.valid() && (end <= _startTime) )
 | 
			
		||||
			return RS_AfterTimeWindow;
 | 
			
		||||
 | 
			
		||||
		if ( start.valid() && (start >= _endTime) )
 | 
			
		||||
			return RS_BeforeTimeWindow;
 | 
			
		||||
 | 
			
		||||
		// Trim packet front
 | 
			
		||||
		if ( _startTime < start ) {
 | 
			
		||||
			TimeSpan ofs = start - _startTime;
 | 
			
		||||
			sampleOfs = timeSpanToSamplesCeil(_header, ofs);
 | 
			
		||||
			sampleCount -= sampleOfs;
 | 
			
		||||
			CAPS_DEBUG("Triming packet start: added offset of %d samples", sampleOfs);
 | 
			
		||||
			_startTime += samplesToTimeSpan(_header, sampleOfs);
 | 
			
		||||
			// Update header timespan
 | 
			
		||||
			timeToTimestamp(_header.samplingTime, _startTime);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			sampleOfs = 0;
 | 
			
		||||
 | 
			
		||||
		if ( maxBytes > 0 ) {
 | 
			
		||||
			int maxSamples = maxBytes / dataTypeSize;
 | 
			
		||||
			// Here we need to clip the complete dataset and only
 | 
			
		||||
			// return a partial record
 | 
			
		||||
			if ( maxSamples < sampleCount ) {
 | 
			
		||||
				CAPS_DEBUG("Clip %d available samples to %d", sampleCount, maxSamples);
 | 
			
		||||
				_endTime -= samplesToTimeSpan(_header, sampleCount-maxSamples);
 | 
			
		||||
				sampleCount = maxSamples;
 | 
			
		||||
				partial = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Trim back
 | 
			
		||||
		if ( end.valid() && (end < _endTime) ) {
 | 
			
		||||
			TimeSpan ofs = _endTime - end;
 | 
			
		||||
			int trimEnd = timeSpanToSamplesFloor(_header, ofs);
 | 
			
		||||
			sampleCount -= trimEnd;
 | 
			
		||||
			_endTime = _startTime + samplesToTimeSpan(_header, sampleCount);
 | 
			
		||||
			CAPS_DEBUG("Triming packet end: added offset of %d samples", trimEnd);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		sampleOfs = 0;
 | 
			
		||||
 | 
			
		||||
	if ( sampleCount == 0 ) return RS_Error;
 | 
			
		||||
 | 
			
		||||
	_currentHeader = _header;
 | 
			
		||||
 | 
			
		||||
	switch ( _header.dataType ) {
 | 
			
		||||
		case DT_INT8:
 | 
			
		||||
		{
 | 
			
		||||
			// Stay with little endian data
 | 
			
		||||
			RIFF::VectorChunk<1,false> dataChunk(_data, sampleOfs, sampleCount);
 | 
			
		||||
			if ( !dataChunk.get(buf, size) ) return RS_Error;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case DT_INT16:
 | 
			
		||||
		{
 | 
			
		||||
			// Stay with little endian data
 | 
			
		||||
			RIFF::VectorChunk<2,false> dataChunk(_data, sampleOfs, sampleCount);
 | 
			
		||||
			if ( !dataChunk.get(buf, size) ) return RS_Error;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case DT_INT32:
 | 
			
		||||
		case DT_FLOAT:
 | 
			
		||||
		{
 | 
			
		||||
			// Stay with little endian data
 | 
			
		||||
			RIFF::VectorChunk<4,false> dataChunk(_data, sampleOfs, sampleCount);
 | 
			
		||||
			if ( !dataChunk.get(buf, size) ) return RS_Error;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case DT_INT64:
 | 
			
		||||
		case DT_DOUBLE:
 | 
			
		||||
		{
 | 
			
		||||
			// Stay with little endian data
 | 
			
		||||
			RIFF::VectorChunk<8,false> dataChunk(_data, sampleOfs, sampleCount);
 | 
			
		||||
			if ( !dataChunk.get(buf, size) ) return RS_Error;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			CAPS_ERROR("THIS SHOULD NEVER HAPPEN: ignored invalid data with type %d",
 | 
			
		||||
			           _header.dataType);
 | 
			
		||||
			return RS_Error;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	// Initialize indicies
 | 
			
		||||
	_dataOfs = 0;
 | 
			
		||||
	_dataSize = _data.size();
 | 
			
		||||
 | 
			
		||||
	return partial?RS_Partial:RS_Complete;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RawDataRecord::put(std::streambuf &buf, bool withHeader) const {
 | 
			
		||||
	if ( withHeader && !_currentHeader.put(buf) ) return false;
 | 
			
		||||
 | 
			
		||||
	switch ( _header.dataType ) {
 | 
			
		||||
		case DT_INT8:
 | 
			
		||||
		{
 | 
			
		||||
			// Data is already in little endian
 | 
			
		||||
			RIFF::CPtrChunk<1,false> dataChunk(&_data[_dataOfs], _dataSize);
 | 
			
		||||
			if ( !dataChunk.put(buf) )
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case DT_INT16:
 | 
			
		||||
		{
 | 
			
		||||
			// Data is already in little endian
 | 
			
		||||
			RIFF::CPtrChunk<2,false> dataChunk(&_data[_dataOfs], _dataSize);
 | 
			
		||||
			if ( !dataChunk.put(buf) )
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case DT_INT32:
 | 
			
		||||
		case DT_FLOAT:
 | 
			
		||||
		{
 | 
			
		||||
			// Data is already in little endian
 | 
			
		||||
			RIFF::CPtrChunk<4,false> dataChunk(&_data[_dataOfs], _dataSize);
 | 
			
		||||
			if ( !dataChunk.put(buf) )
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case DT_INT64:
 | 
			
		||||
		case DT_DOUBLE:
 | 
			
		||||
		{
 | 
			
		||||
			// Data is already in little endian
 | 
			
		||||
			RIFF::CPtrChunk<8,false> dataChunk(&_data[_dataOfs], _dataSize);
 | 
			
		||||
			if ( !dataChunk.put(buf) )
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			CAPS_ERROR("THIS SHOULD NEVER HAPPEN: ignored invalid data with type %d",
 | 
			
		||||
			           _header.dataType);
 | 
			
		||||
			return false;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RawDataRecord::setBuffer(const void *data, size_t size) {
 | 
			
		||||
	_data.resize(size);
 | 
			
		||||
	_dataSize = size;
 | 
			
		||||
	_dataOfs = 0;
 | 
			
		||||
	memcpy(_data.data(), data, size);
 | 
			
		||||
	_dirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *FixedRawDataRecord::formatName() const {
 | 
			
		||||
	DT2STR("FIXEDRAW/", _currentHeader.dataType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										237
									
								
								libs/gempa/caps/rawpacket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								libs/gempa/caps/rawpacket.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,237 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_RAWPACKET_H
 | 
			
		||||
#define GEMPA_CAPS_RAWPACKET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API RawResponseHeader {
 | 
			
		||||
	int64_t timeSeconds;
 | 
			
		||||
	int32_t timeMicroSeconds;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &buf) {
 | 
			
		||||
		Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
		get(timeSeconds);
 | 
			
		||||
		get(timeMicroSeconds);
 | 
			
		||||
 | 
			
		||||
		return get.good;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int dataSize() const {
 | 
			
		||||
		return sizeof(timeSeconds) + sizeof(timeMicroSeconds);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RawDataRecord : public DataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		RawDataRecord();
 | 
			
		||||
 | 
			
		||||
		const char *formatName() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Reads metadata from data record header
 | 
			
		||||
		 * @param The streambuf object
 | 
			
		||||
		 * @param The size of the data record in bytes
 | 
			
		||||
		 * @param The data record header object
 | 
			
		||||
		 * @param The startTime
 | 
			
		||||
		 * @param The endTime
 | 
			
		||||
		 */
 | 
			
		||||
		bool readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
		                  Header &header,
 | 
			
		||||
		                  Time &startTime, Time &endTime);
 | 
			
		||||
 | 
			
		||||
		void setHeader(const Header &header);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the meta information of the data if supported
 | 
			
		||||
		 * @return The data record header
 | 
			
		||||
		 */
 | 
			
		||||
		const Header *header() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the start time of the record
 | 
			
		||||
		 * @return The start time
 | 
			
		||||
		 */
 | 
			
		||||
		Time startTime() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the end time of the record
 | 
			
		||||
		 * @return The end time
 | 
			
		||||
		 */
 | 
			
		||||
		Time endTime() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief canTrim checks if data trimming is possible
 | 
			
		||||
		 * without modifying preceding data
 | 
			
		||||
		 * @return True, if data trimming is possible
 | 
			
		||||
		 */
 | 
			
		||||
		bool canTrim() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief canMerge checks if data merging is possible
 | 
			
		||||
		 * without modifying preceding data
 | 
			
		||||
		 * @return True, if data merging is possible
 | 
			
		||||
		 */
 | 
			
		||||
		bool canMerge() const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief  Trims a record to start and end time. Trimming
 | 
			
		||||
		 * should not modify any data but give access to trimmed
 | 
			
		||||
		 * start and end times and the resulting data size. The trimming
 | 
			
		||||
		 * also influences writing the record to a stream.
 | 
			
		||||
		 * Trimming requires the resulting start time being greater
 | 
			
		||||
		 * or equal than the requested start time.
 | 
			
		||||
		 * (Un)Trimming to the original record is semantically
 | 
			
		||||
		 * equal to passing an invalid start and end time.
 | 
			
		||||
		 * @param start The requested start time
 | 
			
		||||
		 * @param end The requested end time
 | 
			
		||||
		 * @return  It returns true if trimming has been done or false
 | 
			
		||||
		 * if an error occured or trimming is not supported.
 | 
			
		||||
		 */
 | 
			
		||||
		bool trim(const Time &start, const Time &end) const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the data size in bytes if the current state would
 | 
			
		||||
		 * be written to a stream. Trimming has also to be taken into
 | 
			
		||||
		 * account while calculating the size.
 | 
			
		||||
		 * @param withHeader Take header into account
 | 
			
		||||
		 * @return Returns the data size in bytes
 | 
			
		||||
		 */
 | 
			
		||||
		size_t dataSize(bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Reads the packet data including header from a streambuf
 | 
			
		||||
		 * and trims the data if possible to start and end.
 | 
			
		||||
		 * If maxBytes is greater than 0 then the record should
 | 
			
		||||
		 * not use more than this size of memory (in bytes).
 | 
			
		||||
		 *
 | 
			
		||||
		 * @param The streambuf object
 | 
			
		||||
		 * @param The buffer size
 | 
			
		||||
		 * @param The requested start time
 | 
			
		||||
		 * @param The requested end time
 | 
			
		||||
		 * @param The Max bytes to use
 | 
			
		||||
		 * @return If not the complete record has been read, RS_Partial
 | 
			
		||||
		 * must be returned, RS_Complete otherwise.
 | 
			
		||||
		 */
 | 
			
		||||
		ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		               const Time &start = Time(),
 | 
			
		||||
		               const Time &end = Time(),
 | 
			
		||||
		               int maxBytes = -1);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Reads the packet data without header from a streambuf
 | 
			
		||||
		 * and trims the data if possible to start and end.
 | 
			
		||||
		 * If maxBytes is greater than 0 then the record should
 | 
			
		||||
		 * not use more than this size of memory (in bytes).
 | 
			
		||||
		 *
 | 
			
		||||
		 * @param The streambuf object
 | 
			
		||||
		 * @param The buffer size
 | 
			
		||||
		 * @param The requested start time
 | 
			
		||||
		 * @param The requested end time
 | 
			
		||||
		 * @param The Max bytes to use
 | 
			
		||||
		 * @return If not the complete record has been read, RS_Partial
 | 
			
		||||
		 * must be returned, RS_Complete otherwise.
 | 
			
		||||
		 */
 | 
			
		||||
		ReadStatus getData(std::streambuf &buf, int size,
 | 
			
		||||
		                   const Time &start = Time(),
 | 
			
		||||
		                   const Time &end = Time(),
 | 
			
		||||
		                   int maxBytes = -1);
 | 
			
		||||
 | 
			
		||||
		//! writes the packet to a streambuf and trims the data
 | 
			
		||||
		//! if possible to start and end
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Writes the packet to a streambuf and trims the data
 | 
			
		||||
		 * if possible to start and end
 | 
			
		||||
		 * @param The streambuf object
 | 
			
		||||
		 * @param Take header into account
 | 
			
		||||
		 * @return True, if the data has been written
 | 
			
		||||
		 */
 | 
			
		||||
		bool put(std::streambuf &buf, bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Returns the packet type
 | 
			
		||||
		 * @return The packet type
 | 
			
		||||
		 */
 | 
			
		||||
		PacketType packetType() const { return RawDataPacket; }
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the start time of the record
 | 
			
		||||
		 * @param The start time
 | 
			
		||||
		 */
 | 
			
		||||
		void setStartTime(const Time &time);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the sampling frequency of the record
 | 
			
		||||
		 * @param numerator The numerator
 | 
			
		||||
		 * @param denominator The denomintor
 | 
			
		||||
		 */
 | 
			
		||||
		void setSamplingFrequency(uint16_t numerator, uint16_t denominator);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Sets the data type of the record
 | 
			
		||||
		 * @param The datatype to use
 | 
			
		||||
		 */
 | 
			
		||||
		void setDataType(DataType dt);
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * @brief Initializes the internal data vector from the given buffer
 | 
			
		||||
		 * @param The buffer to read the data from
 | 
			
		||||
		 * @param The buffer size
 | 
			
		||||
		 */
 | 
			
		||||
		void setBuffer(const void *data, size_t size);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		Header  _header;
 | 
			
		||||
 | 
			
		||||
		mutable Header  _currentHeader;
 | 
			
		||||
		mutable size_t  _dataOfs;
 | 
			
		||||
		mutable size_t  _dataSize;
 | 
			
		||||
 | 
			
		||||
		mutable Time    _startTime;
 | 
			
		||||
		mutable Time    _endTime;
 | 
			
		||||
	
 | 
			
		||||
		mutable bool    _dirty;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FixedRawDataRecord : public RawDataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		virtual bool canTrim() const { return false; }
 | 
			
		||||
		virtual bool canMerge() const { return false; }
 | 
			
		||||
		virtual bool trim(const Time &start, const Time &end) const { return false; }
 | 
			
		||||
		virtual const char *formatName() const;
 | 
			
		||||
		virtual ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		                       const Time &/*start*/, const Time &/*end*/,
 | 
			
		||||
		                       int maxBytes) {
 | 
			
		||||
			return RawDataRecord::get(buf, size, Time(), Time(), maxBytes);
 | 
			
		||||
		}
 | 
			
		||||
		PacketType packetType() const { return FixedRawDataPacket; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										137
									
								
								libs/gempa/caps/recordbuilder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								libs/gempa/caps/recordbuilder.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,137 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_RECORD_SAMPLER_H
 | 
			
		||||
#define GEMPA_CAPS_RECORD_SAMPLER_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/shared_ptr.hpp>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
template<typename T> class RecordBuilder {
 | 
			
		||||
	public:
 | 
			
		||||
		struct Record {
 | 
			
		||||
			Record() : samplingInterval(0.0), sampleCount(0), userData(NULL) {}
 | 
			
		||||
			std::string    netcode;
 | 
			
		||||
			std::string    stacode;
 | 
			
		||||
			std::string    loccode;
 | 
			
		||||
			std::string    chacode;
 | 
			
		||||
			Time           startTime;
 | 
			
		||||
			double         samplingInterval;
 | 
			
		||||
			size_t         sampleCount;
 | 
			
		||||
			std::vector<T> data;
 | 
			
		||||
			void          *userData;
 | 
			
		||||
		};
 | 
			
		||||
		typedef boost::shared_ptr<Record> RecordPtr;
 | 
			
		||||
		typedef boost::function<void (Record *rec, void*)> FlushCallback;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		RecordBuilder() : _bufSize(64) {}
 | 
			
		||||
		RecordBuilder(const std::string &netcode, const std::string &stacode,
 | 
			
		||||
		              const std::string &loccode, const std::string &chacode,
 | 
			
		||||
		              void *userData = NULL, size_t bufSize = 64) {
 | 
			
		||||
			_networkCode = netcode;
 | 
			
		||||
			_stationCode = stacode;
 | 
			
		||||
			_locationCode = loccode;
 | 
			
		||||
			_channelCode = chacode;
 | 
			
		||||
			_userData = userData;
 | 
			
		||||
			_bufSize = bufSize > 0? bufSize:1;
 | 
			
		||||
			_record = NULL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void flush(bool lastSample = false) {
 | 
			
		||||
			if ( _record != 0 ) {
 | 
			
		||||
				 if ( lastSample ) push();
 | 
			
		||||
 | 
			
		||||
				_flushCallback(_record, _userData);
 | 
			
		||||
				_record = NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void push(T value, const Time &time) {
 | 
			
		||||
			if ( _time.valid() ) {
 | 
			
		||||
				double interval = time - _time;
 | 
			
		||||
				if ( interval <= 0.0 ) {
 | 
			
		||||
					_time = Time();
 | 
			
		||||
					flush(true);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					if ( _record == NULL) {
 | 
			
		||||
						_record = new Record;
 | 
			
		||||
						if ( _record ) {
 | 
			
		||||
							_record->netcode = _networkCode;
 | 
			
		||||
							_record->stacode = _stationCode;
 | 
			
		||||
							_record->loccode = _locationCode;
 | 
			
		||||
							_record->chacode = _channelCode;
 | 
			
		||||
							_record->startTime = _time;
 | 
			
		||||
							_record->samplingInterval = interval;
 | 
			
		||||
 | 
			
		||||
							_record->data.reserve(_bufSize);
 | 
			
		||||
							_record->data[_record->sampleCount] = _value;
 | 
			
		||||
							++_record->sampleCount;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else if ( interval != _record->samplingInterval ) {
 | 
			
		||||
						flush(true);
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						push();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_time = time;
 | 
			
		||||
			_value = value;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void setFlushCallback(const FlushCallback &cb) { _flushCallback = cb; }
 | 
			
		||||
		void setNetworkCode(const std::string &netcode) { _networkCode = netcode; }
 | 
			
		||||
		void setStationCode(const std::string &stacode) { _stationCode = stacode; }
 | 
			
		||||
		void setLocationCode(const std::string &loccode) { _locationCode = loccode; }
 | 
			
		||||
		void setChannelCode(const std::string &chacode) { _channelCode = chacode; }
 | 
			
		||||
		void setUserData(void *userData) { _userData = userData; }
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void push() {
 | 
			
		||||
			if ( _record->sampleCount % _bufSize == 0 )
 | 
			
		||||
				_record->data.reserve(_record->sampleCount + _bufSize);
 | 
			
		||||
			_record->data[_record->sampleCount] = _value;
 | 
			
		||||
			++_record->sampleCount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		T                       _value;
 | 
			
		||||
		Time                    _time;
 | 
			
		||||
		Record                 *_record;
 | 
			
		||||
		FlushCallback           _flushCallback;
 | 
			
		||||
		size_t                  _bufSize;
 | 
			
		||||
		std::string             _networkCode;
 | 
			
		||||
		std::string             _stationCode;
 | 
			
		||||
		std::string             _locationCode;
 | 
			
		||||
		std::string             _channelCode;
 | 
			
		||||
		void                   *_userData;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										398
									
								
								libs/gempa/caps/riff.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								libs/gempa/caps/riff.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,398 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/riff.h>
 | 
			
		||||
#include <gempa/caps/endianess.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
namespace RIFF {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool ChunkHeader::setChunkType(const char *t) {
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if ( t != NULL ) {
 | 
			
		||||
		for ( i = 0; i < 4; ++i ) {
 | 
			
		||||
			if ( t[i] == '\0' ) break;
 | 
			
		||||
			chunkType[i] = t[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Input type must not have more than 4 characters
 | 
			
		||||
		if ( i == 3 && t[i] != '\0' && t[i+1] != '\0' ) {
 | 
			
		||||
			memset(chunkType, ' ', 4);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		i = 0;
 | 
			
		||||
 | 
			
		||||
	// Pad with whitespaces
 | 
			
		||||
	for ( ; i < 4; ++i )
 | 
			
		||||
		chunkType[i] = ' ';
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool ChunkHeader::isChunkType(const char *t) const {
 | 
			
		||||
	for ( int i = 0; i < 4; ++i ) {
 | 
			
		||||
		if ( t[i] == '\0' && chunkType[i] == ' ' ) break;
 | 
			
		||||
		if ( t[i] != chunkType[i] ) return false;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool ChunkHeader::validChunkType() const {
 | 
			
		||||
	for ( int i = 0; i < 4; ++i ) {
 | 
			
		||||
		if ( chunkType[i] == '\0' ) continue;
 | 
			
		||||
		if ( chunkType[i] >= 'a' && chunkType[i] <= 'z' ) continue;
 | 
			
		||||
		if ( chunkType[i] >= 'A' && chunkType[i] <= 'Z' ) continue;
 | 
			
		||||
		if ( chunkType[i] >= '0' && chunkType[i] <= '9' ) continue;
 | 
			
		||||
		if ( chunkType[i] == '-' ) continue;
 | 
			
		||||
		if ( chunkType[i] == '_' ) continue;
 | 
			
		||||
		if ( chunkType[i] == ' ' ) continue;
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool ChunkHeader::get(std::streambuf &input) {
 | 
			
		||||
	Endianess::Reader get(input);
 | 
			
		||||
	get(chunkType, 4);
 | 
			
		||||
	get(chunkSize);
 | 
			
		||||
	return get.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool ChunkHeader::put(std::streambuf &output) const {
 | 
			
		||||
	Endianess::Writer put(output);
 | 
			
		||||
	put(chunkType, 4);
 | 
			
		||||
	put(chunkSize);
 | 
			
		||||
	return put.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ChunkIterator::ChunkIterator() : _stream(&_own) {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ChunkIterator::ChunkIterator(const std::string &filename) {
 | 
			
		||||
	begin(filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ChunkIterator::ChunkIterator(std::istream &input) {
 | 
			
		||||
	begin(input);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ChunkIterator::begin(const std::string &filename) {
 | 
			
		||||
	_stream = &_own;
 | 
			
		||||
	_index = 0;
 | 
			
		||||
	_own.open(filename.c_str());
 | 
			
		||||
	memset(&_header, 0, sizeof(_header));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ChunkIterator::begin(std::istream &input) {
 | 
			
		||||
	_stream = &input;
 | 
			
		||||
	_index = input.tellg();
 | 
			
		||||
	_header.chunkSize = 0;
 | 
			
		||||
	memset(&_header, 0, sizeof(_header));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool ChunkIterator::next() {
 | 
			
		||||
	while ( _stream->good() ) {
 | 
			
		||||
		// Jump to next header
 | 
			
		||||
		_stream->seekg(_index + _header.chunkSize);
 | 
			
		||||
 | 
			
		||||
		if ( !_header.read(*_stream) )
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		//std::cout << " - "; std::cout.write(_header.chunkType, 4); std::cout << " : " << _header.chunkSize << std::endl;
 | 
			
		||||
 | 
			
		||||
		_index = _stream->tellg();
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const ChunkHeader &ChunkIterator::header() const {
 | 
			
		||||
	return _header;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
size_t ChunkIterator::headerPos() const {
 | 
			
		||||
	return _index - _header.dataSize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
size_t ChunkIterator::contentPos() const {
 | 
			
		||||
	return _index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Chunk::~Chunk() {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool HeadChunk::get(std::streambuf &input, int size) {
 | 
			
		||||
	Endianess::Reader r(input);
 | 
			
		||||
 | 
			
		||||
	r(data.version);
 | 
			
		||||
 | 
			
		||||
	char dt;
 | 
			
		||||
	r(dt);
 | 
			
		||||
	data.packetType = static_cast<PacketType>(dt);
 | 
			
		||||
 | 
			
		||||
	r(data.unitOfMeasurement.str, 4);
 | 
			
		||||
 | 
			
		||||
	return r.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool HeadChunk::put(std::streambuf &output) const {
 | 
			
		||||
	Endianess::Writer w(output);
 | 
			
		||||
 | 
			
		||||
	w(data.version);
 | 
			
		||||
 | 
			
		||||
	char dt = data.packetType;
 | 
			
		||||
	w(dt);
 | 
			
		||||
 | 
			
		||||
	w(data.unitOfMeasurement.str, 4);
 | 
			
		||||
 | 
			
		||||
	return w.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int HeadChunk::chunkSize() const {
 | 
			
		||||
	return sizeof(data.version) +
 | 
			
		||||
	       sizeof(data.unitOfMeasurement.str) +
 | 
			
		||||
	       sizeof(char);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool SIDChunk::put(std::streambuf &output) const {
 | 
			
		||||
	char null = '\0';
 | 
			
		||||
	Endianess::Writer w(output);
 | 
			
		||||
 | 
			
		||||
	if ( !networkCode.empty() )
 | 
			
		||||
		w(networkCode.c_str(), networkCode.size());
 | 
			
		||||
	w(&null, 1);
 | 
			
		||||
	if ( !stationCode.empty() )
 | 
			
		||||
		w(stationCode.c_str(), stationCode.size());
 | 
			
		||||
	w(&null, 1);
 | 
			
		||||
	if ( !locationCode.empty() )
 | 
			
		||||
		w(locationCode.c_str(), locationCode.size());
 | 
			
		||||
	w(&null, 1);
 | 
			
		||||
	if ( !channelCode.empty() )
 | 
			
		||||
		w(channelCode.c_str(), channelCode.size());
 | 
			
		||||
 | 
			
		||||
	return w.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool SIDChunk::get(std::streambuf &input, int size) {
 | 
			
		||||
	char tmp;
 | 
			
		||||
	int  count = size;
 | 
			
		||||
	Endianess::Reader r(input);
 | 
			
		||||
 | 
			
		||||
	r(&tmp, 1);
 | 
			
		||||
	networkCode.clear();
 | 
			
		||||
	while ( r.good && count-- ) {
 | 
			
		||||
		if ( tmp == '\0' ) break;
 | 
			
		||||
		networkCode += tmp;
 | 
			
		||||
		r(&tmp, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !r.good ) return false;
 | 
			
		||||
 | 
			
		||||
	r(&tmp, 1);
 | 
			
		||||
	stationCode.clear();
 | 
			
		||||
	while ( r.good && count-- ) {
 | 
			
		||||
		if ( tmp == '\0' ) break;
 | 
			
		||||
		stationCode += tmp;
 | 
			
		||||
		r(&tmp, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !r.good ) return false;
 | 
			
		||||
 | 
			
		||||
	r(&tmp, 1);
 | 
			
		||||
	locationCode.clear();
 | 
			
		||||
	while ( r.good && count-- ) {
 | 
			
		||||
		if ( tmp == '\0' ) break;
 | 
			
		||||
		locationCode += tmp;
 | 
			
		||||
		r(&tmp, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( !r.good ) return false;
 | 
			
		||||
 | 
			
		||||
	r(&tmp, 1);
 | 
			
		||||
	channelCode.clear();
 | 
			
		||||
	while ( r.good && count-- ) {
 | 
			
		||||
		if ( tmp == '\0' ) break;
 | 
			
		||||
		channelCode += tmp;
 | 
			
		||||
		r(&tmp, 1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int SIDChunk::chunkSize() const {
 | 
			
		||||
	return networkCode.size() + 1 +
 | 
			
		||||
	       stationCode.size() + 1 +
 | 
			
		||||
	       locationCode.size() + 1 +
 | 
			
		||||
	       channelCode.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
CPtrChunk<SIZE_T,BigEndian>::CPtrChunk(const char* d, int len) : data(d), size(len) {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
int CPtrChunk<SIZE_T,BigEndian>::chunkSize() const {
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
bool CPtrChunk<SIZE_T,BigEndian>::get(std::streambuf &, int) {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T, int SIZE_T, bool BigEndian>
 | 
			
		||||
struct CPtrWriter {
 | 
			
		||||
	static bool Take(std::streambuf &output, const T*, int count);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// To little endian
 | 
			
		||||
template <typename T, int SIZE_T>
 | 
			
		||||
struct CPtrWriter<T,SIZE_T,true> {
 | 
			
		||||
	static bool Take(std::streambuf &output, const T *data, int count) {
 | 
			
		||||
		Endianess::Writer w(output);
 | 
			
		||||
		for ( int i = 0; i < count; ++i ) {
 | 
			
		||||
			T tmp = Endianess::Swapper<T,true,SIZE_T>::Take(data[i]);
 | 
			
		||||
			w((const char*)&tmp, SIZE_T);
 | 
			
		||||
		}
 | 
			
		||||
		return w.good;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T, int SIZE_T>
 | 
			
		||||
struct CPtrWriter<T,SIZE_T,false> {
 | 
			
		||||
	static bool Take(std::streambuf &output, const T *data, int count) {
 | 
			
		||||
		return (int)output.sputn((const char*)data, SIZE_T*count) == SIZE_T*count;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
bool CPtrChunk<SIZE_T,BigEndian>::put(std::streambuf &output) const {
 | 
			
		||||
	typedef typename Endianess::TypeMap<SIZE_T>::ValueType T;
 | 
			
		||||
	return CPtrWriter<T,SIZE_T,BigEndian>::Take(output, (const T*)data, size/SIZE_T);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
VectorChunk<SIZE_T,BigEndian>::VectorChunk(std::vector<char> &d)
 | 
			
		||||
: data(d), startOfs(-1), len(-1) {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
VectorChunk<SIZE_T,BigEndian>::VectorChunk(std::vector<char> &d, int ofs, int count)
 | 
			
		||||
: data(d), startOfs(ofs), len(count) {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
int VectorChunk<SIZE_T,BigEndian>::chunkSize() const {
 | 
			
		||||
	return data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
bool VectorChunk<SIZE_T,BigEndian>::get(std::streambuf &input, int size) {
 | 
			
		||||
	int count = size/SIZE_T;
 | 
			
		||||
 | 
			
		||||
	if ( len >= 0 ) {
 | 
			
		||||
		if ( len > count )
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		count = len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Skip first samples (bytes = samples*sizeof(T))
 | 
			
		||||
	if ( startOfs > 0 )
 | 
			
		||||
		input.pubseekoff(startOfs*SIZE_T, std::ios_base::cur, std::ios_base::in);
 | 
			
		||||
 | 
			
		||||
	Endianess::Reader r(input);
 | 
			
		||||
 | 
			
		||||
	data.resize(count*SIZE_T);
 | 
			
		||||
	r(&data[0], data.size());
 | 
			
		||||
 | 
			
		||||
	// Convert array to little endian
 | 
			
		||||
	Endianess::ByteSwapper<BigEndian,SIZE_T>::Take(&data[0], count);
 | 
			
		||||
 | 
			
		||||
	// Go the end of chunk
 | 
			
		||||
	if ( (int)data.size() < size )
 | 
			
		||||
		input.pubseekoff(size-data.size(), std::ios_base::cur, std::ios_base::in);
 | 
			
		||||
 | 
			
		||||
	return r.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
bool VectorChunk<SIZE_T,BigEndian>::put(std::streambuf &output) const {
 | 
			
		||||
	typedef typename Endianess::TypeMap<SIZE_T>::ValueType T;
 | 
			
		||||
	return CPtrWriter<T,SIZE_T,BigEndian>::Take(output, (const T*)data.data(), data.size()/SIZE_T);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<1,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<1,true>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<2,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<2,true>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<4,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<4,true>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<8,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API CPtrChunk<8,true>;
 | 
			
		||||
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<1,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<1,true>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<2,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<2,true>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<4,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<4,true>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<8,false>;
 | 
			
		||||
template struct SC_GEMPA_CAPS_API VectorChunk<8,true>;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										193
									
								
								libs/gempa/caps/riff.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								libs/gempa/caps/riff.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,193 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2009 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef CAPS_IO_RIFF_H
 | 
			
		||||
#define CAPS_IO_RIFF_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
namespace RIFF {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API ChunkHeader {
 | 
			
		||||
	union {
 | 
			
		||||
		char     chunkType[4];
 | 
			
		||||
		uint32_t chunkID;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	int  chunkSize;    /* Chunk size in bytes */
 | 
			
		||||
 | 
			
		||||
	bool setChunkType(const char *type);
 | 
			
		||||
	bool isChunkType(const char *type) const;
 | 
			
		||||
	bool validChunkType() const;
 | 
			
		||||
 | 
			
		||||
	int  dataSize() const { return 8; }
 | 
			
		||||
 | 
			
		||||
	bool read(std::istream &input) { return get(*input.rdbuf()); }
 | 
			
		||||
	bool write(std::ostream &output) const { return put(*output.rdbuf()); }
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &input);
 | 
			
		||||
	bool put(std::streambuf &output) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const int ChunkHeaderSize = 8;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API ChunkIterator {
 | 
			
		||||
	public:
 | 
			
		||||
		ChunkIterator();
 | 
			
		||||
		ChunkIterator(const std::string &filename);
 | 
			
		||||
		ChunkIterator(std::istream &input);
 | 
			
		||||
 | 
			
		||||
		//! Starts iterating over a file or stream
 | 
			
		||||
		void begin(const std::string &filename);
 | 
			
		||||
		void begin(std::istream &input);
 | 
			
		||||
 | 
			
		||||
		//! Jumps to the next chunk. Returns false,
 | 
			
		||||
		//! if no chunk is available
 | 
			
		||||
		bool next();
 | 
			
		||||
 | 
			
		||||
		//! Returns the current chunk header
 | 
			
		||||
		const ChunkHeader &header() const;
 | 
			
		||||
 | 
			
		||||
		//! Returns the file position pointing
 | 
			
		||||
		//! to the current chunk header
 | 
			
		||||
		size_t headerPos() const;
 | 
			
		||||
 | 
			
		||||
		//! Returns the file position pointing
 | 
			
		||||
		//! to the current chunk content
 | 
			
		||||
		size_t contentPos() const;
 | 
			
		||||
 | 
			
		||||
		//! Returns the current input stream
 | 
			
		||||
		std::istream &istream() const { return *_stream; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		ChunkHeader    _header;
 | 
			
		||||
		std::istream  *_stream;
 | 
			
		||||
		size_t         _index;
 | 
			
		||||
		std::ifstream  _own;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API Chunk {
 | 
			
		||||
	virtual ~Chunk();
 | 
			
		||||
 | 
			
		||||
	bool read(std::istream &input, int size) { return get(*input.rdbuf(), size); }
 | 
			
		||||
	bool write(std::ostream &output) const { return put(*output.rdbuf()); }
 | 
			
		||||
 | 
			
		||||
	virtual bool get(std::streambuf &input, int size) = 0;
 | 
			
		||||
	virtual bool put(std::streambuf &output) const = 0;
 | 
			
		||||
 | 
			
		||||
	virtual int chunkSize() const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API HeadChunk : Chunk {
 | 
			
		||||
	PacketDataHeader data;
 | 
			
		||||
 | 
			
		||||
	int chunkSize() const;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &input, int size);
 | 
			
		||||
	bool put(std::streambuf &output) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API SID {
 | 
			
		||||
	std::string networkCode;
 | 
			
		||||
	std::string stationCode;
 | 
			
		||||
	std::string locationCode;
 | 
			
		||||
	std::string channelCode;
 | 
			
		||||
 | 
			
		||||
	bool operator==(const SID &other ) const {
 | 
			
		||||
		return networkCode == other.networkCode &&
 | 
			
		||||
		       stationCode == other.stationCode &&
 | 
			
		||||
		       locationCode == other.locationCode &&
 | 
			
		||||
		       channelCode == other.channelCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool operator!=(const SID &other ) const {
 | 
			
		||||
		return networkCode != other.networkCode ||
 | 
			
		||||
		       stationCode != other.stationCode ||
 | 
			
		||||
		       locationCode != other.locationCode ||
 | 
			
		||||
		       channelCode != other.channelCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string toString() const {
 | 
			
		||||
		return networkCode + "." + stationCode + "." +
 | 
			
		||||
		       locationCode + "." + channelCode;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct SC_GEMPA_CAPS_API SIDChunk : Chunk, SID {
 | 
			
		||||
	int chunkSize() const;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &input, int size);
 | 
			
		||||
	bool put(std::streambuf &output) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
struct CPtrChunk : Chunk {
 | 
			
		||||
	const char *data;
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
	CPtrChunk(const char* d, int len);
 | 
			
		||||
	virtual ~CPtrChunk() {}
 | 
			
		||||
 | 
			
		||||
	int chunkSize() const;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &input, int size);
 | 
			
		||||
	bool put(std::streambuf &output) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <int SIZE_T, bool BigEndian>
 | 
			
		||||
struct VectorChunk : Chunk {
 | 
			
		||||
	std::vector<char> &data;
 | 
			
		||||
 | 
			
		||||
	VectorChunk(std::vector<char> &d);
 | 
			
		||||
 | 
			
		||||
	// sampleOfs and sampleCount are not byte offsets but elements of
 | 
			
		||||
	// type T
 | 
			
		||||
	VectorChunk(std::vector<char> &d, int sampleOfs, int sampleCount);
 | 
			
		||||
	virtual ~VectorChunk() {}
 | 
			
		||||
 | 
			
		||||
	int chunkSize() const;
 | 
			
		||||
 | 
			
		||||
	bool get(std::streambuf &input, int size);
 | 
			
		||||
	bool put(std::streambuf &output) const;
 | 
			
		||||
 | 
			
		||||
	int startOfs;
 | 
			
		||||
	int len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										174
									
								
								libs/gempa/caps/rtcm2packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								libs/gempa/caps/rtcm2packet.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,174 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2012 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/rtcm2packet.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/riff.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
bool RTCM2DataRecord::RTCM2Header::put(std::streambuf &buf) const {
 | 
			
		||||
	Endianess::Writer put(buf);
 | 
			
		||||
 | 
			
		||||
	put(samplingTime.year);
 | 
			
		||||
	put(samplingTime.yday);
 | 
			
		||||
	put(samplingTime.hour);
 | 
			
		||||
	put(samplingTime.minute);
 | 
			
		||||
	put(samplingTime.second);
 | 
			
		||||
	put(samplingTime.usec);
 | 
			
		||||
	put(samplingFrequencyNumerator);
 | 
			
		||||
	put(samplingFrequencyDenominator);
 | 
			
		||||
 | 
			
		||||
	return put.good;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
RTCM2DataRecord::RTCM2DataRecord() {
 | 
			
		||||
	_header.samplingFrequencyDenominator = 0;
 | 
			
		||||
	_header.samplingFrequencyNumerator = 0;
 | 
			
		||||
	// Just a bunch of bytes
 | 
			
		||||
	_header.dataType = DT_Unknown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RTCM2DataRecord::setTimeStamp(const Time &ts) {
 | 
			
		||||
	 timeToTimestamp(_header.samplingTime, ts);
 | 
			
		||||
	_startTime = ts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void RTCM2DataRecord::setSamplingFrequency(uint16_t numerator, uint16_t denominator) {
 | 
			
		||||
	_header.samplingFrequencyNumerator = numerator;
 | 
			
		||||
	_header.samplingFrequencyDenominator = denominator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *RTCM2DataRecord::formatName() const {
 | 
			
		||||
	return "RTC2";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool RTCM2DataRecord::readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
                                 Header &header,
 | 
			
		||||
                                 Time &startTime, Time &endTime) {
 | 
			
		||||
	Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
	get(header.samplingTime.year);
 | 
			
		||||
	get(header.samplingTime.yday);
 | 
			
		||||
	get(header.samplingTime.hour);
 | 
			
		||||
	get(header.samplingTime.minute);
 | 
			
		||||
	get(header.samplingTime.second);
 | 
			
		||||
	get(header.samplingTime.usec);
 | 
			
		||||
	get(header.samplingFrequencyNumerator);
 | 
			
		||||
	get(header.samplingFrequencyDenominator);
 | 
			
		||||
 | 
			
		||||
	startTime = timestampToTime(header.samplingTime);
 | 
			
		||||
 | 
			
		||||
	if (  header.samplingFrequencyDenominator == 0 ||
 | 
			
		||||
	       header.samplingFrequencyNumerator == 0 ) {
 | 
			
		||||
		endTime = startTime;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		TimeSpan ts =
 | 
			
		||||
		    header.samplingFrequencyDenominator / header.samplingFrequencyNumerator;
 | 
			
		||||
		endTime = startTime + ts;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const DataRecord::Header *RTCM2DataRecord::header() const {
 | 
			
		||||
	return &_header;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time RTCM2DataRecord::startTime() const {
 | 
			
		||||
	return _startTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Time RTCM2DataRecord::endTime() const {
 | 
			
		||||
	return _endTime;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool RTCM2DataRecord::canTrim() const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool RTCM2DataRecord::canMerge() const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool RTCM2DataRecord::trim(const Time &start,
 | 
			
		||||
                           const Time &end) const {
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
size_t RTCM2DataRecord::dataSize(bool withHeader) const {
 | 
			
		||||
	if ( withHeader )
 | 
			
		||||
		return _data.size() + _header.dataSize();
 | 
			
		||||
	else
 | 
			
		||||
		return _data.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DataRecord::ReadStatus RTCM2DataRecord::get(std::streambuf &buf, int size,
 | 
			
		||||
                                            const Time &start, const Time &end,
 | 
			
		||||
                                            int) {
 | 
			
		||||
	size -= _header.dataSize();
 | 
			
		||||
	if ( size < 0 ) return RS_Error;
 | 
			
		||||
	if ( !_header.get(buf) ) return RS_Error;
 | 
			
		||||
 | 
			
		||||
	if ( _header.samplingFrequencyNumerator == 0 ||
 | 
			
		||||
	     _header.samplingFrequencyDenominator == 0 ) {
 | 
			
		||||
		CAPS_ERROR("Sampling frequency not set");
 | 
			
		||||
		return RS_Error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TimeSpan ts =
 | 
			
		||||
	    _header.samplingFrequencyDenominator / _header.samplingFrequencyNumerator;
 | 
			
		||||
	_startTime = timestampToTime(_header.samplingTime);
 | 
			
		||||
	_endTime = _startTime + ts;
 | 
			
		||||
 | 
			
		||||
	if ( end.valid() && (end <= _startTime) ) return RS_AfterTimeWindow;
 | 
			
		||||
	if ( start.valid() && (start >= _endTime) ) return RS_BeforeTimeWindow;
 | 
			
		||||
 | 
			
		||||
	RIFF::VectorChunk<1,false> dataChunk(_data, 0, size);
 | 
			
		||||
 | 
			
		||||
	return dataChunk.get(buf, size)?RS_Complete:RS_Error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool RTCM2DataRecord::put(std::streambuf &buf, bool withHeader) const {
 | 
			
		||||
	if ( withHeader && !_header.put(buf) ) return false;
 | 
			
		||||
 | 
			
		||||
	RIFF::CPtrChunk<1,false> dataChunk(&_data[0], _data.size());
 | 
			
		||||
	return dataChunk.put(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								libs/gempa/caps/rtcm2packet.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								libs/gempa/caps/rtcm2packet.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2012 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_RTCM2PACKET_H
 | 
			
		||||
#define GEMPA_CAPS_RTCM2PACKET_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/endianess.h>
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class RTCM2DataRecord : public DataRecord {
 | 
			
		||||
	public:
 | 
			
		||||
		struct RTCM2Header : Header {
 | 
			
		||||
			bool get(std::streambuf &buf) {
 | 
			
		||||
				Endianess::Reader get(buf);
 | 
			
		||||
 | 
			
		||||
				get(samplingTime.year);
 | 
			
		||||
				get(samplingTime.yday);
 | 
			
		||||
				get(samplingTime.hour);
 | 
			
		||||
				get(samplingTime.minute);
 | 
			
		||||
				get(samplingTime.second);
 | 
			
		||||
				get(samplingTime.usec);
 | 
			
		||||
				get(samplingFrequencyNumerator);
 | 
			
		||||
				get(samplingFrequencyDenominator);
 | 
			
		||||
 | 
			
		||||
				return get.good;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bool put(std::streambuf &buf) const;
 | 
			
		||||
 | 
			
		||||
			// size of data header
 | 
			
		||||
			int dataSize() const {
 | 
			
		||||
				return
 | 
			
		||||
				       sizeof(samplingTime.year) +
 | 
			
		||||
				       sizeof(samplingTime.yday) +
 | 
			
		||||
				       sizeof(samplingTime.hour) +
 | 
			
		||||
				       sizeof(samplingTime.minute) +
 | 
			
		||||
				       sizeof(samplingTime.second) +
 | 
			
		||||
				       sizeof(samplingTime.usec) +
 | 
			
		||||
				       sizeof(samplingFrequencyNumerator) +
 | 
			
		||||
				       sizeof(samplingFrequencyDenominator);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		RTCM2DataRecord();
 | 
			
		||||
 | 
			
		||||
		const char* formatName() const;
 | 
			
		||||
 | 
			
		||||
		void setTimeStamp(const Time &ts);
 | 
			
		||||
 | 
			
		||||
		void setSamplingFrequency(uint16_t numerator, uint16_t denominator);
 | 
			
		||||
 | 
			
		||||
		virtual bool readMetaData(std::streambuf &buf, int size,
 | 
			
		||||
		                          Header &header,
 | 
			
		||||
		                          Time &startTime,
 | 
			
		||||
		                          Time &endTime);
 | 
			
		||||
 | 
			
		||||
		virtual const Header *header() const;
 | 
			
		||||
		virtual Time startTime() const;
 | 
			
		||||
		virtual Time endTime() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool canTrim() const;
 | 
			
		||||
		virtual bool canMerge() const;
 | 
			
		||||
 | 
			
		||||
		virtual bool trim(const Time &start,
 | 
			
		||||
		                  const Time &end) const;
 | 
			
		||||
 | 
			
		||||
		virtual size_t dataSize(bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		virtual ReadStatus get(std::streambuf &buf, int size,
 | 
			
		||||
		                       const Time &start,
 | 
			
		||||
		                       const Time &end,
 | 
			
		||||
		                       int maxSize = -1);
 | 
			
		||||
 | 
			
		||||
		virtual bool put(std::streambuf &buf, bool withHeader) const;
 | 
			
		||||
 | 
			
		||||
		PacketType packetType() const { return RTCM2Packet; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		RTCM2Header          _header;
 | 
			
		||||
		Buffer               _data;
 | 
			
		||||
		Time                 _startTime;
 | 
			
		||||
		Time                 _endTime;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										404
									
								
								libs/gempa/caps/sessiontable.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										404
									
								
								libs/gempa/caps/sessiontable.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,404 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include  <gempa/caps/sessiontable.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace  CAPS {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
void setDataType(const char *data, int len, Gempa::CAPS::SessionTableItem &item) {
 | 
			
		||||
	if ( CHECK_STRING(data, "FLOAT", len) ) {
 | 
			
		||||
		item.dataType = DT_FLOAT;
 | 
			
		||||
		item.dataSize = 4;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 32bit floats", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "DOUBLE", len) ) {
 | 
			
		||||
		item.dataType = DT_DOUBLE;
 | 
			
		||||
		item.dataSize = 8;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 64bit doubles", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT64", len) ) {
 | 
			
		||||
		item.dataType = DT_INT64;
 | 
			
		||||
		item.dataSize = 8;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 64bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT32", len) ) {
 | 
			
		||||
		item.dataType = DT_INT32;
 | 
			
		||||
		item.dataSize = 4;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 32bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT16", len) ) {
 | 
			
		||||
		item.dataType = DT_INT16;
 | 
			
		||||
		item.dataSize = 2;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 16bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT8", len) ) {
 | 
			
		||||
		item.dataType = DT_INT8;
 | 
			
		||||
		item.dataSize = 1;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 8bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		item.dataType = DT_Unknown;
 | 
			
		||||
		CAPS_WARNING("Unknown raw data type '%s', all packages will be ignored",
 | 
			
		||||
		            string(data, len).c_str());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SessionTableItem::splitStreamID() {
 | 
			
		||||
	const char *tok;
 | 
			
		||||
	int tok_len;
 | 
			
		||||
	int tok_count = 0;
 | 
			
		||||
 | 
			
		||||
	const char* str = streamID.c_str();
 | 
			
		||||
	int len = strlen(str);
 | 
			
		||||
 | 
			
		||||
	string *items[] = {&net, &sta, &loc, &cha};
 | 
			
		||||
 | 
			
		||||
	for ( ; (tok = tokenize(str, ".", len, tok_len)) != NULL;
 | 
			
		||||
	      ++tok_count ) {
 | 
			
		||||
		if ( tok_count > 4 ) return false;
 | 
			
		||||
 | 
			
		||||
		items[tok_count]->assign(tok, tok_len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( tok_count == 3 ) {
 | 
			
		||||
		cha = loc;
 | 
			
		||||
		loc = "";
 | 
			
		||||
		tok_count = 4;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tok_count == 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SessionTable::SessionTable() : _state(Unspecific) {}
 | 
			
		||||
 | 
			
		||||
SessionTable::Status SessionTable::handleResponse(const char *src_data, int data_len) {
 | 
			
		||||
	enum StreamHeaderToken {
 | 
			
		||||
		REQ_ID = 0,
 | 
			
		||||
		SID    = 1,
 | 
			
		||||
		SF     = 2,
 | 
			
		||||
		UOM    = 3,
 | 
			
		||||
		FORMAT = 4,
 | 
			
		||||
		COUNT  = 5
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	int src_len = data_len;
 | 
			
		||||
	const char *src = src_data;
 | 
			
		||||
 | 
			
		||||
	int len;
 | 
			
		||||
	const char *data;
 | 
			
		||||
	if ( (data = tokenize(src_data, " ", data_len, len)) == NULL ) {
 | 
			
		||||
		CAPS_WARNING("server returned empty line, ignoring");
 | 
			
		||||
		return Success;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch ( _state ) {
 | 
			
		||||
		case Unspecific:
 | 
			
		||||
			if ( CHECK_STRING(data, "STATUS", len) ) {
 | 
			
		||||
				if ( (data = tokenize(src_data, " ", data_len, len)) != NULL ) {
 | 
			
		||||
					if ( CHECK_STRING(data, "OK", len) ) {
 | 
			
		||||
						CAPS_DEBUG("server responds OK");
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						CAPS_ERROR("received unknown status from server: %s", data);
 | 
			
		||||
						return Error;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					CAPS_ERROR("received empty status from server");
 | 
			
		||||
					return Error;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else if ( CHECK_STRING(data, "REQUESTS", len) ) {
 | 
			
		||||
				if ( (data = tokenize(src_data, " ", data_len, len)) != NULL ) {
 | 
			
		||||
					CAPS_WARNING("received unknown REQUESTS parameter: %s", data);
 | 
			
		||||
				}
 | 
			
		||||
				CAPS_DEBUG("stream table update started");
 | 
			
		||||
				_state = Requests;
 | 
			
		||||
			}
 | 
			
		||||
			else if ( CHECK_STRING(data, "EOD", len) ) {
 | 
			
		||||
				CAPS_DEBUG("server sent EOD");
 | 
			
		||||
				return EOD;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				CAPS_ERROR("received unknown response: %s", data);
 | 
			
		||||
				return Error;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case Requests:
 | 
			
		||||
			if ( CHECK_STRING(data, "END", len) ) {
 | 
			
		||||
				if ( (data = tokenize(src_data, " ", data_len, len)) != NULL ) {
 | 
			
		||||
					CAPS_WARNING("received unknown END parameter: %s", data);
 | 
			
		||||
				}
 | 
			
		||||
				CAPS_DEBUG("stream table update complete");
 | 
			
		||||
				_state = Unspecific;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			CAPS_DEBUG("request response data: %s", string(data, len).c_str());
 | 
			
		||||
 | 
			
		||||
			typedef std::pair<const char *, int> Buffer;
 | 
			
		||||
			const char *state = src;
 | 
			
		||||
			Buffer toks[COUNT];
 | 
			
		||||
			for ( int i = 0; i < COUNT; ++i )
 | 
			
		||||
				toks[i].second = 0;
 | 
			
		||||
 | 
			
		||||
			// Update request map
 | 
			
		||||
			while ( (data = tokenize(src, ",", src_len, len)) != NULL ) {
 | 
			
		||||
				trim(data, len);
 | 
			
		||||
				if ( !strncasecmp(data, "ID:", 3) )
 | 
			
		||||
					toks[REQ_ID] = Buffer(data+3, len-3);
 | 
			
		||||
				else if ( !strncasecmp(data, "SID:", 4) )
 | 
			
		||||
					toks[SID] = Buffer(data+4, len-4);
 | 
			
		||||
				else if ( !strncasecmp(data, "SFREQ:", 6) )
 | 
			
		||||
					toks[SF] = Buffer(data+6, len-6);
 | 
			
		||||
				else if ( !strncasecmp(data, "UOM:", 4) )
 | 
			
		||||
					toks[UOM] = Buffer(data+4, len-4);
 | 
			
		||||
				else if ( !strncasecmp(data, "FMT:", 4) )
 | 
			
		||||
					toks[FORMAT] = Buffer(data+4, len-4);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			SessionTableItem item;
 | 
			
		||||
			char buffer[7];
 | 
			
		||||
			if ( toks[REQ_ID].second > 6 ) {
 | 
			
		||||
				CAPS_ERROR("request state ID too high: %s", state);
 | 
			
		||||
				return Error;
 | 
			
		||||
			}
 | 
			
		||||
			strncpy(buffer, toks[REQ_ID].first, toks[REQ_ID].second);
 | 
			
		||||
			buffer[toks[REQ_ID].second] = '\0';
 | 
			
		||||
			int req_id;
 | 
			
		||||
 | 
			
		||||
			if ( (sscanf(buffer, "%d", &req_id) != 1) || req_id == 0 ) {
 | 
			
		||||
				CAPS_ERROR("invalid request ID: %s", buffer);
 | 
			
		||||
				return Error;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ( toks[SID].second == 0 ) {
 | 
			
		||||
				CAPS_ERROR("missing SID in request response");
 | 
			
		||||
				return Error;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			item.streamID.assign(toks[SID].first, toks[SID].second);
 | 
			
		||||
 | 
			
		||||
			if ( req_id < 0 ) {
 | 
			
		||||
				removeStream(item.streamID);
 | 
			
		||||
				CAPS_DEBUG("stream %s has finished", item.streamID.c_str());
 | 
			
		||||
				return Success;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				CAPS_DEBUG("new request ID %d for stream %s received", req_id, item.streamID.c_str());
 | 
			
		||||
				std::string tmp;
 | 
			
		||||
 | 
			
		||||
				if ( (data = tokenize(toks[SF].first, "/", toks[SF].second, len)) != NULL ) {
 | 
			
		||||
					trim(data, len);
 | 
			
		||||
					tmp.assign(data, len);
 | 
			
		||||
					if ( !str2int(item.samplingFrequency, tmp.c_str()) ) {
 | 
			
		||||
						CAPS_ERROR("request state 'samplingFrequency' is not a number: %s", state);
 | 
			
		||||
						item.samplingFrequency = 0;
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						item.samplingFrequencyDivider = 1;
 | 
			
		||||
						if ( (data = tokenize(toks[SF].first, "/", toks[SF].second, len)) != NULL ) {
 | 
			
		||||
							trim(data, len);
 | 
			
		||||
							tmp.assign(data, len);
 | 
			
		||||
							if ( !str2int(item.samplingFrequencyDivider, tmp.c_str()) ) {
 | 
			
		||||
								CAPS_ERROR("request state 'samplingFrequencyDivider' "
 | 
			
		||||
								           "is not a number: %s", state);
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					item.samplingFrequency = 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if ( toks[UOM].second > 4 ) {
 | 
			
		||||
					CAPS_ERROR("request state 'unit of measurement' is invalid, "
 | 
			
		||||
					           "too many characters: %s", state);
 | 
			
		||||
					item.uom.ID = 0;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					memcpy(item.uom.str, toks[UOM].first, toks[UOM].second);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if ( (data = tokenize(toks[FORMAT].first, "/", toks[FORMAT].second, len)) != NULL ) {
 | 
			
		||||
					trim(data, len);
 | 
			
		||||
					if ( CHECK_STRING(data, "RAW", len) ) {
 | 
			
		||||
						item.type = RawDataPacket;
 | 
			
		||||
						if ( (data = tokenize(toks[FORMAT].first, "/", toks[FORMAT].second, len)) != NULL ) {
 | 
			
		||||
							setDataType(data, len, item);
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						CAPS_DEBUG("%s: samplingFrequency=%d/%d",
 | 
			
		||||
						           item.streamID.c_str(), item.samplingFrequency,
 | 
			
		||||
						           item.samplingFrequencyDivider);
 | 
			
		||||
					}
 | 
			
		||||
					else if ( CHECK_STRING(data, "FIXEDRAW", len) ) {
 | 
			
		||||
						item.type = FixedRawDataPacket;
 | 
			
		||||
						if ( (data = tokenize(toks[FORMAT].first, "/", toks[FORMAT].second, len)) != NULL ) {
 | 
			
		||||
							setDataType(data, len, item);
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						CAPS_DEBUG("%s: samplingFrequency=%d/%d",
 | 
			
		||||
						           item.streamID.c_str(), item.samplingFrequency,
 | 
			
		||||
						           item.samplingFrequencyDivider);
 | 
			
		||||
					}
 | 
			
		||||
					else if ( CHECK_STRING(data, "MSEED", len) ) {
 | 
			
		||||
						item.type = MSEEDPacket;
 | 
			
		||||
					}
 | 
			
		||||
					else if ( CHECK_STRING(data, "META", len ) ) {
 | 
			
		||||
						item.type = MetaDataPacket;
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						string tmp(data, len);
 | 
			
		||||
						item.type = ANYPacket;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Register item
 | 
			
		||||
				registerItem(req_id, item);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setDataType(const char *data, int len, Gempa::CAPS::SessionTableItem &item) {
 | 
			
		||||
	if ( CHECK_STRING(data, "FLOAT", len) ) {
 | 
			
		||||
		item.dataType = DT_FLOAT;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 32bit floats", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "DOUBLE", len) ) {
 | 
			
		||||
		item.dataType = DT_DOUBLE;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 64bit doubles", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT64", len) ) {
 | 
			
		||||
		item.dataType = DT_INT64;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 64bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT32", len) ) {
 | 
			
		||||
		item.dataType = DT_INT32;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 32bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT16", len) ) {
 | 
			
		||||
		item.dataType = DT_INT16;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 16bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else if ( CHECK_STRING(data, "INT8", len) ) {
 | 
			
		||||
		item.dataType = DT_INT8;
 | 
			
		||||
		//SEISCOMP_DEBUG("%s: raw format with 8bit integers", item.streamID.c_str());
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		string tmp;
 | 
			
		||||
		item.dataType = DT_Unknown;
 | 
			
		||||
		tmp.assign(data, len);
 | 
			
		||||
		CAPS_WARNING("Unknown raw data type '%s', all packages will be ignored",
 | 
			
		||||
		             tmp.c_str());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionTable::registerItem(int id, SessionTableItem &item) {
 | 
			
		||||
	item.fSamplingFrequency = (double)item.samplingFrequency /
 | 
			
		||||
	                          (double)item.samplingFrequencyDivider;
 | 
			
		||||
 | 
			
		||||
	SessionTable::iterator it = find(id);
 | 
			
		||||
	if ( it == end() ) {
 | 
			
		||||
		if ( !item.splitStreamID() ) {
 | 
			
		||||
			CAPS_WARNING("invalid streamID received: %s", item.streamID.c_str());
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Copy the item
 | 
			
		||||
		SessionTableItem &target = operator[](id);
 | 
			
		||||
		target = item;
 | 
			
		||||
 | 
			
		||||
		_streamIDLookup[item.streamID] = id;
 | 
			
		||||
 | 
			
		||||
		if ( _itemAddedFunc ) _itemAddedFunc(&target);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		bool res = item.splitStreamID();
 | 
			
		||||
 | 
			
		||||
		// streamID changed for the same sessionID?
 | 
			
		||||
		if ( it->second.streamID != item.streamID ) {
 | 
			
		||||
			CAPS_WARNING("inconsistent state: streamID '%s' for id %d, "
 | 
			
		||||
			             "but streamID '%s' has not been closed before",
 | 
			
		||||
			             item.streamID.c_str(), id, it->second.streamID.c_str());
 | 
			
		||||
			// Update lookup table
 | 
			
		||||
			_streamIDLookup.erase(_streamIDLookup.find(it->second.streamID));
 | 
			
		||||
 | 
			
		||||
			if ( !res ) {
 | 
			
		||||
				CAPS_WARNING("invalid streamID received: %s", item.streamID.c_str());
 | 
			
		||||
				erase(it);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_streamIDLookup[item.streamID] = id;
 | 
			
		||||
 | 
			
		||||
			// TODO: How to update the request list?
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		it->second = item;
 | 
			
		||||
 | 
			
		||||
		if ( _itemAddedFunc ) _itemAddedFunc(&it->second);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionTable::removeStream(const std::string &streamID) {
 | 
			
		||||
	StreamIDLookupTable::iterator it = _streamIDLookup.find(streamID);
 | 
			
		||||
	if ( it == _streamIDLookup.end() ) {
 | 
			
		||||
		CAPS_WARNING("internal: tried to remove unknown stream '%s'",
 | 
			
		||||
		             streamID.c_str());
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SessionTable::iterator sessionIt = find(it->second);
 | 
			
		||||
	if ( sessionIt != end() ) {
 | 
			
		||||
		// Remove session table row
 | 
			
		||||
		if ( _itemAboutToBeRemovedFunc )
 | 
			
		||||
			_itemAboutToBeRemovedFunc(&sessionIt->second);
 | 
			
		||||
		erase(sessionIt);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove lookup entry
 | 
			
		||||
	_streamIDLookup.erase(it);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SessionTable::reset() {
 | 
			
		||||
	clear();
 | 
			
		||||
	_streamIDLookup.clear();
 | 
			
		||||
	_state = Unspecific;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								libs/gempa/caps/sessiontable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								libs/gempa/caps/sessiontable.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_SESSIONTABLE_H
 | 
			
		||||
#define GEMPA_CAPS_SESSIONTABLE_H
 | 
			
		||||
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
struct SessionTableItem {
 | 
			
		||||
	SessionTableItem() : samplingFrequency(0), samplingFrequencyDivider(0),
 | 
			
		||||
	                     fSamplingFrequency(0.0), dataType(DT_Unknown),
 | 
			
		||||
	                     dataSize(0), userData(NULL) {}
 | 
			
		||||
	std::string           streamID;
 | 
			
		||||
	std::string           net;
 | 
			
		||||
	std::string           sta;
 | 
			
		||||
	std::string           loc;
 | 
			
		||||
	std::string           cha;
 | 
			
		||||
	uint16_t              samplingFrequency;
 | 
			
		||||
	uint16_t              samplingFrequencyDivider;
 | 
			
		||||
	double                fSamplingFrequency;
 | 
			
		||||
	PacketType            type;
 | 
			
		||||
	DataType              dataType;
 | 
			
		||||
	int                   dataSize;
 | 
			
		||||
	UOM                   uom;
 | 
			
		||||
	Time                  startTime;
 | 
			
		||||
	Time                  endTime;
 | 
			
		||||
	void                 *userData;
 | 
			
		||||
 | 
			
		||||
	bool splitStreamID();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API SessionTable : public std::map<int, SessionTableItem> {
 | 
			
		||||
	public:
 | 
			
		||||
		enum Status {Success, Error, EOD};
 | 
			
		||||
 | 
			
		||||
		typedef std::function<void (SessionTableItem*)> CallbackFunc;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		//! Default constructor
 | 
			
		||||
		SessionTable();
 | 
			
		||||
		virtual ~SessionTable() {}
 | 
			
		||||
 | 
			
		||||
		//! Resets state
 | 
			
		||||
		void reset();
 | 
			
		||||
 | 
			
		||||
		SessionTableItem* getItem(int id) {
 | 
			
		||||
			SessionTable::iterator it = find(id);
 | 
			
		||||
			if ( it == end() ) return NULL;
 | 
			
		||||
 | 
			
		||||
			return &it->second;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Status handleResponse(const char *src_data, int data_len);
 | 
			
		||||
 | 
			
		||||
		void setItemAddedFunc(const CallbackFunc &func) { _itemAddedFunc = func; }
 | 
			
		||||
		void setItemAboutToBeRemovedFunc(const CallbackFunc &func) {
 | 
			
		||||
			_itemAboutToBeRemovedFunc = func;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		enum ResponseState {
 | 
			
		||||
			Unspecific,
 | 
			
		||||
			Requests
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		typedef std::map<std::string, int> StreamIDLookupTable;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void registerItem(int id, SessionTableItem &item);
 | 
			
		||||
		void removeStream(const std::string & streamID);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		ResponseState        _state;
 | 
			
		||||
		StreamIDLookupTable  _streamIDLookup;
 | 
			
		||||
		CallbackFunc         _itemAddedFunc;
 | 
			
		||||
		CallbackFunc         _itemAboutToBeRemovedFunc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										545
									
								
								libs/gempa/caps/socket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										545
									
								
								libs/gempa/caps/socket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,545 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/socket.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <netdb.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#ifndef SHUT_RDWR
 | 
			
		||||
#define SHUT_RDWR SD_BOTH
 | 
			
		||||
#endif
 | 
			
		||||
#define _WIN32_WINNT 0x0501  // Older versions does not support getaddrinfo
 | 
			
		||||
#include <io.h>
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
#include <ws2tcpip.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <cerrno>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
inline string toString(unsigned short value) {
 | 
			
		||||
	stringstream ss;
 | 
			
		||||
	ss << value;
 | 
			
		||||
	return ss.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::Socket() {
 | 
			
		||||
	_fd = -1;
 | 
			
		||||
	_bytesSent = _bytesReceived = 0;
 | 
			
		||||
	_timeOutSecs = _timeOutUsecs = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	WSADATA wsa;
 | 
			
		||||
	WSAStartup(MAKEWORD(2,0),&wsa);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::~Socket() {
 | 
			
		||||
	close();
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
	WSACleanup();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
const char *Socket::toString(Status stat) {
 | 
			
		||||
	switch ( stat ) {
 | 
			
		||||
		case Success:
 | 
			
		||||
			return "success";
 | 
			
		||||
		default:
 | 
			
		||||
		case Error:
 | 
			
		||||
			return "error";
 | 
			
		||||
		case AllocationError:
 | 
			
		||||
			return "allocation error";
 | 
			
		||||
		case ReuseAdressError:
 | 
			
		||||
			return "reusing address failed";
 | 
			
		||||
		case BindError:
 | 
			
		||||
			return "bind error";
 | 
			
		||||
		case ListenError:
 | 
			
		||||
			return "listen error";
 | 
			
		||||
		case AcceptError:
 | 
			
		||||
			return "accept error";
 | 
			
		||||
		case ConnectError:
 | 
			
		||||
			return "connect error";
 | 
			
		||||
		case AddrInfoError:
 | 
			
		||||
			return "address info error";
 | 
			
		||||
		case Timeout:
 | 
			
		||||
			return "timeout";
 | 
			
		||||
		case InvalidSocket:
 | 
			
		||||
			return "invalid socket";
 | 
			
		||||
		case InvalidPort:
 | 
			
		||||
			return "invalid port";
 | 
			
		||||
		case InvalidAddressFamily:
 | 
			
		||||
			return "invalid address family";
 | 
			
		||||
		case InvalidAddress:
 | 
			
		||||
			return "invalid address";
 | 
			
		||||
		case InvalidHostname:
 | 
			
		||||
			return "invalid hostname";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return "";
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
void Socket::shutdown() {
 | 
			
		||||
	if ( _fd == -1 ) return;
 | 
			
		||||
	//CAPS_DEBUG("Socket::shutdown");
 | 
			
		||||
	::shutdown(_fd, SHUT_RDWR);
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
void Socket::close() {
 | 
			
		||||
	if ( _fd != -1 ) {
 | 
			
		||||
		//CAPS_DEBUG("[socket] close %lX with fd = %d", (long int)this, _fd);
 | 
			
		||||
		int fd = _fd;
 | 
			
		||||
		_fd = -1;
 | 
			
		||||
		::close(fd);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::Status Socket::setSocketTimeout(int secs, int usecs) {
 | 
			
		||||
	_timeOutSecs = secs;
 | 
			
		||||
	_timeOutUsecs = usecs;
 | 
			
		||||
 | 
			
		||||
	if ( _fd != -1 )
 | 
			
		||||
		return applySocketTimeout(_timeOutSecs, _timeOutUsecs);
 | 
			
		||||
 | 
			
		||||
	return Success;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::Status Socket::applySocketTimeout(int secs, int usecs) {
 | 
			
		||||
	if ( _fd != -1 ) {
 | 
			
		||||
		struct timeval timeout;
 | 
			
		||||
		void *opt;
 | 
			
		||||
		int optlen;
 | 
			
		||||
 | 
			
		||||
		if ( secs >= 0 ) {
 | 
			
		||||
			timeout.tv_sec = secs;
 | 
			
		||||
			timeout.tv_usec = usecs;
 | 
			
		||||
			opt = &timeout;
 | 
			
		||||
			optlen = sizeof(timeout);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			opt = NULL;
 | 
			
		||||
			optlen = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		CAPS_DEBUG("set socket timeout to %d.%ds", secs, usecs);
 | 
			
		||||
 | 
			
		||||
		if ( setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, opt, optlen) )
 | 
			
		||||
			return Error;
 | 
			
		||||
 | 
			
		||||
		if ( setsockopt(_fd, SOL_SOCKET, SO_SNDTIMEO, opt, optlen) )
 | 
			
		||||
			return Error;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		return InvalidSocket;
 | 
			
		||||
 | 
			
		||||
	return Success;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::Device::Status Socket::setNonBlocking(bool nb) {
 | 
			
		||||
	if ( !isValid() )
 | 
			
		||||
		return Device::InvalidDevice;
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
	int flags = fcntl(_fd, F_GETFL, 0);
 | 
			
		||||
 | 
			
		||||
	if ( nb )
 | 
			
		||||
		flags |= O_NONBLOCK;
 | 
			
		||||
	else
 | 
			
		||||
		flags &= ~O_NONBLOCK;
 | 
			
		||||
 | 
			
		||||
	if ( fcntl(_fd, F_SETFL, flags) == -1 )
 | 
			
		||||
		return Device::Error;
 | 
			
		||||
#else
 | 
			
		||||
	u_long arg = nb?1:0;
 | 
			
		||||
	if ( ioctlsocket(_fd, FIONBIO, &arg) != 0 )
 | 
			
		||||
		return Device::Error;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return Device::Success;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::Status Socket::connect(const std::string &hostname, uint16_t port) {
 | 
			
		||||
	if ( _fd != -1 ) {
 | 
			
		||||
		//CAPS_WARNING("closing stale socket");
 | 
			
		||||
		close();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct sockaddr addr;
 | 
			
		||||
	size_t addrlen;
 | 
			
		||||
 | 
			
		||||
	struct addrinfo *res;
 | 
			
		||||
	struct addrinfo hints;
 | 
			
		||||
 | 
			
		||||
	memset (&hints, 0, sizeof(hints));
 | 
			
		||||
	hints.ai_family = PF_INET;
 | 
			
		||||
	hints.ai_socktype = SOCK_STREAM;
 | 
			
		||||
 | 
			
		||||
	string strPort = ::toString(port);
 | 
			
		||||
 | 
			
		||||
	int ret = getaddrinfo(hostname.c_str(), strPort.c_str(), &hints, &res);
 | 
			
		||||
	if ( ret ) {
 | 
			
		||||
		CAPS_DEBUG("Test3 Socket::connect(%s:%d): %s",
 | 
			
		||||
			       hostname.c_str(), port,
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
		           strerror(errno));
 | 
			
		||||
#else
 | 
			
		||||
		           gai_strerror(ret));
 | 
			
		||||
#endif
 | 
			
		||||
		return AddrInfoError;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addr = *(res->ai_addr);
 | 
			
		||||
	addrlen = res->ai_addrlen;
 | 
			
		||||
	freeaddrinfo(res);
 | 
			
		||||
 | 
			
		||||
	if ( (_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
 | 
			
		||||
		/*CAPS_DEBUG("Socket::connect(%s:%d): %s",
 | 
			
		||||
		               hostname.c_str(), port, strerror(errno));*/
 | 
			
		||||
		return AllocationError;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
	if ( ::connect(_fd, (struct sockaddr *)&addr, addrlen) == -1 ) {
 | 
			
		||||
		if ( errno != EINPROGRESS ) {
 | 
			
		||||
			/*CAPS_DEBUG("Socket::connect(%s:%d): %s",
 | 
			
		||||
			               hostname.c_str(), port, strerror(errno));*/
 | 
			
		||||
			close();
 | 
			
		||||
			return errno == ETIMEDOUT?Timeout:ConnectError;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	if ( ::connect(_fd, (struct sockaddr *)&addr, addrlen) == SOCKET_ERROR ) {
 | 
			
		||||
		int err = WSAGetLastError();
 | 
			
		||||
		if (err != WSAEINPROGRESS && err != WSAEWOULDBLOCK) {
 | 
			
		||||
			CAPS_DEBUG("Socket::connect(%s:%d): %s",
 | 
			
		||||
			            hostname.c_str(), port, gai_strerror(err));
 | 
			
		||||
			close();
 | 
			
		||||
			return ConnectError;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return Success;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
int Socket::send(const char *data) {
 | 
			
		||||
	return write(data, strlen(data));
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
int Socket::write(const char *data, int len) {
 | 
			
		||||
#if !defined(MACOSX) && !defined(WIN32)
 | 
			
		||||
	int sent = (int)::send(_fd, data, len, MSG_NOSIGNAL);
 | 
			
		||||
#else
 | 
			
		||||
	int sent = (int)::send(_fd, data, len, 0);
 | 
			
		||||
#endif
 | 
			
		||||
	if ( sent > 0 ) {
 | 
			
		||||
		_bytesSent += sent;
 | 
			
		||||
	}
 | 
			
		||||
	return sent;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
int Socket::read(char *data, int len) {
 | 
			
		||||
	int recvd = (int)::recv(_fd, data, len, 0);
 | 
			
		||||
	if ( recvd > 0 ) _bytesReceived += recvd;
 | 
			
		||||
	return recvd;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
int Socket::flush() { return 1; }
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
bool Socket::isValid() {
 | 
			
		||||
	return _fd != -1;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
SSLSocket::SSLSocket() : _ssl(NULL), _ctx(NULL) {}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
SSLSocket::SSLSocket(SSL_CTX *ctx) : _ssl(NULL), _ctx(ctx) {}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
SSLSocket::~SSLSocket() {
 | 
			
		||||
	close();
 | 
			
		||||
	cleanUp();
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
int SSLSocket::write(const char *data, int len) {
 | 
			
		||||
	int ret = SSL_write(_ssl, data, len);
 | 
			
		||||
	if ( ret > 0 ) {
 | 
			
		||||
		_bytesSent += ret;
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int err = SSL_get_error(_ssl, ret);
 | 
			
		||||
 | 
			
		||||
	switch ( err ) {
 | 
			
		||||
		case SSL_ERROR_WANT_X509_LOOKUP:
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
			return -1;
 | 
			
		||||
		case SSL_ERROR_WANT_READ:
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
			return -1;
 | 
			
		||||
		case SSL_ERROR_WANT_WRITE:
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
			return -1;
 | 
			
		||||
		case SSL_ERROR_ZERO_RETURN:
 | 
			
		||||
			errno = EINVAL;
 | 
			
		||||
			return 0;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
int SSLSocket::read(char *data, int len) {
 | 
			
		||||
	int ret = SSL_read(_ssl, data, len);
 | 
			
		||||
	if ( ret > 0 ) {
 | 
			
		||||
		_bytesReceived += ret;
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int err = SSL_get_error(_ssl, ret);
 | 
			
		||||
 | 
			
		||||
	switch ( err ) {
 | 
			
		||||
		case SSL_ERROR_WANT_X509_LOOKUP:
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
			return -1;
 | 
			
		||||
		case SSL_ERROR_WANT_READ:
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
			return -1;
 | 
			
		||||
		case SSL_ERROR_WANT_WRITE:
 | 
			
		||||
			errno = EAGAIN;
 | 
			
		||||
			return -1;
 | 
			
		||||
		case SSL_ERROR_ZERO_RETURN:
 | 
			
		||||
			errno = EINVAL;
 | 
			
		||||
			return 0;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
Socket::Status SSLSocket::connect(const std::string &hostname, uint16_t port) {
 | 
			
		||||
	cleanUp();
 | 
			
		||||
 | 
			
		||||
	_ctx = SSL_CTX_new(SSLv23_client_method());
 | 
			
		||||
	if ( _ctx == NULL ) {
 | 
			
		||||
		CAPS_DEBUG("Invalid SSL context");
 | 
			
		||||
		return ConnectError;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SSL_CTX_set_mode(_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
 | 
			
		||||
 | 
			
		||||
	Status s = Socket::connect(hostname, port);
 | 
			
		||||
	if ( s != Success )
 | 
			
		||||
		return s;
 | 
			
		||||
 | 
			
		||||
	_ssl = SSL_new(_ctx);
 | 
			
		||||
	if ( _ssl == NULL ) {
 | 
			
		||||
		CAPS_DEBUG("Failed to create SSL context");
 | 
			
		||||
		return ConnectError;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SSL_set_fd(_ssl, _fd);
 | 
			
		||||
	SSL_set_shutdown(_ssl, 0);
 | 
			
		||||
	SSL_set_connect_state(_ssl);
 | 
			
		||||
	int err = SSL_connect(_ssl);
 | 
			
		||||
	if ( err < 0 ) {
 | 
			
		||||
		CAPS_ERROR("Failed to connect with SSL, error %d",
 | 
			
		||||
		           SSL_get_error(_ssl, err));
 | 
			
		||||
		close();
 | 
			
		||||
		return ConnectError;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Success;
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
const unsigned char *SSLSocket::sessionID() const {
 | 
			
		||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
 | 
			
		||||
	return _ssl?_ssl->session->session_id:NULL;
 | 
			
		||||
#else
 | 
			
		||||
	return _ssl?SSL_SESSION_get0_id_context(SSL_get0_session(_ssl), NULL):NULL;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
unsigned int SSLSocket::sessionIDLength() const {
 | 
			
		||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
 | 
			
		||||
	return _ssl?_ssl->session->session_id_length:0;
 | 
			
		||||
#else
 | 
			
		||||
	unsigned int len;
 | 
			
		||||
	if ( !_ssl ) return 0;
 | 
			
		||||
	SSL_SESSION_get0_id_context(SSL_get0_session(_ssl), &len);
 | 
			
		||||
	return len;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
X509 *SSLSocket::peerCertificate() {
 | 
			
		||||
	if ( _ssl == NULL ) return NULL;
 | 
			
		||||
	return SSL_get_peer_certificate(_ssl);
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
void SSLSocket::cleanUp() {
 | 
			
		||||
	if ( _ssl ) {
 | 
			
		||||
		SSL_free(_ssl);
 | 
			
		||||
		_ssl = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( _ctx ) {
 | 
			
		||||
		SSL_CTX_free(_ctx);
 | 
			
		||||
		_ctx = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										273
									
								
								libs/gempa/caps/socket.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								libs/gempa/caps/socket.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,273 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2013 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_SOCKET_H
 | 
			
		||||
#define GEMPA_CAPS_SOCKET_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
#include <boost/shared_ptr.hpp>
 | 
			
		||||
 | 
			
		||||
#include <openssl/ssl.h>
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
namespace Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class SC_GEMPA_CAPS_API Socket {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef uint64_t count_t;
 | 
			
		||||
 | 
			
		||||
		enum Status {
 | 
			
		||||
			Success = 0,
 | 
			
		||||
			Error,
 | 
			
		||||
			AllocationError,
 | 
			
		||||
			ReuseAdressError,
 | 
			
		||||
			BindError,
 | 
			
		||||
			ListenError,
 | 
			
		||||
			AcceptError,
 | 
			
		||||
			ConnectError,
 | 
			
		||||
			AddrInfoError,
 | 
			
		||||
			Timeout,
 | 
			
		||||
			InvalidSocket,
 | 
			
		||||
			InvalidPort,
 | 
			
		||||
			InvalidAddressFamily,
 | 
			
		||||
			InvalidAddress,
 | 
			
		||||
			InvalidHostname
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		struct Device {
 | 
			
		||||
			enum Status {
 | 
			
		||||
				Success = 0,
 | 
			
		||||
				Error,
 | 
			
		||||
				InvalidDevice,
 | 
			
		||||
				AllocationError
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		Socket();
 | 
			
		||||
		virtual ~Socket();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		static const char *toString(Status);
 | 
			
		||||
 | 
			
		||||
		int fd() { return _fd; }
 | 
			
		||||
 | 
			
		||||
		bool isValid();
 | 
			
		||||
 | 
			
		||||
		void shutdown();
 | 
			
		||||
		void close();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		int send(const char *data);
 | 
			
		||||
 | 
			
		||||
		virtual int write(const char *data, int len);
 | 
			
		||||
		virtual int read(char *data, int len);
 | 
			
		||||
		virtual int flush();
 | 
			
		||||
 | 
			
		||||
		//! Sets the socket timeout. This utilizes setsockopt which does not
 | 
			
		||||
		//! work in non blocking sockets.
 | 
			
		||||
		Status setSocketTimeout(int secs, int usecs);
 | 
			
		||||
 | 
			
		||||
		Device::Status setNonBlocking(bool nb);
 | 
			
		||||
 | 
			
		||||
		virtual Status connect(const std::string &hostname, uint16_t port);
 | 
			
		||||
 | 
			
		||||
		count_t rx() const { return _bytesReceived; }
 | 
			
		||||
		count_t tx() const { return _bytesSent; }
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		Status applySocketTimeout(int secs, int usecs);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		int         _fd;
 | 
			
		||||
 | 
			
		||||
		count_t     _bytesSent;
 | 
			
		||||
		count_t     _bytesReceived;
 | 
			
		||||
 | 
			
		||||
		int         _timeOutSecs;
 | 
			
		||||
		int         _timeOutUsecs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef boost::shared_ptr<Socket> SocketPtr;
 | 
			
		||||
 | 
			
		||||
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
 | 
			
		||||
 | 
			
		||||
class SSLSocket : public Socket {
 | 
			
		||||
	public:
 | 
			
		||||
		SSLSocket();
 | 
			
		||||
		SSLSocket(SSL_CTX *ctx);
 | 
			
		||||
		~SSLSocket();
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		int write(const char *data, int len);
 | 
			
		||||
		int read(char *data, int len);
 | 
			
		||||
 | 
			
		||||
		Status connect(const std::string &hostname, uint16_t port);
 | 
			
		||||
 | 
			
		||||
		virtual const unsigned char *sessionID() const;
 | 
			
		||||
		virtual unsigned int sessionIDLength() const;
 | 
			
		||||
 | 
			
		||||
		X509 *peerCertificate();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void cleanUp();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		SSL     *_ssl;
 | 
			
		||||
		SSL_CTX *_ctx;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef boost::shared_ptr<SSLSocket> SSLSocketPtr;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
template <typename T, int N>
 | 
			
		||||
class socketbuf : public std::streambuf {
 | 
			
		||||
	public:
 | 
			
		||||
		socketbuf() {
 | 
			
		||||
			setsocket(NULL);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		socketbuf(T *sock) {
 | 
			
		||||
			setsocket(sock);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void setsocket(T *sock) {
 | 
			
		||||
			_allowed_reads = -1;
 | 
			
		||||
			_real_buffer_size = 0;
 | 
			
		||||
			_block_write = false;
 | 
			
		||||
			setg(_in, _in, _in);
 | 
			
		||||
			setp(_out, _out + N);
 | 
			
		||||
			_sock = sock;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void settimeout(const struct timeval &tv) {
 | 
			
		||||
			_timeout = tv;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void set_read_limit(int bytes) {
 | 
			
		||||
			_allowed_reads = bytes;
 | 
			
		||||
 | 
			
		||||
			if ( _allowed_reads >= 0 ) {
 | 
			
		||||
				if ( egptr() - gptr() > _allowed_reads )
 | 
			
		||||
					setg(eback(), gptr(), gptr() + _allowed_reads);
 | 
			
		||||
 | 
			
		||||
				// Set the number of read bytes to the
 | 
			
		||||
				// remaining bytes in the buffer
 | 
			
		||||
				_allowed_reads -= egptr() - gptr();
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				setg(eback(), gptr(), eback() + _real_buffer_size);
 | 
			
		||||
 | 
			
		||||
			//std::cout << "[" << (void*)eback() << ", " << (void*)gptr() << ", " << (void*)egptr() << "]" << " = " << (egptr() - gptr()) << std::endl;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int read_limit() const {
 | 
			
		||||
			if ( _allowed_reads < 0 ) return -1;
 | 
			
		||||
			return egptr() - gptr() + _allowed_reads;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	protected:
 | 
			
		||||
		virtual int underflow() {
 | 
			
		||||
			// No more reads allowed?
 | 
			
		||||
			if ( !_allowed_reads )
 | 
			
		||||
				return traits_type::eof();
 | 
			
		||||
 | 
			
		||||
			// Read available data from socket
 | 
			
		||||
			int res = _sock->read(_in, N);
 | 
			
		||||
			if ( res <= 0 ) {
 | 
			
		||||
				set_read_limit(0);
 | 
			
		||||
				return traits_type::eof();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Set input sequence pointers
 | 
			
		||||
			_real_buffer_size = res;
 | 
			
		||||
			setg(_in, _in, _in + _real_buffer_size);
 | 
			
		||||
 | 
			
		||||
			// clip to limit
 | 
			
		||||
			set_read_limit(_allowed_reads);
 | 
			
		||||
 | 
			
		||||
			return traits_type::to_int_type(*gptr());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual int overflow(int c) {
 | 
			
		||||
			if ( _block_write ) return traits_type::eof();
 | 
			
		||||
 | 
			
		||||
			if ( pptr() - pbase() == N ) {
 | 
			
		||||
				if ( sync() != 0 ) return traits_type::eof();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ( !traits_type::eq_int_type(traits_type::eof(), c)) {
 | 
			
		||||
				   traits_type::assign(*pptr(), traits_type::to_char_type(c));
 | 
			
		||||
 | 
			
		||||
				   pbump(1);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return traits_type::not_eof(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual int sync() {
 | 
			
		||||
			if ( pbase() == pptr() ) return 0;
 | 
			
		||||
 | 
			
		||||
			int res = _sock->write(pbase(), pptr() - pbase());
 | 
			
		||||
			if ( res == pptr() - pbase() ) {
 | 
			
		||||
				setp(_out, _out + N);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Only forward seeking is supported
 | 
			
		||||
		virtual std::streampos
 | 
			
		||||
		seekoff(std::streamoff off, std::ios_base::seekdir way,
 | 
			
		||||
		        std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) {
 | 
			
		||||
			if ( way != std::ios_base::cur || which != std::ios_base::in || off < 0 )
 | 
			
		||||
				return -1;
 | 
			
		||||
 | 
			
		||||
			while ( off > 0 ) {
 | 
			
		||||
				int ch = sbumpc();
 | 
			
		||||
				if ( ch == traits_type::eof() )
 | 
			
		||||
					return -1;
 | 
			
		||||
				--off;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		T       *_sock;
 | 
			
		||||
		timeval  _timeout;
 | 
			
		||||
		char     _in[N];
 | 
			
		||||
		char     _out[N];
 | 
			
		||||
		bool     _block_write;
 | 
			
		||||
		int      _real_buffer_size;
 | 
			
		||||
		int      _allowed_reads;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1009
									
								
								libs/gempa/caps/strptime.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1009
									
								
								libs/gempa/caps/strptime.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										22
									
								
								libs/gempa/caps/strptime.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								libs/gempa/caps/strptime.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 *   Copyright (C) by GFZ Potsdam                                          *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 *   You can redistribute and/or modify this program under the             *
 | 
			
		||||
 *   terms of the SeisComP Public License.                                 *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 *   This program is distributed in the hope that it will be useful,       *
 | 
			
		||||
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 | 
			
		||||
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 | 
			
		||||
 *   SeisComP Public License for more details.                             *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef STRPTIME_H
 | 
			
		||||
#define STRPTIME_H
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Version of "strptime()", for the benefit of OSes that don't have it.
 | 
			
		||||
 */
 | 
			
		||||
extern char *strptime(const char *, const char *, struct tm *);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										23
									
								
								libs/gempa/caps/test/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								libs/gempa/caps/test/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
SET(TESTS
 | 
			
		||||
	datetime.cpp
 | 
			
		||||
	rawpacket.cpp
 | 
			
		||||
	packet.cpp
 | 
			
		||||
	utils.cpp
 | 
			
		||||
	datetime_time.cpp
 | 
			
		||||
	endianess.cpp
 | 
			
		||||
	mseedpacket.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
FOREACH(testSrc ${TESTS})
 | 
			
		||||
	GET_FILENAME_COMPONENT(testName ${testSrc} NAME_WE)
 | 
			
		||||
	SET(testName test_caps_${testName})
 | 
			
		||||
	ADD_EXECUTABLE(${testName} ${testSrc})
 | 
			
		||||
	SC_LINK_LIBRARIES_INTERNAL(${testName} unittest)
 | 
			
		||||
	SC_LINK_LIBRARIES(${testName} ${CURL_LIBRARIES} caps_client)
 | 
			
		||||
 | 
			
		||||
	ADD_TEST(
 | 
			
		||||
		NAME ${testName}
 | 
			
		||||
		WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
 | 
			
		||||
		COMMAND ${testName}
 | 
			
		||||
	)
 | 
			
		||||
ENDFOREACH(testSrc)
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								libs/gempa/caps/test/data/AM.RFE4F.00.SHZ.20180912.mseed
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/gempa/caps/test/data/AM.RFE4F.00.SHZ.20180912.mseed
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										566
									
								
								libs/gempa/caps/test/datetime.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										566
									
								
								libs/gempa/caps/test/datetime.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,566 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gc = Gempa::CAPS;
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool isClose(gc::TimeSpan time, long sec, long micro, int offset = 1) {
 | 
			
		||||
	long microSeconds = time.microseconds();
 | 
			
		||||
 | 
			
		||||
	long secDiff = time.seconds() - sec;
 | 
			
		||||
	if ( secDiff > 0 )
 | 
			
		||||
		microSeconds += secDiff * 1000000;
 | 
			
		||||
	else if ( secDiff < 0 )
 | 
			
		||||
		micro += abs(secDiff) * 1000000;
 | 
			
		||||
 | 
			
		||||
	if ( abs(microSeconds - micro) <= offset )
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_datetime)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(construction) {
 | 
			
		||||
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	struct timeval tvPositive;
 | 
			
		||||
	tvPositive.tv_sec = 60000;
 | 
			
		||||
	tvPositive.tv_usec = 123456;
 | 
			
		||||
	gc::TimeSpan k(tvPositive);
 | 
			
		||||
	BOOST_CHECK(k.seconds() == tvPositive.tv_sec);
 | 
			
		||||
	BOOST_CHECK(k.microseconds() == tvPositive.tv_usec);
 | 
			
		||||
 | 
			
		||||
	struct timeval tvNegativeUsec;
 | 
			
		||||
	tvNegativeUsec.tv_sec = 300;
 | 
			
		||||
	tvNegativeUsec.tv_usec = -13456;
 | 
			
		||||
	gc::TimeSpan ki(tvNegativeUsec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ki.seconds() , tvNegativeUsec.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ki.microseconds() , tvNegativeUsec.tv_usec);
 | 
			
		||||
 | 
			
		||||
	struct timeval tvNegativeSec;
 | 
			
		||||
	tvNegativeSec.tv_sec = -300;
 | 
			
		||||
	tvNegativeSec.tv_usec = 13456;
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan kj(tvNegativeSec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kj.seconds() , tvNegativeSec.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kj.microseconds() , tvNegativeSec.tv_usec);
 | 
			
		||||
 | 
			
		||||
	struct timeval tvNegative;
 | 
			
		||||
	tvNegative.tv_sec = -3000;
 | 
			
		||||
	tvNegative.tv_usec = -123456;
 | 
			
		||||
	gc::TimeSpan kk(tvNegative);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kk.seconds() , tvNegative.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kk.microseconds() , tvNegative.tv_usec);
 | 
			
		||||
 | 
			
		||||
	struct timeval tvNull;
 | 
			
		||||
	gc::TimeSpan kl(tvNull);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kl.seconds() , tvNull.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kl.microseconds() , tvNull.tv_usec);
 | 
			
		||||
 | 
			
		||||
	// copy
 | 
			
		||||
	gc::TimeSpan copyPositive(gc::TimeSpan(79743.123456));
 | 
			
		||||
	BOOST_CHECK(copyPositive.seconds() == 79743);
 | 
			
		||||
	BOOST_CHECK(copyPositive.microseconds() == 123456);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan copyNegative(gc::TimeSpan(-98765.123456));
 | 
			
		||||
	long sec = -98765;
 | 
			
		||||
	long micro = -123456;
 | 
			
		||||
	BOOST_CHECK(isClose(copyNegative, sec, micro,20) == true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan copyNegativeTest(gc::TimeSpan(-98765.000070));
 | 
			
		||||
	sec = -98765 ;
 | 
			
		||||
	micro = 70;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(copyNegativeTest,sec, micro,500), true);
 | 
			
		||||
 | 
			
		||||
	// long
 | 
			
		||||
	gc::TimeSpan longPositive(765432, 456789);
 | 
			
		||||
	BOOST_CHECK(longPositive.seconds() == 765432);
 | 
			
		||||
	BOOST_CHECK(longPositive.microseconds() == 456789);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan longNegativeUsec(200, -732);
 | 
			
		||||
	BOOST_CHECK_EQUAL(longNegativeUsec.seconds(), 200);
 | 
			
		||||
	BOOST_CHECK_EQUAL(longNegativeUsec.microseconds(), -732);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan longNegativeSec(-800, 73265);
 | 
			
		||||
	BOOST_CHECK_EQUAL(longNegativeSec.seconds(), -800);
 | 
			
		||||
	BOOST_CHECK_EQUAL(longNegativeSec.microseconds(), 73265);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan longNegative(-500, -732650);
 | 
			
		||||
	BOOST_CHECK_EQUAL(longNegative.seconds(), -500);
 | 
			
		||||
	BOOST_CHECK_EQUAL(longNegative.microseconds(), -732650);
 | 
			
		||||
 | 
			
		||||
	// double
 | 
			
		||||
	double number = 123456.98765;
 | 
			
		||||
	gc::TimeSpan doublePositive(number);
 | 
			
		||||
	BOOST_CHECK_EQUAL(doublePositive.seconds(), 123456);
 | 
			
		||||
	BOOST_CHECK_EQUAL(doublePositive.microseconds(), 987650);
 | 
			
		||||
 | 
			
		||||
	number = -98765.123470;
 | 
			
		||||
	gc::TimeSpan doubleNegative(number);
 | 
			
		||||
	BOOST_CHECK_EQUAL(doubleNegative.seconds(), -98765);
 | 
			
		||||
	BOOST_CHECK_CLOSE((double)doubleNegative.microseconds(), -123470, 0.01);
 | 
			
		||||
 | 
			
		||||
	number = -98765.000080;
 | 
			
		||||
	gc::TimeSpan doubleNegativeTest(number);
 | 
			
		||||
	sec = -98765;
 | 
			
		||||
	micro = 80;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(doubleNegativeTest,sec, micro,500), true);
 | 
			
		||||
 | 
			
		||||
	// pointer
 | 
			
		||||
	timeval n;
 | 
			
		||||
	n.tv_sec = 123;
 | 
			
		||||
	n.tv_usec = 123456;
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan pointerPositive(&n);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerPositive.seconds(), 123);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerPositive.microseconds(), 123456);
 | 
			
		||||
 | 
			
		||||
	n.tv_sec = -123;
 | 
			
		||||
	n.tv_usec = 123456;
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan pointerNegativeSec(&n);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNegativeSec.seconds(), -123);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNegativeSec.microseconds(), 123456);
 | 
			
		||||
 | 
			
		||||
	n.tv_sec = 123;
 | 
			
		||||
	n.tv_usec = -123456;
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan pointerNegativeUsec(&n);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNegativeUsec.seconds(), 123);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNegativeUsec.microseconds(), -123456);
 | 
			
		||||
 | 
			
		||||
	n.tv_sec = -123;
 | 
			
		||||
	n.tv_usec = -123456;
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan pointerNegative(&n);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNegative.seconds(), -123);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNegative.microseconds(), -123456);
 | 
			
		||||
 | 
			
		||||
	timeval *nullPointer = NULL;
 | 
			
		||||
	gc::TimeSpan pointerNull(nullPointer);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNull.seconds(), 0);
 | 
			
		||||
	BOOST_CHECK_EQUAL(pointerNull.microseconds(), 0);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(addition) {
 | 
			
		||||
	gc::TimeSpan k = 5, l = 7;
 | 
			
		||||
	BOOST_CHECK(k + l  == gc::TimeSpan(12));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan m = 320.5, n = 60.2;
 | 
			
		||||
	BOOST_CHECK(m + n  == gc::TimeSpan(380.7));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan g = 55, d = -50;
 | 
			
		||||
	BOOST_CHECK(d + g  == gc::TimeSpan(5));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t = -80.0053, s = -70.0044;
 | 
			
		||||
	gc::TimeSpan result = t + s;
 | 
			
		||||
	long sec = t.seconds() + s.seconds();
 | 
			
		||||
	long micro = t.microseconds() + s.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result, sec,micro),true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan u = -5.035, v = -60.044;
 | 
			
		||||
	result = u + v;
 | 
			
		||||
	sec = u.seconds() + v.seconds();
 | 
			
		||||
	micro = u.microseconds() + v.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan w = -5.0885, x = -6.01111;
 | 
			
		||||
	result = w + x;
 | 
			
		||||
	sec = w.seconds() + x.seconds();
 | 
			
		||||
	micro = w.microseconds() + x.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,sec, micro), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(subtraction) {
 | 
			
		||||
	gc::TimeSpan k = 5, l = 6;
 | 
			
		||||
	BOOST_CHECK(k - l == gc::TimeSpan(-1));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t = 58, i = 68.05;
 | 
			
		||||
	gc::TimeSpan result = t - i;
 | 
			
		||||
	long sec = t.seconds() - i.seconds();
 | 
			
		||||
	long micro = t.microseconds() - i.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan e(30,4);
 | 
			
		||||
	gc::TimeSpan o(45,3);
 | 
			
		||||
	result = e - o;
 | 
			
		||||
	sec = e.seconds() - o.seconds();
 | 
			
		||||
	micro = e.microseconds() - o.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan f = 30.00004, g = -45.00003;
 | 
			
		||||
	result = f - g;
 | 
			
		||||
	sec = f.seconds() - g.seconds();
 | 
			
		||||
	micro = f.microseconds() - g.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,sec, micro), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(setSec) {
 | 
			
		||||
	gc::TimeSpan h, k, l;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h.set(4), gc::TimeSpan(4));
 | 
			
		||||
	BOOST_CHECK_EQUAL(k.set(2), gc::TimeSpan(2));
 | 
			
		||||
	BOOST_CHECK_EQUAL(l.set(1), gc::TimeSpan(1));
 | 
			
		||||
	BOOST_CHECK_EQUAL(l.set(-10), gc::TimeSpan(-10));
 | 
			
		||||
	BOOST_CHECK_EQUAL(k.set(-9876), gc::TimeSpan(-9876));
 | 
			
		||||
	BOOST_CHECK_EQUAL(l.set(0), gc::TimeSpan(0.));
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(setMicro) {
 | 
			
		||||
	gc::TimeSpan h, k, l, ts;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h.setUSecs(9), gc::TimeSpan(0.000009));
 | 
			
		||||
	BOOST_CHECK_EQUAL(k.setUSecs(2), gc::TimeSpan(0.0000020));
 | 
			
		||||
	BOOST_CHECK_EQUAL(l.setUSecs(3), gc::TimeSpan(0.000003));
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.setUSecs(4), gc::TimeSpan(0.000004));
 | 
			
		||||
	BOOST_CHECK_EQUAL(l.setUSecs(0), gc::TimeSpan(0.0));
 | 
			
		||||
	BOOST_CHECK_EQUAL(h.setUSecs(2000000), gc::TimeSpan(2.00));
 | 
			
		||||
	BOOST_CHECK_EQUAL(k.setUSecs(-3000000), gc::TimeSpan(-3.0));
 | 
			
		||||
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan test = l.setUSecs(-7262);
 | 
			
		||||
	BOOST_WARN_EQUAL(test.microseconds(), -7262);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan test2 = l.setUSecs(-98744);
 | 
			
		||||
	BOOST_WARN_EQUAL(test2.microseconds(), -98744);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan test3 = l.setUSecs(-98);
 | 
			
		||||
	BOOST_WARN_EQUAL(isClose(test3,0, -98), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(secAndMicro) {
 | 
			
		||||
	gc::TimeSpan ts(2.000002);
 | 
			
		||||
	BOOST_CHECK(ts.seconds() == 2 && ts.microseconds() == 2);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h(4.000009);
 | 
			
		||||
	BOOST_CHECK(h.seconds() == 4 && h.microseconds()  == 9);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t(0.000004);
 | 
			
		||||
	BOOST_CHECK(t.seconds() == 0 && t.microseconds()  == 4);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan k(0.000000);
 | 
			
		||||
	BOOST_CHECK(k.seconds() == 0 && k.microseconds()  == 0);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan m(-8.123456);
 | 
			
		||||
	long sec =  -8;
 | 
			
		||||
	long micro = -123456;
 | 
			
		||||
	BOOST_WARN_EQUAL(isClose(m,sec, micro,20), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(absolute) {
 | 
			
		||||
	gc::TimeSpan k(-2.567);
 | 
			
		||||
	gc::TimeSpan result = k.abs();
 | 
			
		||||
	long sec = result.seconds();
 | 
			
		||||
	long micro = result.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,2, 567000,20), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan m(-2, -5);
 | 
			
		||||
	gc::TimeSpan n(2, 5);
 | 
			
		||||
	BOOST_CHECK_EQUAL(m.abs(), n.abs());
 | 
			
		||||
	BOOST_CHECK_EQUAL(m.abs(), n);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan i(600, -700000);
 | 
			
		||||
	result = i.abs();
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 600);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(),700000);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan r(200, -5);
 | 
			
		||||
	gc::TimeSpan s(200.000005);
 | 
			
		||||
	gc::TimeSpan absR = r.abs();
 | 
			
		||||
	BOOST_CHECK_EQUAL(r.abs(), s.abs());
 | 
			
		||||
	BOOST_CHECK_EQUAL(absR.seconds(), s.seconds());
 | 
			
		||||
	BOOST_CHECK_EQUAL(absR.microseconds(), s.microseconds());
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan l = (double)-1.000678;
 | 
			
		||||
	result = l.abs();
 | 
			
		||||
	sec = 1;
 | 
			
		||||
	micro = 678;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result,sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = -4;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h.abs(), gc::TimeSpan(4));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts;
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.abs(), gc::TimeSpan(0.0));
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(length) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002;
 | 
			
		||||
	BOOST_CHECK(k.length() == 2.000002);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan l = 1.000003;
 | 
			
		||||
	BOOST_CHECK(l.length() == 1.000003);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009;
 | 
			
		||||
	BOOST_CHECK(h.length() == 4.000009);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(notEqual) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002, l = 1.000003;
 | 
			
		||||
	BOOST_CHECK(k != l);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts, t = 0.000007;
 | 
			
		||||
	BOOST_CHECK(ts != t);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009, j = 2845687.000004;
 | 
			
		||||
	BOOST_CHECK(h != j);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(assign) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002;
 | 
			
		||||
	BOOST_CHECK(k == gc::TimeSpan(2.000002));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t;
 | 
			
		||||
	BOOST_CHECK(t  == gc::TimeSpan(0.0));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009;
 | 
			
		||||
	BOOST_CHECK(h  == gc::TimeSpan(4.000009));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts = 0.000004;
 | 
			
		||||
	BOOST_CHECK(ts == gc::TimeSpan(0.000004));
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(plus) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002, l = 1.000003;
 | 
			
		||||
	BOOST_CHECK_EQUAL(k += l, gc::TimeSpan(3.000005));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009, t;
 | 
			
		||||
	BOOST_CHECK_EQUAL(t += h, gc::TimeSpan(4.000009));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts = 0.000004, j = 80005.000004;
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts += j, gc::TimeSpan(80005.000008));
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(minus) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002, l = 1.000003;
 | 
			
		||||
	BOOST_CHECK_EQUAL(k -= l, gc::TimeSpan(0.999999));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t, j = 6897.098772;
 | 
			
		||||
	BOOST_CHECK_EQUAL(j -= t, gc::TimeSpan(6897.098772));
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009, ts = 0.000004;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h -= ts, gc::TimeSpan(4.000005));
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(lower) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002, t;
 | 
			
		||||
	BOOST_CHECK_EQUAL(t < k, true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009, j = 2.897665;
 | 
			
		||||
	BOOST_CHECK_EQUAL(j < h, true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts = 0.000004, z = 7893648.987645;
 | 
			
		||||
	BOOST_CHECK_EQUAL(z < ts, false);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(greater) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002, t;
 | 
			
		||||
	BOOST_CHECK_EQUAL(k > t, true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009, j = 3.909888;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h > j, true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts = 0.000004, g = 0.000001;
 | 
			
		||||
	BOOST_CHECK_EQUAL(g > ts, false);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(lowerEqual) {
 | 
			
		||||
	gc::TimeSpan k = 2.000002;
 | 
			
		||||
	BOOST_CHECK_EQUAL(k <= gc::TimeSpan(2.000002), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t;
 | 
			
		||||
	BOOST_CHECK_EQUAL(t <= gc::TimeSpan(2), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan h = 4.000009;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h <= gc::TimeSpan(2), false);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(greaterEqual) {
 | 
			
		||||
	gc::TimeSpan h = 4.000009;
 | 
			
		||||
	BOOST_CHECK_EQUAL(h >= gc::TimeSpan(2), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts = 0.000004;
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts >= gc::TimeSpan(0.000001), true);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan k = 2.000002;
 | 
			
		||||
	BOOST_CHECK_EQUAL(k >= gc::TimeSpan(2.000002), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(inDouble) {
 | 
			
		||||
	gc::TimeSpan k = 6.000003;
 | 
			
		||||
	double kd = k.operator double();
 | 
			
		||||
	BOOST_CHECK_EQUAL(kd, 6.000003);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan t = 0.000008;
 | 
			
		||||
	double td = t.operator double();
 | 
			
		||||
	BOOST_CHECK_EQUAL(td, 0.000008);
 | 
			
		||||
 | 
			
		||||
	gc::TimeSpan ts = 2.000004;
 | 
			
		||||
	double tsd = ts.operator double();
 | 
			
		||||
	BOOST_CHECK_EQUAL(tsd, 2.000004);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(toTimeval) {
 | 
			
		||||
	const timeval tv = gc::Time(6.000003);
 | 
			
		||||
	gc::TimeSpan k = 6.000003;
 | 
			
		||||
	timeval kv = k.operator const timeval &();
 | 
			
		||||
	BOOST_CHECK_EQUAL(kv.tv_sec, tv.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(kv.tv_usec, tv.tv_usec);
 | 
			
		||||
 | 
			
		||||
	const timeval ti = gc::Time(0.000008);
 | 
			
		||||
	gc::TimeSpan t = 0.000008;
 | 
			
		||||
	timeval tvi = t.operator const timeval &();
 | 
			
		||||
	BOOST_CHECK_EQUAL(tvi.tv_sec, ti.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(tvi.tv_usec, ti.tv_usec);
 | 
			
		||||
 | 
			
		||||
	const timeval tl = gc::Time(2.000004);
 | 
			
		||||
	gc::TimeSpan ts = 2.000004;
 | 
			
		||||
	timeval tsv = ts.operator const timeval &();
 | 
			
		||||
	BOOST_CHECK_EQUAL(tsv.tv_sec, tl.tv_sec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(tsv.tv_usec, tl.tv_usec);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(fromString) {
 | 
			
		||||
	gc::Time time = gc::Time::FromString("2019-01-01 10:01:59", "%F %T");
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK(time.valid());
 | 
			
		||||
 | 
			
		||||
	int year, month, day, hour, min, sec;
 | 
			
		||||
	BOOST_CHECK(time.get(&year, &month, &day, &hour, &min, &sec));
 | 
			
		||||
	BOOST_CHECK_EQUAL(year, 2019);
 | 
			
		||||
	BOOST_CHECK_EQUAL(month, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(hour, 10);
 | 
			
		||||
	BOOST_CHECK_EQUAL(min, 01);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sec, 59);
 | 
			
		||||
 | 
			
		||||
	// Buffer overflow test
 | 
			
		||||
	std::string str;
 | 
			
		||||
	str.resize(1024);
 | 
			
		||||
	time = gc::Time::FromString(str.c_str(), "%F %T");
 | 
			
		||||
	BOOST_CHECK(!time.valid());
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										511
									
								
								libs/gempa/caps/test/datetime_time.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										511
									
								
								libs/gempa/caps/test/datetime_time.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,511 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gc = Gempa::CAPS;
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_datetime_time)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool isClose(gc::TimeSpan time, long sec, long micro, int offset = 1) {
 | 
			
		||||
	long microSeconds = time.microseconds();
 | 
			
		||||
 | 
			
		||||
	long secDiff = time.seconds() - sec;
 | 
			
		||||
	if ( secDiff > 0 )
 | 
			
		||||
		microSeconds += secDiff * 1000000;
 | 
			
		||||
	else if ( secDiff < 0 )
 | 
			
		||||
		micro += abs(secDiff) * 1000000;
 | 
			
		||||
 | 
			
		||||
	if ( abs(microSeconds - micro) <= offset )
 | 
			
		||||
		return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(construction) {
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	gc::Time time;
 | 
			
		||||
	BOOST_CHECK(time == gc::Time(0.0));
 | 
			
		||||
 | 
			
		||||
	// long
 | 
			
		||||
	gc::Time tPositive(200, 600);
 | 
			
		||||
	BOOST_CHECK(tPositive == gc::Time(200.000600));
 | 
			
		||||
 | 
			
		||||
	gc::Time tNegativeUsec(3000, -789);
 | 
			
		||||
	BOOST_WARN_EQUAL(tNegativeUsec.seconds(), 3000);
 | 
			
		||||
	BOOST_WARN_EQUAL(tNegativeUsec.microseconds(), -789);
 | 
			
		||||
 | 
			
		||||
	gc::Time tNegativeSec(-12, 12345);
 | 
			
		||||
	BOOST_WARN_EQUAL(tNegativeSec.seconds(), -12);
 | 
			
		||||
	BOOST_WARN_EQUAL(tNegativeSec.microseconds(), 12345);
 | 
			
		||||
 | 
			
		||||
	gc::Time tNegative(-15,-9876);
 | 
			
		||||
	BOOST_WARN_EQUAL(tNegative.seconds(), -15);
 | 
			
		||||
	BOOST_WARN_EQUAL(tNegative.microseconds(), -9876);
 | 
			
		||||
 | 
			
		||||
	// TimeSpan
 | 
			
		||||
	gc::Time tsPositive(gc::TimeSpan(5.345));
 | 
			
		||||
	BOOST_WARN_EQUAL(tsPositive.seconds(), 5);
 | 
			
		||||
	BOOST_WARN_EQUAL(tsPositive.microseconds(), 345000);
 | 
			
		||||
 | 
			
		||||
	// timeval
 | 
			
		||||
	timeval number;
 | 
			
		||||
	number.tv_sec = 150;
 | 
			
		||||
	number.tv_usec = 6000;
 | 
			
		||||
	gc::Time tvPositive(number);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvPositive.seconds(), 150);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvPositive.microseconds(), 6000);
 | 
			
		||||
 | 
			
		||||
	number.tv_sec = -150;
 | 
			
		||||
	number.tv_usec = 9000;
 | 
			
		||||
	gc::Time tvNegativeSec(number);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvNegativeSec.seconds(), -150);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvNegativeSec.microseconds(),9000);
 | 
			
		||||
 | 
			
		||||
	number.tv_sec = 4000;
 | 
			
		||||
	number.tv_usec = -98876;
 | 
			
		||||
	gc::Time tvNegativeUsec(number);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvNegativeUsec.seconds(), 4000);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvNegativeUsec.microseconds(), -98876);
 | 
			
		||||
 | 
			
		||||
	number.tv_sec = -9877;
 | 
			
		||||
	number.tv_usec = -874547;
 | 
			
		||||
	gc::Time tvNegative(number);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvNegative.seconds(), -9877);
 | 
			
		||||
	BOOST_WARN_EQUAL(tvNegative.microseconds(), -874547);
 | 
			
		||||
 | 
			
		||||
	// double
 | 
			
		||||
	double val = 5678.9864;
 | 
			
		||||
	gc::Time tdPositive(val);
 | 
			
		||||
	BOOST_WARN_EQUAL(tdPositive.seconds(), 5678);
 | 
			
		||||
	BOOST_CHECK_EQUAL(tdPositive.microseconds(), 986400);
 | 
			
		||||
 | 
			
		||||
	val = -89765.745377;
 | 
			
		||||
	gc::Time tdNegative(val);
 | 
			
		||||
	BOOST_WARN_EQUAL(isClose(tdNegative, -89765, -745377), true);
 | 
			
		||||
 | 
			
		||||
	// pointer
 | 
			
		||||
	timeval pointer;
 | 
			
		||||
	pointer.tv_sec = 76656;
 | 
			
		||||
	pointer.tv_usec = 8900;
 | 
			
		||||
 | 
			
		||||
	gc::Time tpPositive(&pointer);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpPositive.seconds(), 76656);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpPositive.microseconds(), 8900);
 | 
			
		||||
 | 
			
		||||
	pointer.tv_sec = -76656;
 | 
			
		||||
	pointer.tv_usec = 8900;
 | 
			
		||||
	gc::Time tpNegativeSec(&pointer);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpNegativeSec.seconds(), -76656);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpNegativeSec.microseconds(), 8900);
 | 
			
		||||
 | 
			
		||||
	pointer.tv_sec = 98744;
 | 
			
		||||
	pointer.tv_usec = -8965;
 | 
			
		||||
	gc::Time tpNegativeUsec(&pointer);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpNegativeUsec.seconds(), 98744);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpNegativeUsec.microseconds(), -8965);
 | 
			
		||||
 | 
			
		||||
	pointer.tv_sec = -44;
 | 
			
		||||
	pointer.tv_usec = -895;
 | 
			
		||||
	gc::Time tpNegative(&pointer);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpNegative.seconds(), -44);
 | 
			
		||||
	BOOST_WARN_EQUAL(tpNegative.microseconds(), -895);
 | 
			
		||||
 | 
			
		||||
	// copy
 | 
			
		||||
	gc::Time copyPositive(gc::Time(758.9975));
 | 
			
		||||
	BOOST_CHECK_EQUAL(copyPositive.seconds(), 758);
 | 
			
		||||
	BOOST_CHECK_EQUAL(copyPositive.microseconds(), 997500);
 | 
			
		||||
 | 
			
		||||
	gc::Time copyNegative(gc::Time(-877.963));
 | 
			
		||||
	BOOST_WARN_EQUAL(isClose(copyNegative, -877, -963000), true);
 | 
			
		||||
 | 
			
		||||
	// date
 | 
			
		||||
	gc::Time date(1971,1,3,1,1,4,6544);
 | 
			
		||||
	double dayInSeconds = 86400;
 | 
			
		||||
	double yearInSeconds = 31536000;
 | 
			
		||||
	BOOST_WARN_CLOSE(double(date), dayInSeconds*2 + yearInSeconds,0.3);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(addition) {
 | 
			
		||||
	gc::Time a(7,5);
 | 
			
		||||
	gc::TimeSpan b = 9.000004;
 | 
			
		||||
	gc::TimeSpan result = a + b;
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(), 9);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 16);
 | 
			
		||||
 | 
			
		||||
	gc::Time c(7,5);
 | 
			
		||||
	gc::TimeSpan d = -3.000004;
 | 
			
		||||
	result = c + d;
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(), 2);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 4);
 | 
			
		||||
 | 
			
		||||
	gc::Time e(-7,5);
 | 
			
		||||
	gc::TimeSpan f = 9.000004;
 | 
			
		||||
	result = e + f;
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(),9);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 2);
 | 
			
		||||
 | 
			
		||||
	gc::Time g(900,789);
 | 
			
		||||
	gc::TimeSpan h;
 | 
			
		||||
	result = h += g;
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(),789);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 900);
 | 
			
		||||
 | 
			
		||||
	gc::Time i(455, -355);
 | 
			
		||||
	gc::TimeSpan j = 80.000444;
 | 
			
		||||
	i += j;
 | 
			
		||||
	BOOST_CHECK_EQUAL(i.microseconds(),89);
 | 
			
		||||
	BOOST_CHECK_EQUAL(i.seconds(), 535);
 | 
			
		||||
 | 
			
		||||
	gc::Time k(-899, 22255);
 | 
			
		||||
	gc::TimeSpan l = 773.992;
 | 
			
		||||
	l += k;
 | 
			
		||||
	BOOST_WARN_EQUAL(l.seconds(), -125);
 | 
			
		||||
	BOOST_WARN_EQUAL(l.microseconds(), 14255);
 | 
			
		||||
 | 
			
		||||
	gc::Time m(500, 987);
 | 
			
		||||
	gc::TimeSpan n(-30, 876);
 | 
			
		||||
	int result2 = m.microseconds() + n.microseconds();
 | 
			
		||||
	int result3 = m.seconds() + n.seconds();
 | 
			
		||||
	m += n;
 | 
			
		||||
	BOOST_WARN_EQUAL(m.microseconds(),result2);
 | 
			
		||||
	BOOST_WARN_EQUAL(m.seconds(),result3);
 | 
			
		||||
 | 
			
		||||
	gc::Time o(-60, 47);
 | 
			
		||||
	gc::TimeSpan p(-44,5);
 | 
			
		||||
	long sec = o.seconds() + p.seconds();
 | 
			
		||||
	long micro = o.microseconds() + p.microseconds();
 | 
			
		||||
	o += p;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(o, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time q(9876, -6748);
 | 
			
		||||
	gc::TimeSpan r = -876.987;
 | 
			
		||||
	q += r;
 | 
			
		||||
	BOOST_WARN_EQUAL(q.microseconds(), 6253);
 | 
			
		||||
	BOOST_CHECK_EQUAL(q.seconds(),8999);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(subtraction) {
 | 
			
		||||
	gc::Time a(7,5);
 | 
			
		||||
	gc::TimeSpan b(9,000004);
 | 
			
		||||
	gc::TimeSpan result = a - b;
 | 
			
		||||
	long sec = a.seconds() - b.seconds();
 | 
			
		||||
	long micro = a.microseconds() - b.microseconds();
 | 
			
		||||
	BOOST_WARN_EQUAL(isClose(result, sec, micro),true);
 | 
			
		||||
 | 
			
		||||
	gc::Time c(7,5);
 | 
			
		||||
	gc::TimeSpan d = -3.000004;
 | 
			
		||||
	result = c - d;
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(), 8);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 10);
 | 
			
		||||
 | 
			
		||||
	gc::Time e(-7,5);
 | 
			
		||||
	gc::TimeSpan f(9,000004);
 | 
			
		||||
	result = e - f;
 | 
			
		||||
	sec = e.seconds() - f.seconds();
 | 
			
		||||
	micro = e.microseconds() -f.microseconds();
 | 
			
		||||
	BOOST_WARN_EQUAL(isClose(result, sec, micro),true);
 | 
			
		||||
 | 
			
		||||
	gc::Time g(900,789);
 | 
			
		||||
	gc::TimeSpan h;
 | 
			
		||||
	sec = h.seconds() - g.seconds();
 | 
			
		||||
	micro = h.microseconds() - g.microseconds();
 | 
			
		||||
	h -= g;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(h, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time i(455, -355);
 | 
			
		||||
	gc::TimeSpan j(80, 444);
 | 
			
		||||
	sec = i.seconds() - j.seconds();
 | 
			
		||||
	micro = i.microseconds() - j.microseconds();
 | 
			
		||||
	i -= j;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(i, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time k(-899, 22255);
 | 
			
		||||
	gc::TimeSpan l(773, 992);
 | 
			
		||||
	sec = l.seconds() - k.seconds();
 | 
			
		||||
	micro = l.microseconds() - k.microseconds();
 | 
			
		||||
	l -= k;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(l, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time m(500,987);
 | 
			
		||||
	gc::TimeSpan n = -30.876;
 | 
			
		||||
	m -= n;
 | 
			
		||||
	BOOST_CHECK_EQUAL(m.microseconds(),876986);
 | 
			
		||||
	BOOST_CHECK_EQUAL(m.seconds(), 530);
 | 
			
		||||
 | 
			
		||||
	gc::Time o(-60, 47);
 | 
			
		||||
	gc::TimeSpan p = -44.05;
 | 
			
		||||
	sec = o.seconds() - p.seconds();
 | 
			
		||||
	micro = o.microseconds() - p.microseconds();
 | 
			
		||||
	o -= p;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(o, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time q(9876, -6748);
 | 
			
		||||
	gc::TimeSpan r = -876.987;
 | 
			
		||||
	sec = q.seconds() -r.seconds();
 | 
			
		||||
	micro = q.microseconds() - r.microseconds();
 | 
			
		||||
	q -= r;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(q, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time s(50, 778), t(4, 221);
 | 
			
		||||
	result = s - t;
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.microseconds(), 557);
 | 
			
		||||
	BOOST_CHECK_EQUAL(result.seconds(), 46);
 | 
			
		||||
 | 
			
		||||
	gc::Time u(-30,0),v(60,66);
 | 
			
		||||
	result = u - v;
 | 
			
		||||
	sec = u.seconds() -v.seconds();
 | 
			
		||||
	micro = u.microseconds() - v.microseconds();
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result, sec, micro), true);
 | 
			
		||||
 | 
			
		||||
	gc::Time w(798, -444),x(6, 0321);
 | 
			
		||||
	sec = w.seconds() - x.seconds();
 | 
			
		||||
	micro = w.microseconds() - x.microseconds();
 | 
			
		||||
	result = w - x;
 | 
			
		||||
	BOOST_CHECK_EQUAL(isClose(result, sec, micro), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(setAndGet) {
 | 
			
		||||
	gc::Time date;
 | 
			
		||||
	gc::TimeSpan oneDay (86400); // one day in seconds
 | 
			
		||||
	gc::TimeSpan oneYear (31536000); // one year in seconds
 | 
			
		||||
	gc::TimeSpan toNextYear (26524800); // seconds to the next year
 | 
			
		||||
	int year = 1970, month = 8, day = 5,h = 7,min = 50,sec = 33,uSec= 80;
 | 
			
		||||
	date.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(date.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(year == 1970);
 | 
			
		||||
	BOOST_CHECK(month == 8);
 | 
			
		||||
	BOOST_CHECK(day == 5);
 | 
			
		||||
	BOOST_CHECK(h == 7);
 | 
			
		||||
	BOOST_CHECK(min = 50);
 | 
			
		||||
	BOOST_CHECK(sec = 33);
 | 
			
		||||
	BOOST_CHECK(uSec = 80);
 | 
			
		||||
 | 
			
		||||
	date -= oneYear;
 | 
			
		||||
	BOOST_CHECK(date.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(year == 1969);
 | 
			
		||||
	BOOST_CHECK(month == 8);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day , 5);
 | 
			
		||||
 | 
			
		||||
	year = 2017, month = 2, day = 28;
 | 
			
		||||
	date.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(date.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(year == 2017);
 | 
			
		||||
	BOOST_CHECK(month == 2);
 | 
			
		||||
	BOOST_CHECK(day == 28);
 | 
			
		||||
 | 
			
		||||
	date += oneDay;
 | 
			
		||||
	BOOST_CHECK(date.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(month , 3);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day , 1);
 | 
			
		||||
 | 
			
		||||
	year = 2018, month = 2, day = 28;
 | 
			
		||||
	date.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	date += oneDay;
 | 
			
		||||
	BOOST_CHECK(date.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(month , 3);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day, 1);
 | 
			
		||||
 | 
			
		||||
	date += oneYear;
 | 
			
		||||
	BOOST_CHECK(date.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year , 2019);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(month , 3);
 | 
			
		||||
 | 
			
		||||
	gc::Time leapYear;
 | 
			
		||||
	year = 1956, month = 2, day = 28;
 | 
			
		||||
	leapYear.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(leapYear.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(year == 1956);
 | 
			
		||||
	BOOST_CHECK(month == 2);
 | 
			
		||||
	BOOST_CHECK(day == 28);
 | 
			
		||||
 | 
			
		||||
	leapYear += oneDay;
 | 
			
		||||
	BOOST_CHECK(leapYear.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(month == 2);
 | 
			
		||||
	BOOST_CHECK(day == 29);
 | 
			
		||||
 | 
			
		||||
	leapYear += oneDay;
 | 
			
		||||
	BOOST_CHECK(leapYear.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(month == 3);
 | 
			
		||||
	BOOST_CHECK(day == 1);
 | 
			
		||||
 | 
			
		||||
	gc::Time time;
 | 
			
		||||
	year = 2011, month = 2, day = 28;
 | 
			
		||||
	int yday ;
 | 
			
		||||
	time.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(time.get2(&year,&yday,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK(year == 2011);
 | 
			
		||||
	BOOST_CHECK_EQUAL(yday , 58);
 | 
			
		||||
 | 
			
		||||
	time += toNextYear;
 | 
			
		||||
	BOOST_CHECK(time.get2(&year,&yday,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year , 2012);
 | 
			
		||||
	BOOST_CHECK_EQUAL(yday , 0);
 | 
			
		||||
 | 
			
		||||
	year = 1964, month = 2, day = 29;
 | 
			
		||||
	leapYear.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(leapYear.get2(&year,&yday,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(yday , 59);
 | 
			
		||||
 | 
			
		||||
	leapYear += toNextYear;
 | 
			
		||||
	BOOST_CHECK(leapYear.get2(&year,&yday,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year, 1965);
 | 
			
		||||
	BOOST_CHECK_EQUAL(yday , 0);
 | 
			
		||||
 | 
			
		||||
	gc::Time before1900;
 | 
			
		||||
	day = 28, month = 2, year = 1900;
 | 
			
		||||
	before1900.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(before1900.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year , 1900);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day , 28);
 | 
			
		||||
	BOOST_CHECK_EQUAL(month, 2);
 | 
			
		||||
 | 
			
		||||
	gc::Time pure;
 | 
			
		||||
	pure.get(&year,&month,&day,&h,&min,&sec,&uSec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year, 1970);
 | 
			
		||||
 | 
			
		||||
	pure -= oneYear;
 | 
			
		||||
	pure.get(&year,&month,&day,&h,&min,&sec,&uSec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year, 1969);
 | 
			
		||||
 | 
			
		||||
	day = 50, month = 4, year = 1566;
 | 
			
		||||
	before1900.set(year,month,day,h,min,sec,uSec);
 | 
			
		||||
	BOOST_CHECK(before1900.get(&year,&month,&day,&h,&min,&sec,&uSec) == true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year , 1566);
 | 
			
		||||
	BOOST_CHECK_EQUAL(day , 20);
 | 
			
		||||
	BOOST_CHECK_EQUAL(month, 5);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(localTime) {
 | 
			
		||||
	gc::Time local;
 | 
			
		||||
	local.set(1970,3,14,5,30,3,39);
 | 
			
		||||
	gc::Time time(local);
 | 
			
		||||
	BOOST_CHECK_EQUAL(double(local), double(time));
 | 
			
		||||
	std::string check1 = local.toString("%FT%T.%fZ");
 | 
			
		||||
	std::string check2 = "1970-03-14T05:30:03.000039Z";
 | 
			
		||||
	bool equal = boost::iequals(check1,check2);
 | 
			
		||||
	BOOST_CHECK_EQUAL(equal, true);
 | 
			
		||||
	gc::Time localtest = local.LocalTime();
 | 
			
		||||
	local = local.LocalTime();
 | 
			
		||||
	localtest.setUSecs(0);
 | 
			
		||||
	local.setUSecs(0);
 | 
			
		||||
	check1 = local.iso();
 | 
			
		||||
	check2 = localtest.iso();
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	local.set(1970,3,14,5,30,3,39);
 | 
			
		||||
	check1 = "1970-03-14T05:30:03.000039Z";
 | 
			
		||||
	check2 = local.toString("%FT%T.%fZ");
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	local.set(1981,9,14,5,30,3,39);
 | 
			
		||||
	check1 = "1981-09-14T05:30:03.000039Z";
 | 
			
		||||
	check2 = local.toString("%FT%T.%fZ");
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	local.set(2014,3,14,5,30,3,39);
 | 
			
		||||
	check1 = "2014-03-14T05:30:03.000039Z";
 | 
			
		||||
	check2 = local.toString("%FT%T.%fZ");
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	local.set(2000,8,14,5,30,3,39);
 | 
			
		||||
	check1 = local.toString("%FT%T.%fZ");
 | 
			
		||||
	check2 = "2000-08-14T05:30:03.000039Z";
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	// before 1970
 | 
			
		||||
	gc::Time before1970;
 | 
			
		||||
	before1970.set(1950,6,4,15,8,66,11);
 | 
			
		||||
	gc::Time t(before1970);
 | 
			
		||||
	gc::Time time1 = local.LocalTime();
 | 
			
		||||
	time1.setUSecs(0);
 | 
			
		||||
	gc::Time time2 = before1970.LocalTime();
 | 
			
		||||
	time2.setUSecs(0);
 | 
			
		||||
	check1 = time1.toString("%FT%T.%fZ");
 | 
			
		||||
	check2 = time2.toString("%FT%T.%fZ");
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	before1970.set(1914,9,4,7,8,66,11);
 | 
			
		||||
	check1 = "1914-09-04T07:09:06.000011Z";
 | 
			
		||||
	check2 = before1970.toString("%FT%T.%fZ");
 | 
			
		||||
	BOOST_CHECK_EQUAL(check1, check2);
 | 
			
		||||
 | 
			
		||||
	gc::Time yearDay = yearDay.FromYearDay(1971, 3);
 | 
			
		||||
	double dayInSeconds = 86400;
 | 
			
		||||
	double yearInSeconds = 31536000;
 | 
			
		||||
	BOOST_CHECK_EQUAL(double(yearDay),dayInSeconds*2 + yearInSeconds);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(validStrings) {
 | 
			
		||||
 | 
			
		||||
	gc::Time date(2016,8,26,15,44,9,644);
 | 
			
		||||
	std::string test = date.toString("%FT%T.%fZ");
 | 
			
		||||
	std::string check = "2016-08-26T15:44:09.000644Z";
 | 
			
		||||
	bool equal = boost::iequals(test,check);
 | 
			
		||||
	BOOST_CHECK_EQUAL(equal, true);
 | 
			
		||||
	BOOST_CHECK(date.FromString(test.c_str(),"%FT%T.%fZ") == date);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK(test == date.iso());
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK(date.fromString(test.c_str(),"%FT%T.%fZ") == true);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(date.valid(), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										105
									
								
								libs/gempa/caps/test/endianess.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								libs/gempa/caps/test/endianess.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,105 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/endianess.h>
 | 
			
		||||
#include <gempa/caps/rawpacket.cpp>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gce = Gempa::CAPS::Endianess;
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_endianess)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(converter) {
 | 
			
		||||
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	// Check little_endian int16_t.
 | 
			
		||||
	const int16_t k16Value{0x0123};
 | 
			
		||||
 | 
			
		||||
	if(gce::Current::LittleEndian) {
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::ToLittleEndian(k16Value), k16Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromLittleEndian(k16Value), k16Value);
 | 
			
		||||
		int16_t g16Value = gce::Converter::ToBigEndian(k16Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(g16Value, 8961);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromBigEndian(g16Value), k16Value);
 | 
			
		||||
		gce::Converter::ToLittleEndian(&k16Value, 4);
 | 
			
		||||
		BOOST_CHECK_EQUAL(291, k16Value);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::ToBigEndian(k16Value), k16Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromBigEndian(k16Value), k16Value);
 | 
			
		||||
		int16_t g16Value = gce::Converter::ToLittleEndian(k16Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(g16Value, 291);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromLittleEndian(g16Value), k16Value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check little_endian int32_t.
 | 
			
		||||
	const int32_t k32Value{0x01234567};
 | 
			
		||||
	if(gce::Current::LittleEndian) {
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::ToLittleEndian(k32Value), k32Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromLittleEndian(k32Value), k32Value);
 | 
			
		||||
		int32_t g32Value = gce::Converter::ToBigEndian(k32Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(g32Value, 1732584193);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromBigEndian(g32Value), k32Value);
 | 
			
		||||
		gce::Converter::ToLittleEndian(&k32Value, 11);
 | 
			
		||||
		BOOST_CHECK_EQUAL(19088743, k32Value);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::ToBigEndian(k32Value), k32Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromBigEndian(k32Value), k32Value);
 | 
			
		||||
		int16_t g32Value = gce::Converter::ToLittleEndian(k32Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(g32Value, 19088743);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromLittleEndian(g32Value), k32Value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check little_endian int64_t.
 | 
			
		||||
	const int64_t k64Value{0x0123456789abcdef};
 | 
			
		||||
	if(gce::Current::LittleEndian) {
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::ToLittleEndian(k64Value), k64Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromLittleEndian(k64Value), k64Value);
 | 
			
		||||
		int64_t g32Value = gce::Converter::ToBigEndian(k64Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(g32Value, -1167088121787636991);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromBigEndian(g32Value), k64Value);
 | 
			
		||||
		gce::Converter::ToLittleEndian(&k64Value, 11);
 | 
			
		||||
		BOOST_CHECK_EQUAL(81985529216486895, k64Value);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::ToBigEndian(k64Value), k64Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromBigEndian(k64Value), k64Value);
 | 
			
		||||
		int16_t g64Value = gce::Converter::ToLittleEndian(k64Value);
 | 
			
		||||
		BOOST_CHECK_EQUAL(g64Value, 19088743);
 | 
			
		||||
		BOOST_CHECK_EQUAL(gce::Converter::FromLittleEndian(g64Value), k64Value);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										29
									
								
								libs/gempa/caps/test/errors_find
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								libs/gempa/caps/test/errors_find
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
Bei utils.h
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
---------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Bei datetime.h
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
---------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Bei rawpacket.cpp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
---------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Bei packet.h
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
---------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Bei endianess.h
 | 
			
		||||
 | 
			
		||||
1) Bei reader ist der Pointer nicht an der ersten stelle des Streams. Siehe endianess.cpp (test) Zeile 114 und folgende.
 | 
			
		||||
---------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Bei mseedpacket.cpp
 | 
			
		||||
 | 
			
		||||
1)
 | 
			
		||||
---------------------------------------------------------------------------------------------------------------------------
 | 
			
		||||
							
								
								
									
										227
									
								
								libs/gempa/caps/test/mseedpacket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								libs/gempa/caps/test/mseedpacket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include "test_utils.h"
 | 
			
		||||
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
#include <gempa/caps/rawpacket.cpp>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
using namespace Gempa::CAPS;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct Record {
 | 
			
		||||
	Record() {
 | 
			
		||||
		vector<char> mseed;
 | 
			
		||||
		mseed.resize(512);
 | 
			
		||||
 | 
			
		||||
		ifstream ifs("data/AM.RFE4F.00.SHZ.20180912.mseed");
 | 
			
		||||
		if( ifs.is_open() ) {
 | 
			
		||||
			ifs.read(mseed.data(), 512);
 | 
			
		||||
			testRec.setData(mseed.data(), 512);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			BOOST_TEST_MESSAGE("unable to open test data file.");
 | 
			
		||||
	}
 | 
			
		||||
	MSEEDDataRecord testRec;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_mseedpacket)
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(equal_functions) {
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	MSEEDDataRecord::Header header;
 | 
			
		||||
	MSEEDDataRecord::Header otherHeader;
 | 
			
		||||
 | 
			
		||||
	header.setSamplingTime(fromString("2018-01-01 00:00:01"));
 | 
			
		||||
	header.samplingFrequencyNumerator = 30;
 | 
			
		||||
	header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	BOOST_CHECK_EQUAL(header != otherHeader, true);
 | 
			
		||||
 | 
			
		||||
	bool valid = header.compatible(otherHeader);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
	otherHeader = header;
 | 
			
		||||
	valid = header.compatible(otherHeader);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(header != otherHeader, false);
 | 
			
		||||
 }
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(header_functions) {
 | 
			
		||||
 | 
			
		||||
	MSEEDDataRecord::Header header;
 | 
			
		||||
	header.dataType = DT_INT64;
 | 
			
		||||
	header.samplingFrequencyNumerator = 1;
 | 
			
		||||
	header.samplingFrequencyDenominator = 1;
 | 
			
		||||
 | 
			
		||||
	char buf[1024];
 | 
			
		||||
	arraybuf abuf(buf, 1024);
 | 
			
		||||
	BOOST_CHECK_EQUAL(header.put(abuf), true);
 | 
			
		||||
 | 
			
		||||
	MSEEDDataRecord::Header otherHeader;
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.get(abuf), true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.samplingFrequencyNumerator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.samplingFrequencyDenominator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.dataType, DT_INT64);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(trim_function) {
 | 
			
		||||
	// MSEEDs records can not be trimmed -> always false
 | 
			
		||||
	MSEEDDataRecord testRec;
 | 
			
		||||
	BOOST_CHECK(!testRec.canTrim());
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(merge_function) {
 | 
			
		||||
	// MSEEDs records can not be merged -> always false
 | 
			
		||||
	MSEEDDataRecord testRec;
 | 
			
		||||
	BOOST_CHECK(!testRec.canMerge());
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(getter_and_setter, Record) {
 | 
			
		||||
	BOOST_CHECK_EQUAL("MSEED", testRec.formatName());
 | 
			
		||||
 | 
			
		||||
	// get data size with and without header
 | 
			
		||||
	size_t sizeWithout = testRec.dataSize(false);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeWithout, 512);
 | 
			
		||||
 | 
			
		||||
	size_t sizeWith = testRec.dataSize(true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(512, sizeWith);
 | 
			
		||||
 | 
			
		||||
	// check start end end time
 | 
			
		||||
	BOOST_CHECK_EQUAL(testRec.startTime().iso(), "2018-09-12T10:55:56.751Z");
 | 
			
		||||
	BOOST_CHECK_EQUAL(testRec.endTime().iso(), "2018-09-12T10:56:03.511Z");
 | 
			
		||||
 | 
			
		||||
	// check sampling frequency
 | 
			
		||||
	BOOST_CHECK_EQUAL(testRec.header()->samplingFrequencyNumerator, 50);
 | 
			
		||||
	BOOST_CHECK_EQUAL(testRec.header()->samplingFrequencyDenominator, 1);
 | 
			
		||||
 | 
			
		||||
	// check packet type
 | 
			
		||||
	BOOST_CHECK_EQUAL(testRec.packetType(), MSEEDPacket);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(read_header_from_buffer, Record) {
 | 
			
		||||
	char data[512];
 | 
			
		||||
 | 
			
		||||
	// write test record data into a buffer
 | 
			
		||||
	arraybuf abuf(data, 512);
 | 
			
		||||
	BOOST_CHECK(testRec.put(abuf, true));
 | 
			
		||||
 | 
			
		||||
	Time startTime, endTime;
 | 
			
		||||
	MSEEDDataRecord::Header header;
 | 
			
		||||
 | 
			
		||||
	// read start, end time and further information from buffer
 | 
			
		||||
	MSEEDDataRecord rec;
 | 
			
		||||
	rec.readMetaData(abuf, 512, header, startTime, endTime);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(startTime.iso(), "2018-09-12T10:55:56.751Z");
 | 
			
		||||
	BOOST_CHECK_EQUAL(endTime.iso(), "2018-09-12T10:56:03.511Z");
 | 
			
		||||
	BOOST_CHECK_EQUAL(header.dataType, DT_INT32);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(read_data_from_file, Record) {
 | 
			
		||||
	ifstream ifs("data/AM.RFE4F.00.SHZ.20180912.mseed");
 | 
			
		||||
	BOOST_CHECK(ifs.is_open());
 | 
			
		||||
 | 
			
		||||
	vector<char> buf;
 | 
			
		||||
	buf.resize(512);
 | 
			
		||||
	ifs.read(buf.data(), 512);
 | 
			
		||||
 | 
			
		||||
	MSEEDDataRecord rec;
 | 
			
		||||
	rec.setData(buf.data(),512);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(rec.header()->samplingFrequencyDenominator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rec.header()->samplingFrequencyNumerator, 50);
 | 
			
		||||
 | 
			
		||||
	TimeSpan timeSpan = samplesToTimeSpan(*rec.header(), 338);
 | 
			
		||||
 | 
			
		||||
	// check that the record start time + all samples is equal to
 | 
			
		||||
	// the record end time
 | 
			
		||||
	Time endTime = rec.startTime() + timeSpan;
 | 
			
		||||
	BOOST_CHECK(endTime == rec.endTime());
 | 
			
		||||
 | 
			
		||||
	// check both header are equal
 | 
			
		||||
	BOOST_CHECK_EQUAL(rec.header()->compatible(*testRec.header()), true);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
							
								
								
									
										97
									
								
								libs/gempa/caps/test/packet.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								libs/gempa/caps/test/packet.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
#include <gempa/caps/rawpacket.cpp>
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gc = Gempa::CAPS;
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_packet)
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(equal_function) {
 | 
			
		||||
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	gc::DataRecord::Header header;
 | 
			
		||||
	gc::DataRecord::Header other;
 | 
			
		||||
	gc::Time t(1004791084,45368);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_NO_THROW(header.setSamplingTime(t));
 | 
			
		||||
	header.samplingFrequencyNumerator = 3;
 | 
			
		||||
	header.samplingFrequencyDenominator = 7;
 | 
			
		||||
	BOOST_CHECK_EQUAL(header != other, true);
 | 
			
		||||
 | 
			
		||||
	bool valid = header.compatible(other);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
	other = header;
 | 
			
		||||
	valid = header.compatible(other);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(header != other, false);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(getAndPut) {
 | 
			
		||||
 | 
			
		||||
	gc::DataRecord::Header header;
 | 
			
		||||
	header.dataType = gc::DT_INT64;
 | 
			
		||||
	header.samplingFrequencyNumerator = 1;
 | 
			
		||||
	header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	char buf[1024];
 | 
			
		||||
	gc::arraybuf abuf(buf, 1024);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(header.samplingFrequencyNumerator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(header.samplingFrequencyDenominator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(header.dataType, gc::DT_INT64);
 | 
			
		||||
	bool valid = header.put(abuf);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, true);
 | 
			
		||||
 | 
			
		||||
	gc::DataRecord::Header otherHeader;
 | 
			
		||||
	valid = otherHeader.get(abuf);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid,true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.samplingFrequencyNumerator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.samplingFrequencyDenominator, 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(otherHeader.dataType, gc::DT_INT64);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										288
									
								
								libs/gempa/caps/test/rawpacket.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								libs/gempa/caps/test/rawpacket.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,288 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef M_PI
 | 
			
		||||
#define M_PI 3.14159265359
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include "test_utils.h"
 | 
			
		||||
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/rawpacket.cpp>
 | 
			
		||||
#include <gempa/caps/mseedpacket.cpp>
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <streambuf>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gc = Gempa::CAPS;
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
struct Record {
 | 
			
		||||
	Record() {
 | 
			
		||||
		gc::DataRecord::Header header;
 | 
			
		||||
		header.setSamplingTime(fromString("2018-01-01 00:00:01"));
 | 
			
		||||
		header.dataType = gc::DT_INT32;
 | 
			
		||||
		header.samplingFrequencyNumerator = 1;
 | 
			
		||||
		header.samplingFrequencyDenominator = 1;
 | 
			
		||||
 | 
			
		||||
		rdr.setHeader(header);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gc::RawDataRecord rdr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T> void fillRecord(T *data, size_t len , gc::Time stime, int sample_microsecs,
 | 
			
		||||
                                     double amplitude, double period) {
 | 
			
		||||
	double periodScale = (2 * M_PI) / period;
 | 
			
		||||
	double x = (double)stime * periodScale;
 | 
			
		||||
	double xOffset = sample_microsecs * 1E-6 * periodScale;
 | 
			
		||||
 | 
			
		||||
	for ( size_t i = 0; i < len; ++i ) {
 | 
			
		||||
		*data = amplitude * sin(x);
 | 
			
		||||
		++data;
 | 
			
		||||
		x += xOffset;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_rawpacket)
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(getAndSet, Record) {
 | 
			
		||||
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	vector<int> data;
 | 
			
		||||
	data.resize(256);
 | 
			
		||||
	rdr.setBuffer(data.data(), 256);
 | 
			
		||||
 | 
			
		||||
	// Set data type and get size of it
 | 
			
		||||
	rdr.setDataType(gc::DT_FLOAT);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeof(float), gc::sizeOf(rdr.header()->dataType));
 | 
			
		||||
	BOOST_CHECK_EQUAL("RAW/FLOAT", rdr.formatName());
 | 
			
		||||
 | 
			
		||||
	rdr.setDataType(gc::DT_INT64);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeof(int64_t), gc::sizeOf(rdr.header()->dataType));
 | 
			
		||||
	BOOST_CHECK_EQUAL("RAW/INT64", rdr.formatName());
 | 
			
		||||
 | 
			
		||||
	// get data size with and without header
 | 
			
		||||
	size_t sizeWithout = rdr.dataSize(false);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeWithout, 256);
 | 
			
		||||
 | 
			
		||||
	size_t sizeWith = rdr.dataSize(true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeWithout + rdr.header()->dataSize(), sizeWith);
 | 
			
		||||
 | 
			
		||||
	data.resize(65536);
 | 
			
		||||
	rdr.setBuffer(data.data(), 65536);
 | 
			
		||||
	sizeWithout = rdr.dataSize(false);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeWithout, 65536);
 | 
			
		||||
	sizeWith = rdr.dataSize(true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(sizeWithout + rdr.header()->dataSize(), sizeWith);
 | 
			
		||||
 | 
			
		||||
	// Set new FrequencyNumerator and FrequencyDenominator
 | 
			
		||||
	rdr.setSamplingFrequency(100,1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.header()->samplingFrequencyNumerator, 100);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.header()->samplingFrequencyDenominator, 1);
 | 
			
		||||
 | 
			
		||||
	rdr.setSamplingFrequency(20,1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.header()->samplingFrequencyNumerator, 20);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.header()->samplingFrequencyDenominator, 1);
 | 
			
		||||
	gc::Time t = gc::getEndTime(rdr.startTime(),20, *rdr.header());
 | 
			
		||||
	BOOST_CHECK_EQUAL(t.iso(), "2018-01-01T00:00:02.0000Z");
 | 
			
		||||
 | 
			
		||||
	gc::DataRecord::Header otherHeader;
 | 
			
		||||
	BOOST_CHECK_NO_THROW(rdr.setHeader(otherHeader));
 | 
			
		||||
	BOOST_CHECK_EQUAL("RAW/UNKWN", rdr.formatName());
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(checkTime, Record) {
 | 
			
		||||
 | 
			
		||||
	gc::Time t = gc::getEndTime(rdr.startTime(), 3, *rdr.header());
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(t.iso(), "2018-01-01T00:00:04.0000Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setStartTime(fromString("2018-02-01 00:00:03.0000"));
 | 
			
		||||
	vector<int> data;
 | 
			
		||||
	data.resize(1024);
 | 
			
		||||
	rdr.setBuffer(data.data(), 1024);
 | 
			
		||||
	t = gc::getEndTime(rdr.startTime(), 3, *rdr.header());
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.startTime().iso(), "2018-02-01T00:00:03.0000Z");
 | 
			
		||||
	BOOST_CHECK_EQUAL(t.iso(), "2018-02-01T00:00:06.0000Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setStartTime(fromString("1988-03-14 14:22:57.322"));
 | 
			
		||||
	t = gc::getEndTime(rdr.startTime(), 2, *rdr.header());
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(t.iso(), "1988-03-14T14:22:59.0000Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setStartTime(fromString("1970-01-01 00:00:00.0000"));
 | 
			
		||||
	rdr.setSamplingFrequency(20,1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.endTime().iso(), "1970-01-01T00:00:12.8Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setDataType(gc::DT_FLOAT);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.endTime().iso(), "1970-01-01T00:00:12.8Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setDataType(gc::DT_DOUBLE);
 | 
			
		||||
	data.resize(2048);
 | 
			
		||||
	rdr.setBuffer(data.data(), 2048);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.endTime().iso(), "1970-01-01T00:00:12.8Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setDataType(gc::DT_INT64);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.endTime().iso(), "1970-01-01T00:00:12.8Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setDataType(gc::DT_INT8);
 | 
			
		||||
	data.resize(256);
 | 
			
		||||
	rdr.setBuffer(data.data(), 256);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.endTime().iso(), "1970-01-01T00:00:12.8Z");
 | 
			
		||||
 | 
			
		||||
	rdr.setDataType(gc::DT_INT16);
 | 
			
		||||
	data.resize(512);
 | 
			
		||||
	rdr.setBuffer(data.data(),512);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.endTime().iso(), "1970-01-01T00:00:12.8Z");
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(trimTest, Record) {
 | 
			
		||||
	// Raw records are trimable -> always true
 | 
			
		||||
	BOOST_CHECK(rdr.canTrim());
 | 
			
		||||
 | 
			
		||||
	const gc::Time endT = gc::getEndTime(rdr.startTime(), 1, *rdr.header());
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.canTrim(), true);
 | 
			
		||||
 | 
			
		||||
	bool trimTest = rdr.trim(rdr.startTime(), endT);
 | 
			
		||||
	BOOST_CHECK_EQUAL(trimTest, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.startTime().iso(), "2018-01-01T00:00:01.0000Z");
 | 
			
		||||
	BOOST_CHECK_EQUAL(endT.iso(), "2018-01-01T00:00:02.0000Z");
 | 
			
		||||
 | 
			
		||||
	trimTest = rdr.trim(endT, rdr.startTime());
 | 
			
		||||
	BOOST_CHECK_EQUAL(trimTest, false);
 | 
			
		||||
 | 
			
		||||
	rdr.setSamplingFrequency(0,0);
 | 
			
		||||
	trimTest = rdr.trim(rdr.startTime(), endT);
 | 
			
		||||
	BOOST_CHECK_EQUAL(trimTest, false);
 | 
			
		||||
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdr.canMerge(), true);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_FIXTURE_TEST_CASE(getAndPut, Record) {
 | 
			
		||||
 | 
			
		||||
	char data[500000];
 | 
			
		||||
	uint64_t sample_microsecs = uint64_t(rdr.header()->samplingFrequencyDenominator) * 1000000 / rdr.header()->samplingFrequencyNumerator;
 | 
			
		||||
	fillRecord<float>((float*)&data, 1024, rdr.startTime(), (int)sample_microsecs, 4.2, 2.1);
 | 
			
		||||
	gc::arraybuf abuf(data, 1024);
 | 
			
		||||
 | 
			
		||||
	vector<int> arr;
 | 
			
		||||
	arr.resize(1024);
 | 
			
		||||
	rdr.setBuffer(arr.data(), 1024);
 | 
			
		||||
	bool check = rdr.put(abuf, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(check, false);
 | 
			
		||||
 | 
			
		||||
	// RS_PARTIAL = 2
 | 
			
		||||
	gc::RawDataRecord rdrOther;
 | 
			
		||||
	gc::DataRecord::ReadStatusCode ret = rdrOther.get(abuf, 1024, rdr.startTime(),rdr.endTime(), 10);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, gc::DataRecord::RS_Partial);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdrOther.startTime() == rdr.startTime(), true);
 | 
			
		||||
 | 
			
		||||
	// RS_COMPLETE = 1
 | 
			
		||||
	gc::arraybuf abuf2(data, 1024);
 | 
			
		||||
	check = rdrOther.put(abuf2, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(check, true);
 | 
			
		||||
 | 
			
		||||
	gc::RawDataRecord rdrOther2;
 | 
			
		||||
	ret = rdrOther2.get(abuf2, 1024, rdrOther2.startTime(),rdrOther2.endTime(), 10);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, gc::DataRecord::RS_Complete);
 | 
			
		||||
 | 
			
		||||
	gc::DataRecord::Header header = *rdrOther2.header();
 | 
			
		||||
	gc::Time start = rdrOther2.startTime();
 | 
			
		||||
	gc::Time end = gc::getEndTime(rdrOther2.startTime(), 2, header);
 | 
			
		||||
	rdrOther2.readMetaData(abuf, 1024, header, start, end);
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdrOther2.startTime().iso(), "2018-01-01T00:00:01.0000Z");
 | 
			
		||||
	BOOST_CHECK_EQUAL(rdrOther2.endTime().iso(), "2018-01-01T00:04:13.0000Z");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// RS_BEFORE_TIME_WINDOW = 3
 | 
			
		||||
	gc::arraybuf abuf3(data, 1024);
 | 
			
		||||
	gc::RawDataRecord rdrBefore;
 | 
			
		||||
	header.setSamplingTime(fromString("2018-01-01 00:00:00"));
 | 
			
		||||
	header.dataType = gc::DT_INT32;
 | 
			
		||||
	header.samplingFrequencyNumerator = 1;
 | 
			
		||||
	header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	rdrBefore.setHeader(header);
 | 
			
		||||
	check = rdrBefore.put(abuf3, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(check, true);
 | 
			
		||||
 | 
			
		||||
	ret = rdrOther.get(abuf3, 1024, rdr.endTime(),rdr.startTime(), 10);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, gc::DataRecord::RS_BeforeTimeWindow);
 | 
			
		||||
 | 
			
		||||
	// RS_AFTER_TIME_WINDOW = 4
 | 
			
		||||
	gc::arraybuf abuf4(data, 1024);
 | 
			
		||||
	gc::RawDataRecord rdrAfter;
 | 
			
		||||
	header.setSamplingTime(fromString("2020-01-01 00:00:00"));
 | 
			
		||||
	header.dataType = gc::DT_INT32;
 | 
			
		||||
	header.samplingFrequencyNumerator = 1;
 | 
			
		||||
	header.samplingFrequencyDenominator = 1;
 | 
			
		||||
	rdrAfter.setHeader(header);
 | 
			
		||||
	check = rdrAfter.put(abuf4, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(check, true);
 | 
			
		||||
 | 
			
		||||
	ret = rdrOther.get(abuf4, 1024, rdrBefore.startTime(),rdrBefore.endTime(), 10);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, gc::DataRecord::RS_AfterTimeWindow);
 | 
			
		||||
 | 
			
		||||
	// RS_ERROR = 0
 | 
			
		||||
	gc::RawDataRecord rdrError;
 | 
			
		||||
	ret = rdrError.get(abuf, 1248, rdr.startTime(),rdr.endTime(), 10);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, gc::DataRecord::RS_Error);
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										10
									
								
								libs/gempa/caps/test/test_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								libs/gempa/caps/test/test_utils.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef __TEST_UTILS_H__
 | 
			
		||||
#define __TEST_UTILS_H__
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
 | 
			
		||||
Gempa::CAPS::Time fromString(const char *str) {
 | 
			
		||||
	return Gempa::CAPS::Time::FromString(str, "%F %T");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										289
									
								
								libs/gempa/caps/test/utils.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								libs/gempa/caps/test/utils.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,289 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * Author: Tracey Werner, Enrico Ellguth                                   *
 | 
			
		||||
 * Email: tracey.werner@gempa.de, enrico.ellguth@gempa.de                  *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SEISCOMP_TEST_MODULE gempa
 | 
			
		||||
#include <seiscomp3/unittest/unittests.h>
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace gc = Gempa::CAPS;
 | 
			
		||||
namespace bu = boost::unit_test;
 | 
			
		||||
 | 
			
		||||
using namespace gc;
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_utils)
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_CASE(split_address_function) {
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_warnings);
 | 
			
		||||
	bu::unit_test_log.set_threshold_level(bu::log_messages);
 | 
			
		||||
 | 
			
		||||
	string name;
 | 
			
		||||
	unsigned short port;
 | 
			
		||||
	int defaultPort = 18002;
 | 
			
		||||
 | 
			
		||||
	string hostname = "localhost";
 | 
			
		||||
	bool valid = splitAddress(name, port, hostname,defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(hostname, "localhost");
 | 
			
		||||
	BOOST_CHECK_EQUAL(port, 18002);
 | 
			
		||||
 | 
			
		||||
	hostname = "data.gempa.de:18000";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(name, "data.gempa.de");
 | 
			
		||||
	BOOST_CHECK_EQUAL(port, 18000);
 | 
			
		||||
 | 
			
		||||
	hostname = "";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	hostname = "localhost:abcde";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
	// port range check. By definition allowed ports are 1 - 65535
 | 
			
		||||
	hostname = "localhost:0";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
	hostname = "localhost:1";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, true);
 | 
			
		||||
 | 
			
		||||
	hostname = "localhost:65536";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
	hostname = "localhost:-1";
 | 
			
		||||
	valid = splitAddress(name, port, hostname, defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
 | 
			
		||||
	hostname = "localhost:";
 | 
			
		||||
	valid = splitAddress(name, port, hostname,defaultPort);
 | 
			
		||||
	BOOST_CHECK_EQUAL(valid, false);
 | 
			
		||||
}
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
BOOST_AUTO_TEST_CASE(trim_function) {
 | 
			
		||||
	// delete whitespaces before and after string
 | 
			
		||||
	string text = " This is a test text 1";
 | 
			
		||||
	BOOST_CHECK_EQUAL(trim(text), "This is a test text 1");
 | 
			
		||||
 | 
			
		||||
	const char *str = text.c_str();
 | 
			
		||||
	int len = text.length();
 | 
			
		||||
 | 
			
		||||
	const char *res = trim(str,len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(res, len), "This is a test text 1");
 | 
			
		||||
 | 
			
		||||
	text = "   This is a test text 2";
 | 
			
		||||
	BOOST_CHECK_EQUAL(trim(text), "This is a test text 2");
 | 
			
		||||
 | 
			
		||||
	str = text.c_str();
 | 
			
		||||
	len = text.length();
 | 
			
		||||
	res = trim(str,len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(res,len), "This is a test text 2");
 | 
			
		||||
 | 
			
		||||
	text = "This is a test text      ";
 | 
			
		||||
	BOOST_CHECK_EQUAL(trim(text), "This is a test text");
 | 
			
		||||
 | 
			
		||||
	str = text.c_str();
 | 
			
		||||
	len = text.length();
 | 
			
		||||
	res = trim(str,len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(res,len), "This is a test text");
 | 
			
		||||
 | 
			
		||||
	text = "   Hello World   ";
 | 
			
		||||
	BOOST_CHECK_EQUAL(trim(text), "Hello World");
 | 
			
		||||
 | 
			
		||||
	str = text.c_str();
 | 
			
		||||
	len = text.length();
 | 
			
		||||
	res = trim(str,len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(res,len), "Hello World");
 | 
			
		||||
 | 
			
		||||
	text = " Hello     :     world";
 | 
			
		||||
	BOOST_CHECK_EQUAL(trim(text), "Hello     :     world");
 | 
			
		||||
 | 
			
		||||
	str = text.c_str();
 | 
			
		||||
	len = text.length();
 | 
			
		||||
	res = trim(str, len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(res,len), "Hello     :     world");
 | 
			
		||||
}
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
BOOST_AUTO_TEST_CASE(converts_time) {
 | 
			
		||||
	// Converts  time object to timestamp
 | 
			
		||||
	const Time t(2014,4,14,6,34,39,7389);
 | 
			
		||||
	TimeStamp ts;
 | 
			
		||||
	timeToTimestamp(ts, t);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.year, 2014);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.second, 39);
 | 
			
		||||
 | 
			
		||||
	const Time t2(0,0);
 | 
			
		||||
	timeToTimestamp(ts,t2);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.year, 1970);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.hour, 0);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts.yday, 0);
 | 
			
		||||
 | 
			
		||||
	// Converts timestamp to time object
 | 
			
		||||
	Time t3 = timestampToTime(ts);
 | 
			
		||||
	int year, yday, hour, min, sec, usec;
 | 
			
		||||
	t3.get2(&year, &yday, &hour, &min, &sec, &usec);
 | 
			
		||||
	BOOST_CHECK_EQUAL(year, 1970);
 | 
			
		||||
	BOOST_CHECK_EQUAL(min, 0);
 | 
			
		||||
}
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
BOOST_AUTO_TEST_CASE(samples) {
 | 
			
		||||
	DataRecord::Header head;
 | 
			
		||||
	head.samplingFrequencyNumerator = 1;
 | 
			
		||||
	head.samplingFrequencyDenominator = 1;
 | 
			
		||||
 | 
			
		||||
	// Convert samples to timespan
 | 
			
		||||
	TimeSpan ts = samplesToTimeSpan(head, 2);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ts, TimeSpan(2,0));
 | 
			
		||||
 | 
			
		||||
	// Convert time span to samples
 | 
			
		||||
	BOOST_CHECK_EQUAL(timeSpanToSamples(head, ts), 2);
 | 
			
		||||
 | 
			
		||||
	// Convert time span to samples and round up/down
 | 
			
		||||
	BOOST_CHECK_EQUAL(timeSpanToSamplesCeil(head, TimeSpan(0, 500000)), 1);
 | 
			
		||||
	BOOST_CHECK_EQUAL(timeSpanToSamplesFloor(head, TimeSpan(0, 600000)), 0);
 | 
			
		||||
}
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
BOOST_AUTO_TEST_CASE(str_to_int) {
 | 
			
		||||
	// int tests
 | 
			
		||||
 | 
			
		||||
	const char *str = "1352";
 | 
			
		||||
	int i;
 | 
			
		||||
	bool ret = str2int(i, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(i, 1352);
 | 
			
		||||
 | 
			
		||||
	str = "";
 | 
			
		||||
	ret = str2int(i, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, false);
 | 
			
		||||
 | 
			
		||||
	str = "478a2";
 | 
			
		||||
	ret = str2int(i, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, false);
 | 
			
		||||
 | 
			
		||||
	str = " 57721";
 | 
			
		||||
	ret = str2int(i, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(i, 57721);
 | 
			
		||||
 | 
			
		||||
	str = "4876 9742";
 | 
			
		||||
	ret = str2int(i, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(i, 4876);
 | 
			
		||||
 | 
			
		||||
	str = "-98256";
 | 
			
		||||
	ret = str2int(i,str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, true);
 | 
			
		||||
	BOOST_CHECK_EQUAL(i, -98256);
 | 
			
		||||
 | 
			
		||||
	str = "-2147483649";
 | 
			
		||||
	ret = str2int(i,str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, false);
 | 
			
		||||
 | 
			
		||||
	str = "2147483648";
 | 
			
		||||
	ret = str2int(i,str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, false);
 | 
			
		||||
 | 
			
		||||
	// uint16_t tests
 | 
			
		||||
 | 
			
		||||
	str = "1";
 | 
			
		||||
	uint16_t value;
 | 
			
		||||
	ret = str2int(value, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, true);
 | 
			
		||||
 | 
			
		||||
	str = "-1";
 | 
			
		||||
	ret = str2int(value, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, false);
 | 
			
		||||
 | 
			
		||||
	str = "65535";
 | 
			
		||||
	ret = str2int(value, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, true);
 | 
			
		||||
 | 
			
		||||
	str = "65536";
 | 
			
		||||
	ret = str2int(value, str);
 | 
			
		||||
	BOOST_CHECK_EQUAL(ret, false);
 | 
			
		||||
}
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
BOOST_AUTO_TEST_CASE(tokenize_function) {
 | 
			
		||||
	const char *text = "Hello, World!";
 | 
			
		||||
	int len = strlen(text), tok_len;
 | 
			
		||||
 | 
			
		||||
	const char *tok = tokenize(text, ",", len, tok_len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(tok, tok_len), "Hello");
 | 
			
		||||
 | 
			
		||||
	tok = tokenize(text, ",", len, tok_len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(tok,tok_len)," World!");
 | 
			
		||||
 | 
			
		||||
	text = "This is a book";
 | 
			
		||||
	len = strlen(text);
 | 
			
		||||
	int tok_count = 0;
 | 
			
		||||
	while ( (tok = tokenize(text, ",", len, tok_len)) != NULL ) {
 | 
			
		||||
		if ( tok_count == 3 ) {
 | 
			
		||||
			BOOST_CHECK_EQUAL(string(tok, tok_len), "book");
 | 
			
		||||
		}
 | 
			
		||||
		++tok_count;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	text = "";
 | 
			
		||||
	len = strlen(text);
 | 
			
		||||
	tok = tokenize(text, ";", len,tok_len);
 | 
			
		||||
	BOOST_CHECK_EQUAL(string(tok,tok_len), "");
 | 
			
		||||
}
 | 
			
		||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 | 
			
		||||
BOOST_AUTO_TEST_SUITE_END()
 | 
			
		||||
							
								
								
									
										377
									
								
								libs/gempa/caps/utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								libs/gempa/caps/utils.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,377 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2014 by gempa GmbH                                        *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * All Rights Reserved.                                                    *
 | 
			
		||||
 *                                                                         *
 | 
			
		||||
 * NOTICE: All information contained herein is, and remains                *
 | 
			
		||||
 * the property of gempa GmbH and its suppliers, if any. The intellectual  *
 | 
			
		||||
 * and technical concepts contained herein are proprietary to gempa GmbH   *
 | 
			
		||||
 * and its suppliers.                                                      *
 | 
			
		||||
 * Dissemination of this information or reproduction of this material      *
 | 
			
		||||
 * is strictly forbidden unless prior written permission is obtained       *
 | 
			
		||||
 * from gempa GmbH.                                                        *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef GEMPA_CAPS_UTILS_H
 | 
			
		||||
#define GEMPA_CAPS_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
 | 
			
		||||
#include <cerrno>
 | 
			
		||||
#include <cstdlib>
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace  Gempa {
 | 
			
		||||
namespace CAPS {
 | 
			
		||||
 | 
			
		||||
class arraybuf : public std::streambuf {
 | 
			
		||||
	public:
 | 
			
		||||
		typedef std::streambuf::pos_type pos_type;
 | 
			
		||||
		typedef std::streambuf::off_type off_type;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		arraybuf(const char *buf, int len) {
 | 
			
		||||
			char *tmp = const_cast<char*>(buf);
 | 
			
		||||
			setp(tmp, tmp + len);
 | 
			
		||||
			setg(tmp, tmp, tmp + len);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		arraybuf(const std::string &buf) {
 | 
			
		||||
			if ( buf.size() > 0 ) {
 | 
			
		||||
				char *tmp = const_cast<char*>(&buf[0]);
 | 
			
		||||
				setg(tmp, tmp, tmp + buf.size());
 | 
			
		||||
				setp(tmp, tmp + buf.size());
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void reset(const char *buf, int len) {
 | 
			
		||||
			char *tmp = const_cast<char*>(buf);
 | 
			
		||||
			setp(tmp, tmp + len);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual pos_type seekoff(off_type ofs, std::ios_base::seekdir dir,
 | 
			
		||||
		                         std::ios_base::openmode mode) {
 | 
			
		||||
			if ( mode & std::ios_base::in ) {
 | 
			
		||||
				char *next;
 | 
			
		||||
 | 
			
		||||
				switch ( dir ) {
 | 
			
		||||
					case std::ios_base::beg:
 | 
			
		||||
						next = eback() + ofs;
 | 
			
		||||
						break;
 | 
			
		||||
					case std::ios_base::cur:
 | 
			
		||||
						next = gptr() + ofs;
 | 
			
		||||
						break;
 | 
			
		||||
					case std::ios_base::end:
 | 
			
		||||
						next = egptr() + ofs;
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						return pos_type(off_type(-1));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if ( next > egptr() || next < eback() )
 | 
			
		||||
					return pos_type(off_type(-1));
 | 
			
		||||
 | 
			
		||||
				gbump(next-gptr());
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ( mode & std::ios_base::out ) {
 | 
			
		||||
				return pos_type(off_type(-1));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return pos_type(off_type(-1));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual pos_type seekpos(pos_type pos, std::ios_base::openmode mode) {
 | 
			
		||||
			if ( mode & std::ios_base::in ) {
 | 
			
		||||
				char *next = eback() + pos;
 | 
			
		||||
				if ( next > egptr() )
 | 
			
		||||
					return pos_type(off_type(-1));
 | 
			
		||||
				gbump(next-gptr());
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ( mode & std::ios_base::out ) {
 | 
			
		||||
				char *next = pbase() + pos;
 | 
			
		||||
				if ( next > epptr() ) {
 | 
			
		||||
					return pos_type(off_type(-1));
 | 
			
		||||
				}
 | 
			
		||||
				pbump(pos);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return pos;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		virtual std::streamsize xsgetn(char* s, std::streamsize n) {
 | 
			
		||||
			char *next = gptr() + n;
 | 
			
		||||
			if ( next >= egptr() )
 | 
			
		||||
				n = n - (next - egptr());
 | 
			
		||||
 | 
			
		||||
			if ( n == 0 ) return 0;
 | 
			
		||||
 | 
			
		||||
			memcpy(s, gptr(), n);
 | 
			
		||||
			setg(eback(), next, egptr());
 | 
			
		||||
 | 
			
		||||
			return n;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::streampos tellg() {
 | 
			
		||||
			return gptr() - eback();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		std::streampos tellp() {
 | 
			
		||||
			return pptr() - pbase();
 | 
			
		||||
		}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CHECK_STRING(data, str, len) \
 | 
			
		||||
	((len == sizeof(str)-1) && (strncasecmp(data, str, len) == 0))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Splits an address string into hostname and port
 | 
			
		||||
 * @param host The host
 | 
			
		||||
 * @param port The port
 | 
			
		||||
 * @param address The address
 | 
			
		||||
 * @param default_port The default port which will be used
 | 
			
		||||
 * if the addrees contains no port
 | 
			
		||||
 * @return True, if the address is valid
 | 
			
		||||
 */
 | 
			
		||||
inline bool splitAddress(std::string &host, unsigned short &port,
 | 
			
		||||
                         const std::string &address, unsigned short default_port) {
 | 
			
		||||
	size_t pos = address.find(':');
 | 
			
		||||
	if ( pos != std::string::npos ) {
 | 
			
		||||
		int p = -1;
 | 
			
		||||
		host = address.substr(0, pos);
 | 
			
		||||
		std::stringstream ss(address.substr(pos+1));
 | 
			
		||||
		ss >> p;
 | 
			
		||||
		if ( p > 0 && p <= 65535 )
 | 
			
		||||
			port = p;
 | 
			
		||||
		else
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		host = address;
 | 
			
		||||
		port = default_port;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return !host.empty();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns substring that contains leftmost characters up to the delimiter
 | 
			
		||||
 */
 | 
			
		||||
inline const char *tokenize(const char *&str, const char *delim,
 | 
			
		||||
                            int &len_source, int &len_tok) {
 | 
			
		||||
	len_tok = 0;
 | 
			
		||||
	for ( ; len_source; --len_source, ++str ) {
 | 
			
		||||
		// Hit first non delimiter?
 | 
			
		||||
		if ( strchr(delim, *str) == NULL ) {
 | 
			
		||||
			const char *tok = str;
 | 
			
		||||
 | 
			
		||||
			++str; --len_source;
 | 
			
		||||
			len_tok = 1;
 | 
			
		||||
 | 
			
		||||
			// Hit first delimiter?
 | 
			
		||||
			for ( ; len_source; --len_source, ++str, ++len_tok ) {
 | 
			
		||||
				if ( strchr(delim, *str) != NULL )
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return tok;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Removes whitespaces from start and end of string
 | 
			
		||||
 */
 | 
			
		||||
inline const char *trim(const char *&str, int &len) {
 | 
			
		||||
	int i = len;
 | 
			
		||||
	while ( i > 0 ) {
 | 
			
		||||
		if ( isspace(*str) ) {
 | 
			
		||||
			++str;
 | 
			
		||||
			--len;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			break;
 | 
			
		||||
		++i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i = len-1;
 | 
			
		||||
	while ( i > 0 ) {
 | 
			
		||||
		if ( !isspace(str[i]) )
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		--len;
 | 
			
		||||
		--i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
inline std::string trim(const std::string &s) {
 | 
			
		||||
	int l = (int)s.size();
 | 
			
		||||
	const char *str = &s[0];
 | 
			
		||||
	trim(str, l);
 | 
			
		||||
	return std::string(str, l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Converts  time object to timestamp
 | 
			
		||||
 */
 | 
			
		||||
inline void timeToTimestamp(TimeStamp &ts, const Time &t) {
 | 
			
		||||
	int year, yday, hour, min, sec, usec;
 | 
			
		||||
	t.get2(&year, &yday, &hour, &min, &sec, &usec);
 | 
			
		||||
	ts.year = year;
 | 
			
		||||
	ts.yday = yday;
 | 
			
		||||
	ts.hour = hour;
 | 
			
		||||
	ts.minute = min;
 | 
			
		||||
	ts.second = sec;
 | 
			
		||||
	ts.usec = usec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Converts string to integer value
 | 
			
		||||
 * @param v The integer value
 | 
			
		||||
 * @param s The input string
 | 
			
		||||
 * @param len The string length. If len is 0 the length
 | 
			
		||||
 *            is calculated from string
 | 
			
		||||
 * @param base The numeric base
 | 
			
		||||
 * @return True on success
 | 
			
		||||
 */
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool str2int(T &v, char const *s, int len = 0, int base = 10) {
 | 
			
		||||
	// Return false in case of empty string
 | 
			
		||||
	if (*s == '\0' ) return false;
 | 
			
		||||
 | 
			
		||||
	char *end;
 | 
			
		||||
	long l;
 | 
			
		||||
	errno = 0;
 | 
			
		||||
	l = strtol(s, &end, base);
 | 
			
		||||
	if ( errno == ERANGE ||
 | 
			
		||||
	     l < std::numeric_limits<T>::min() ||
 | 
			
		||||
	     l > std::numeric_limits<T>::max() ) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if the string contains invalid chars
 | 
			
		||||
	if ( len == 0 ) len = strlen(s);
 | 
			
		||||
 | 
			
		||||
	int bytes_read = end - s;
 | 
			
		||||
	if ( bytes_read < len && *end != ' ' ) return false;
 | 
			
		||||
 | 
			
		||||
	v = static_cast<T>(l);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Converts string to integer value
 | 
			
		||||
 * @param v The integer value
 | 
			
		||||
 * @param s The input string
 | 
			
		||||
 * @param len The string length. If len is 0 the length
 | 
			
		||||
 *            is calculated from string
 | 
			
		||||
 * @param base The numeric base
 | 
			
		||||
 * @return True on success
 | 
			
		||||
 */
 | 
			
		||||
inline bool str2int(int &v, char const *s, int len = 0, int base = 10) {
 | 
			
		||||
	return str2int<int>(v, s, len, base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Converts string to unsigned int16 value
 | 
			
		||||
 * @param v The integer value
 | 
			
		||||
 * @param s The input string
 | 
			
		||||
 * @param len The string length. If len is 0 the length
 | 
			
		||||
 *            is calculated from string
 | 
			
		||||
 * @param base The numeric base
 | 
			
		||||
 * @return True on success
 | 
			
		||||
 */
 | 
			
		||||
inline bool str2int(uint16_t &v, char const *s, int len = 0, int base = 10) {
 | 
			
		||||
	return str2int<uint16_t>(v, s, len, base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Converts timestamp to time object
 | 
			
		||||
 */
 | 
			
		||||
inline Time
 | 
			
		||||
timestampToTime(const TimeStamp &ts) {
 | 
			
		||||
	Time t;
 | 
			
		||||
	t.set(ts.year, 1, 1, ts.hour, ts.minute, ts.second, ts.usec);
 | 
			
		||||
	// Add the day of the year in seconds
 | 
			
		||||
	t += TimeSpan(ts.yday*86400);
 | 
			
		||||
	return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline TimeSpan
 | 
			
		||||
samplesToTimeSpan(const DataRecord::Header &head, int sampleCount) {
 | 
			
		||||
	int64_t ms = ((int64_t)(sampleCount)) * 1000000 * head.samplingFrequencyDenominator / head.samplingFrequencyNumerator;
 | 
			
		||||
	return TimeSpan(ms/1000000, ms%1000000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int
 | 
			
		||||
timeSpanToSamples(const DataRecord::Header &head, const TimeSpan &span) {
 | 
			
		||||
	int64_t ms = ((int64_t)span.seconds())*1000000 + span.microseconds();
 | 
			
		||||
	return ms * head.samplingFrequencyNumerator / head.samplingFrequencyDenominator / 1000000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int
 | 
			
		||||
timeSpanToSamplesCeil(const DataRecord::Header &head, const TimeSpan &span) {
 | 
			
		||||
	int64_t ms = ((int64_t)span.seconds())*1000000 + span.microseconds();
 | 
			
		||||
	return (ms * head.samplingFrequencyNumerator / head.samplingFrequencyDenominator + 999999) / 1000000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline int
 | 
			
		||||
timeSpanToSamplesFloor(const DataRecord::Header &head, const TimeSpan &span) {
 | 
			
		||||
	int64_t ms = ((int64_t)span.seconds())*1000000 + span.microseconds();
 | 
			
		||||
	return ms * head.samplingFrequencyNumerator / head.samplingFrequencyDenominator / 1000000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(WIN32)
 | 
			
		||||
inline void usleep(__int64 usec)
 | 
			
		||||
{
 | 
			
		||||
	HANDLE timer;
 | 
			
		||||
	LARGE_INTEGER ft;
 | 
			
		||||
 | 
			
		||||
	ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time
 | 
			
		||||
 | 
			
		||||
	timer = CreateWaitableTimer(NULL, TRUE, NULL);
 | 
			
		||||
	SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
 | 
			
		||||
	WaitForSingleObject(timer, INFINITE);
 | 
			
		||||
	CloseHandle(timer);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
inline uint8_t dataTypeSize(DataType dt) {
 | 
			
		||||
	if ( dt == DT_INT8 )
 | 
			
		||||
		return sizeof(int8_t);
 | 
			
		||||
	if ( dt == DT_INT16 )
 | 
			
		||||
		return sizeof(int16_t);
 | 
			
		||||
	else if ( dt == DT_INT32 )
 | 
			
		||||
		return sizeof(int32_t);
 | 
			
		||||
	else if ( dt == DT_INT64 )
 | 
			
		||||
		return sizeof(DT_INT64);
 | 
			
		||||
	else if ( dt == DT_FLOAT )
 | 
			
		||||
		return sizeof(float);
 | 
			
		||||
	else if ( dt == DT_DOUBLE )
 | 
			
		||||
		return sizeof(double);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										32
									
								
								libs/gempa/caps/version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								libs/gempa/caps/version.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
/***************************************************************************
 | 
			
		||||
 * Copyright (C) 2018 by gempa GmbH
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Stephan Herrnkind
 | 
			
		||||
 * Email: herrnkidn@gempa.de
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef __GEMPA_CAPS_VERSION_H__
 | 
			
		||||
#define __GEMPA_CAPS_VERSION_H__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* #if (LIB_CAPS_VERSION >= LIB_CAPS_VERSION_CHECK(1, 0, 0)) */
 | 
			
		||||
#define LIB_CAPS_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
 | 
			
		||||
 | 
			
		||||
#define LIB_CAPS_VERSION_MAJOR(v) (v >> 16)
 | 
			
		||||
#define LIB_CAPS_VERSION_MINOR(v) ((v >> 8) & 0xff)
 | 
			
		||||
#define LIB_CAPS_VERSION_PATCH(v) (v & 0xff)
 | 
			
		||||
 | 
			
		||||
/* LIB_CAPS_VERSION is (major << 16) + (minor << 8) + patch. */
 | 
			
		||||
#define LIB_CAPS_VERSION 0x010000
 | 
			
		||||
#define LIB_CAPS_VERSION_NAME "1.0.0"
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 API Changelog
 | 
			
		||||
 ******************************************************************************
 | 
			
		||||
 "1.0.0"   0x010000
 | 
			
		||||
   - Initial version
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#endif // __GEMPA_CAPS_VERSION_H__
 | 
			
		||||
							
								
								
									
										1
									
								
								libs/swig/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libs/swig/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
SUBDIRS(gempa)
 | 
			
		||||
							
								
								
									
										125
									
								
								libs/swig/gempa/CAPS.i
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								libs/swig/gempa/CAPS.i
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
%feature("notabstract") Gempa::CAPS::AnyDataRecord;
 | 
			
		||||
%include "stdint.i"
 | 
			
		||||
 | 
			
		||||
%init
 | 
			
		||||
%{
 | 
			
		||||
import_array();
 | 
			
		||||
%}
 | 
			
		||||
 | 
			
		||||
%module CAPS
 | 
			
		||||
%{
 | 
			
		||||
#define SWIG_FILE_WITH_INIT
 | 
			
		||||
#include <gempa/caps/utils.h>
 | 
			
		||||
#include <gempa/caps/anypacket.h>
 | 
			
		||||
#include <gempa/caps/datetime.h>
 | 
			
		||||
#include <gempa/caps/log.h>
 | 
			
		||||
#include <gempa/caps/mseedpacket.h>
 | 
			
		||||
#include <gempa/caps/packet.h>
 | 
			
		||||
#include <gempa/caps/plugin.h>
 | 
			
		||||
typedef Gempa::CAPS::Plugin::Buffer Buffer;
 | 
			
		||||
#include <gempa/caps/rawpacket.h>
 | 
			
		||||
#include <gempa/caps/riff.h>
 | 
			
		||||
#include <gempa/caps/rtcm2packet.h>
 | 
			
		||||
#include <gempa/caps/socket.h>
 | 
			
		||||
#include <gempa/caps/mseed/spclock.h>
 | 
			
		||||
#include <numpy/ndarrayobject.h>
 | 
			
		||||
 | 
			
		||||
%}
 | 
			
		||||
 | 
			
		||||
%extend Gempa::CAPS::Plugin {
 | 
			
		||||
        Gempa::CAPS::Plugin::Status push(const std::string &net, const std::string &sta,
 | 
			
		||||
                              const std::string &loc, const std::string &cha,
 | 
			
		||||
                              const Time &stime, int16_t numerator, int16_t denominator,
 | 
			
		||||
                              const std::string &uom,
 | 
			
		||||
                              PyObject *obj, int type
 | 
			
		||||
                              ) {
 | 
			
		||||
                PyArrayObject *arr = NULL;
 | 
			
		||||
                Gempa::CAPS::DataType dataType = (Gempa::CAPS::DataType)type;
 | 
			
		||||
                Gempa::CAPS::Plugin::Status status = Gempa::CAPS::Plugin::PacketLoss;
 | 
			
		||||
                switch(type) {
 | 
			
		||||
                        case Gempa::CAPS::DT_INT8:
 | 
			
		||||
                                arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_CHAR, 1, 1);
 | 
			
		||||
                                if ( arr == NULL )
 | 
			
		||||
                                        break;
 | 
			
		||||
 | 
			
		||||
                                status = self->push(net, sta, loc, cha, stime, numerator, denominator,
 | 
			
		||||
                                                    uom, (int8_t*)(arr->data), arr->dimensions[0], dataType);
 | 
			
		||||
                                break;
 | 
			
		||||
                        case Gempa::CAPS::DT_INT16:
 | 
			
		||||
                                arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_INT16, 1, 1);
 | 
			
		||||
                                if ( arr == NULL )
 | 
			
		||||
                                        break;
 | 
			
		||||
 | 
			
		||||
                                status = self->push(net, sta, loc, cha, stime, numerator, denominator,
 | 
			
		||||
                                                    uom, (int16_t*)(arr->data), arr->dimensions[0], dataType);
 | 
			
		||||
                                break;
 | 
			
		||||
                        case Gempa::CAPS::DT_INT32:
 | 
			
		||||
                                arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_INT32, 1, 1);
 | 
			
		||||
                                if ( arr == NULL )
 | 
			
		||||
                                        break;
 | 
			
		||||
 | 
			
		||||
                                status = self->push(net, sta, loc, cha, stime, numerator, denominator,
 | 
			
		||||
                                                    uom, (int32_t*)(arr->data), arr->dimensions[0], dataType);
 | 
			
		||||
                                break;
 | 
			
		||||
                        case Gempa::CAPS::DT_FLOAT:
 | 
			
		||||
                                arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_FLOAT32, 1, 1);
 | 
			
		||||
                                if ( arr == NULL )
 | 
			
		||||
                                        break;
 | 
			
		||||
 | 
			
		||||
                                status = self->push(net, sta, loc, cha, stime, numerator, denominator,
 | 
			
		||||
                                                    uom, (float*)(arr->data), arr->dimensions[0], dataType);
 | 
			
		||||
                                break;
 | 
			
		||||
                        case Gempa::CAPS::DT_DOUBLE:
 | 
			
		||||
                                arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_FLOAT64, 1, 1);
 | 
			
		||||
                                if ( arr == NULL )
 | 
			
		||||
                                        break;
 | 
			
		||||
 | 
			
		||||
                                status = self->push(net, sta, loc, cha, stime, numerator, denominator,
 | 
			
		||||
                                                    uom, (double*)(arr->data), arr->dimensions[0], dataType);
 | 
			
		||||
                                break;
 | 
			
		||||
                        default:
 | 
			
		||||
                                break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Py_XDECREF(arr);
 | 
			
		||||
                return status;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Gempa::CAPS::Plugin::Status push(const std::string &net, const std::string &sta,
 | 
			
		||||
                                         const std::string &loc, const std::string &cha,
 | 
			
		||||
                                         const Time &stime, uint16_t numerator,
 | 
			
		||||
                                         uint16_t denominator, const std::string &format,
 | 
			
		||||
                                         PyObject *obj) {
 | 
			
		||||
                char *data;
 | 
			
		||||
                Py_ssize_t len;
 | 
			
		||||
                if ( PyBytes_AsStringAndSize(obj, &data, &len) == -1 )
 | 
			
		||||
                        return Gempa::CAPS::Plugin::PacketLoss;
 | 
			
		||||
 | 
			
		||||
                return self->push(net, sta, loc, cha, stime, numerator,
 | 
			
		||||
                                  denominator, format, data, len);
 | 
			
		||||
        }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
%include "exception.i"
 | 
			
		||||
%include "std_string.i"
 | 
			
		||||
%include "numpy.i"
 | 
			
		||||
 | 
			
		||||
%include "gempa/caps/api.h"
 | 
			
		||||
%include "gempa/caps/datetime.h"
 | 
			
		||||
%include "gempa/caps/packet.h"
 | 
			
		||||
%include "gempa/caps/pluginpacket.h"
 | 
			
		||||
%include "gempa/caps/anypacket.h"
 | 
			
		||||
%include "gempa/caps/log.h"
 | 
			
		||||
%include "gempa/caps/mseed/spclock.h"
 | 
			
		||||
%include "gempa/caps/mseed/encoder.h"
 | 
			
		||||
%include "gempa/caps/encoderfactory.h"
 | 
			
		||||
%include "gempa/caps/mseedpacket.h"
 | 
			
		||||
typedef Gempa::CAPS::Plugin::Buffer Buffer;
 | 
			
		||||
%include "gempa/caps/plugin.h"
 | 
			
		||||
%include "gempa/caps/rawpacket.h"
 | 
			
		||||
%include "gempa/caps/riff.h"
 | 
			
		||||
%include "gempa/caps/rtcm2packet.h"
 | 
			
		||||
%include "gempa/caps/socket.h"
 | 
			
		||||
%include <carrays.i>
 | 
			
		||||
%array_class(char, charArray);
 | 
			
		||||
%include "gempa/caps/utils.h"
 | 
			
		||||
							
								
								
									
										1928
									
								
								libs/swig/gempa/CAPS.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1928
									
								
								libs/swig/gempa/CAPS.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										26030
									
								
								libs/swig/gempa/CAPSPYTHON_wrap.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26030
									
								
								libs/swig/gempa/CAPSPYTHON_wrap.cxx
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										79
									
								
								libs/swig/gempa/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								libs/swig/gempa/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
FIND_PACKAGE(PythonLibs REQUIRED)
 | 
			
		||||
FIND_PACKAGE(PythonInterp REQUIRED)
 | 
			
		||||
SET(PYTHON_LIBRARY_SUFFIX /python)
 | 
			
		||||
SET(PYTHON_LIBRARY_PATH lib${PYTHON_LIBRARY_SUFFIX})
 | 
			
		||||
 | 
			
		||||
FIND_PACKAGE(Numpy)
 | 
			
		||||
 | 
			
		||||
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIR})
 | 
			
		||||
INCLUDE_DIRECTORIES(${PYTHON_NUMPY_INCLUDE_DIR})
 | 
			
		||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
 | 
			
		||||
INCLUDE_DIRECTORIES(../../../system/libs/swig)
 | 
			
		||||
 | 
			
		||||
FIND_PACKAGE(Boost REQUIRED COMPONENTS filesystem)
 | 
			
		||||
 | 
			
		||||
IF (CMAKE_COMPILER_IS_GNUCC)
 | 
			
		||||
    # Important for O2 compilation
 | 
			
		||||
    ADD_DEFINITIONS("-fno-strict-aliasing")
 | 
			
		||||
ENDIF (CMAKE_COMPILER_IS_GNUCC)
 | 
			
		||||
 | 
			
		||||
SET(
 | 
			
		||||
        WRAPPER_MODULES
 | 
			
		||||
				CAPS
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
FIND_PACKAGE(OpenSSL REQUIRED)
 | 
			
		||||
 | 
			
		||||
SET(WRAPPER_MODULE_CAPS_EXTRA_LIBS capsclient ${Boost_filesystem_LIBRARY} ${OPENSSL_LIBRARIES})
 | 
			
		||||
 | 
			
		||||
FOREACH (wrapper_module ${WRAPPER_MODULES})
 | 
			
		||||
        SET(
 | 
			
		||||
                ${wrapper_module}_SOURCES
 | 
			
		||||
                        ${wrapper_module}PYTHON_wrap.cxx
 | 
			
		||||
                        ${WRAPPER_MODULE_${wrapper_module}_EXTRA_FILES}
 | 
			
		||||
        )
 | 
			
		||||
        ADD_LIBRARY(_${wrapper_module} MODULE ${${wrapper_module}_SOURCES})
 | 
			
		||||
        SET_TARGET_PROPERTIES(_${wrapper_module} PROPERTIES PREFIX "")
 | 
			
		||||
        TARGET_LINK_LIBRARIES(_${wrapper_module} ${PYTHON_LIBRARIES})
 | 
			
		||||
        TARGET_LINK_LIBRARIES(_${wrapper_module} ${WRAPPER_MODULE_${wrapper_module}_EXTRA_LIBS})
 | 
			
		||||
ENDFOREACH (wrapper_module)
 | 
			
		||||
 | 
			
		||||
#SC_SWIG_GET_MODULE_PATH(_module_path)
 | 
			
		||||
SET(_module_path ${CMAKE_INSTALL_PREFIX}/lib/python/gempa)
 | 
			
		||||
 | 
			
		||||
FOREACH (wrapper_module ${WRAPPER_MODULES})
 | 
			
		||||
        INSTALL(
 | 
			
		||||
                TARGETS _${wrapper_module}
 | 
			
		||||
                LIBRARY DESTINATION ${_module_path}
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
	 INSTALL(
 | 
			
		||||
                FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
 | 
			
		||||
                DESTINATION ${_module_path}
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        INSTALL(
 | 
			
		||||
                FILES ${CMAKE_CURRENT_SOURCE_DIR}/${wrapper_module}.py
 | 
			
		||||
                DESTINATION ${_module_path}
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        INSTALL(
 | 
			
		||||
                FILES ${CMAKE_CURRENT_BINARY_DIR}/${wrapper_module}.pyc
 | 
			
		||||
                DESTINATION ${_module_path}
 | 
			
		||||
                OPTIONAL
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        INSTALL(
 | 
			
		||||
                FILES ${CMAKE_CURRENT_BINARY_DIR}/${wrapper_module}.pyo
 | 
			
		||||
                DESTINATION ${_module_path}
 | 
			
		||||
                OPTIONAL
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        ADD_CUSTOM_COMMAND(
 | 
			
		||||
                TARGET _${wrapper_module}
 | 
			
		||||
                POST_BUILD
 | 
			
		||||
                COMMAND ${CMAKE_SOURCE_DIR}/py-compile ARGS --python \"${PYTHON_EXECUTABLE}\" --destdir ${CMAKE_CURRENT_BINARY_DIR} ${wrapper_module}.py
 | 
			
		||||
        )
 | 
			
		||||
ENDFOREACH (wrapper_module)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										0
									
								
								libs/swig/gempa/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								libs/swig/gempa/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										2
									
								
								libs/swig/gempa/codegen.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								libs/swig/gempa/codegen.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
swig -c++ -I../../ -o CAPSPYTHON_wrap.cxx -python CAPS.i
 | 
			
		||||
							
								
								
									
										3161
									
								
								libs/swig/gempa/numpy.i
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3161
									
								
								libs/swig/gempa/numpy.i
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user