Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 44609d367f | |||
| f593487c77 | |||
| ed6649e947 | |||
| 4bd69a81fc | |||
|
8934eeac6b
|
@@ -1,5 +1,11 @@
|
||||
PROJECT(LIBCAPS)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
IF(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "7.0")
|
||||
ADD_DEFINITIONS(-std=c++17 -DBOOST_NO_CXX11_SCOPED_ENUM -DBOOST_NO_SCOPED_ENUMS)
|
||||
ELSE()
|
||||
MESSAGE(ERROR "The CAPS client library requires gcc version 4.7 or higher")
|
||||
ENDIF()
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules)
|
||||
|
||||
@@ -15,6 +21,7 @@ INCLUDE_DIRECTORIES(libs)
|
||||
#ADD_DEFINITIONS("-DCAPS_FEATURES_RTCM2=0")
|
||||
#ADD_DEFINITIONS("-DCAPS_FEATURES_BACKFILLING=0")
|
||||
#ADD_DEFINITIONS("-DCAPS_FEATURES_JOURNAL=0")
|
||||
ADD_DEFINITIONS("-DCAPS_SC_LOGGING=0")
|
||||
|
||||
OPTION(LIBCAPS_PYTHON_WRAPPER "Create Python wrappers" ON)
|
||||
OPTION(LIBCAPS_EXAMPLES "Build and install example applications" OFF)
|
||||
|
||||
1571
libs/gempa/caps/3rd-party/libmseed/libmseed.h
vendored
Normal file
1571
libs/gempa/caps/3rd-party/libmseed/libmseed.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
661
libs/gempa/caps/3rd-party/libmseed/mseedformat.h
vendored
Normal file
661
libs/gempa/caps/3rd-party/libmseed/mseedformat.h
vendored
Normal file
@@ -0,0 +1,661 @@
|
||||
/***************************************************************************
|
||||
* Documentation and helpers for miniSEED structures.
|
||||
*
|
||||
* This file is part of the miniSEED Library.
|
||||
*
|
||||
* Copyright (c) 2024 Chad Trabant, EarthScope Data Services
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MSEEDFORMAT_H
|
||||
#define MSEEDFORMAT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "libmseed.h"
|
||||
|
||||
/* Length of Fixed Section of Data Header for miniSEED v3 */
|
||||
#define MS3FSDH_LENGTH 40
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 3.0 Fixed Section of Data Header
|
||||
* 40 bytes, plus length of identifier, plus length of extra headers
|
||||
*
|
||||
* # FIELD TYPE OFFSET
|
||||
* 1 record indicator char[2] 0
|
||||
* 2 format version uint8_t 2
|
||||
* 3 flags uint8_t 3
|
||||
* 4a nanosecond uint32_t 4
|
||||
* 4b year uint16_t 8
|
||||
* 4c day uint16_t 10
|
||||
* 4d hour uint8_t 12
|
||||
* 4e min uint8_t 13
|
||||
* 4f sec uint8_t 14
|
||||
* 5 data encoding uint8_t 15
|
||||
* 6 sample rate/period float64 16
|
||||
* 7 number of samples uint32_t 24
|
||||
* 8 CRC of record uint32_t 28
|
||||
* 9 publication version uint8_t 32
|
||||
* 10 length of identifer uint8_t 33
|
||||
* 11 length of extra headers uint16_t 34
|
||||
* 12 length of data payload uint32_t 36
|
||||
* 13 source identifier char 40
|
||||
* 14 extra headers char 40 + field 10
|
||||
* 15 data payload encoded 40 + field 10 + field 11
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS3FSDH_INDICATOR(record) ((char*)record)
|
||||
#define pMS3FSDH_FORMATVERSION(record) ((uint8_t*)((uint8_t*)record+2))
|
||||
#define pMS3FSDH_FLAGS(record) ((uint8_t*)((uint8_t*)record+3))
|
||||
#define pMS3FSDH_NSEC(record) ((uint32_t*)((uint8_t*)record+4))
|
||||
#define pMS3FSDH_YEAR(record) ((uint16_t*)((uint8_t*)record+8))
|
||||
#define pMS3FSDH_DAY(record) ((uint16_t*)((uint8_t*)record+10))
|
||||
#define pMS3FSDH_HOUR(record) ((uint8_t*)((uint8_t*)record+12))
|
||||
#define pMS3FSDH_MIN(record) ((uint8_t*)((uint8_t*)record+13))
|
||||
#define pMS3FSDH_SEC(record) ((uint8_t*)((uint8_t*)record+14))
|
||||
#define pMS3FSDH_ENCODING(record) ((uint8_t*)((uint8_t*)record+15))
|
||||
#define pMS3FSDH_SAMPLERATE(record) ((double*)((uint8_t*)record+16))
|
||||
#define pMS3FSDH_NUMSAMPLES(record) ((uint32_t*)((uint8_t*)record+24))
|
||||
#define pMS3FSDH_CRC(record) ((uint32_t*)((uint8_t*)record+28))
|
||||
#define pMS3FSDH_PUBVERSION(record) ((uint8_t*)((uint8_t*)record+32))
|
||||
#define pMS3FSDH_SIDLENGTH(record) ((uint8_t*)((uint8_t*)record+33))
|
||||
#define pMS3FSDH_EXTRALENGTH(record) ((uint16_t*)((uint8_t*)record+34))
|
||||
#define pMS3FSDH_DATALENGTH(record) ((uint32_t*)((uint8_t*)record+36))
|
||||
#define pMS3FSDH_SID(record) ((char*)((uint8_t*)record+40))
|
||||
|
||||
/* Length of Fixed Section of Data Header for miniSEED v2 */
|
||||
#define MS2FSDH_LENGTH 48
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Fixed Section of Data Header
|
||||
* 48 bytes total
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* sequence_number char[6] 0
|
||||
* dataquality char 6
|
||||
* reserved char 7
|
||||
* station char[5] 8
|
||||
* location char[2] 13
|
||||
* channel char[3] 15
|
||||
* network char[2] 18
|
||||
* year uint16_t 20
|
||||
* day uint16_t 22
|
||||
* hour uint8_t 24
|
||||
* min uint8_t 25
|
||||
* sec uint8_t 26
|
||||
* unused uint8_t 27
|
||||
* fract uint16_t 28
|
||||
* numsamples uint16_t 30
|
||||
* samprate_fact int16_t 32
|
||||
* samprate_mult int16_t 34
|
||||
* act_flags uint8_t 36
|
||||
* io_flags uint8_t 37
|
||||
* dq_flags uint8_t 38
|
||||
* numblockettes uint8_t 39
|
||||
* time_correct int32_t 40
|
||||
* data_offset uint16_t 44
|
||||
* blockette_offset uint16_t 46
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2FSDH_SEQNUM(record) ((char*)record)
|
||||
#define pMS2FSDH_DATAQUALITY(record) ((char*)((uint8_t*)record+6))
|
||||
#define pMS2FSDH_RESERVED(record) ((char*)((uint8_t*)record+7))
|
||||
#define pMS2FSDH_STATION(record) ((char*)((uint8_t*)record+8))
|
||||
#define pMS2FSDH_LOCATION(record) ((char*)((uint8_t*)record+13))
|
||||
#define pMS2FSDH_CHANNEL(record) ((char*)((uint8_t*)record+15))
|
||||
#define pMS2FSDH_NETWORK(record) ((char*)((uint8_t*)record+18))
|
||||
#define pMS2FSDH_YEAR(record) ((uint16_t*)((uint8_t*)record+20))
|
||||
#define pMS2FSDH_DAY(record) ((uint16_t*)((uint8_t*)record+22))
|
||||
#define pMS2FSDH_HOUR(record) ((uint8_t*)((uint8_t*)record+24))
|
||||
#define pMS2FSDH_MIN(record) ((uint8_t*)((uint8_t*)record+25))
|
||||
#define pMS2FSDH_SEC(record) ((uint8_t*)((uint8_t*)record+26))
|
||||
#define pMS2FSDH_UNUSED(record) ((uint8_t*)((uint8_t*)record+27))
|
||||
#define pMS2FSDH_FSEC(record) ((uint16_t*)((uint8_t*)record+28))
|
||||
#define pMS2FSDH_NUMSAMPLES(record) ((uint16_t*)((uint8_t*)record+30))
|
||||
#define pMS2FSDH_SAMPLERATEFACT(record) ((int16_t*)((uint8_t*)record+32))
|
||||
#define pMS2FSDH_SAMPLERATEMULT(record) ((int16_t*)((uint8_t*)record+34))
|
||||
#define pMS2FSDH_ACTFLAGS(record) ((uint8_t*)((uint8_t*)record+36))
|
||||
#define pMS2FSDH_IOFLAGS(record) ((uint8_t*)((uint8_t*)record+37))
|
||||
#define pMS2FSDH_DQFLAGS(record) ((uint8_t*)((uint8_t*)record+38))
|
||||
#define pMS2FSDH_NUMBLOCKETTES(record) ((uint8_t*)((uint8_t*)record+39))
|
||||
#define pMS2FSDH_TIMECORRECT(record) ((int32_t*)((uint8_t*)record+40))
|
||||
#define pMS2FSDH_DATAOFFSET(record) ((uint16_t*)((uint8_t*)record+44))
|
||||
#define pMS2FSDH_BLOCKETTEOFFSET(record) ((uint16_t*)((uint8_t*)record+46))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 100 - sample rate
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* samprate float 4
|
||||
* flags uint8_t 8
|
||||
* reserved uint8_t[3] 9
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B100_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B100_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B100_SAMPRATE(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B100_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B100_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 200 - generic event detection
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* amplitude float 4
|
||||
* period float 8
|
||||
* background_est float 12
|
||||
* flags uint8_t 16
|
||||
* reserved uint8_t 17
|
||||
* year uint16_t 18
|
||||
* day uint16_t 20
|
||||
* hour uint8_t 22
|
||||
* min uint8_t 23
|
||||
* sec uint8_t 24
|
||||
* unused uint8_t 25
|
||||
* fract uint16_t 26
|
||||
* detector char[24] 28
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B200_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B200_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B200_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B200_PERIOD(blockette) ((float*)((uint8_t*)blockette+8))
|
||||
#define pMS2B200_BACKGROUNDEST(blockette) ((float*)((uint8_t*)blockette+12))
|
||||
#define pMS2B200_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B200_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+17))
|
||||
#define pMS2B200_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+18))
|
||||
#define pMS2B200_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B200_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+22))
|
||||
#define pMS2B200_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+23))
|
||||
#define pMS2B200_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+24))
|
||||
#define pMS2B200_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+25))
|
||||
#define pMS2B200_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+26))
|
||||
#define pMS2B200_DETECTOR(blockette) ((char*)((uint8_t*)blockette+28))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 201 - Murdock event detection
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* amplitude float 4
|
||||
* period float 8
|
||||
* background_est float 12
|
||||
* flags uint8_t 16
|
||||
* reserved uint8_t 17
|
||||
* year uint16_t 18
|
||||
* day uint16_t 20
|
||||
* hour uint8_t 22
|
||||
* min uint8_t 23
|
||||
* sec uint8_t 24
|
||||
* unused uint8_t 25
|
||||
* fract uint16_t 26
|
||||
* snr_values uint8_t[6] 28
|
||||
* loopback uint8_t 34
|
||||
* pick_algorithm uint8_t 35
|
||||
* detector char[24] 36
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B201_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B201_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B201_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B201_PERIOD(blockette) ((float*)((uint8_t*)blockette+8))
|
||||
#define pMS2B201_BACKGROUNDEST(blockette) ((float*)((uint8_t*)blockette+12))
|
||||
#define pMS2B201_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B201_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+17))
|
||||
#define pMS2B201_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+18))
|
||||
#define pMS2B201_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B201_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+22))
|
||||
#define pMS2B201_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+23))
|
||||
#define pMS2B201_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+24))
|
||||
#define pMS2B201_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+25))
|
||||
#define pMS2B201_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+26))
|
||||
#define pMS2B201_MEDSNR(blockette) ((uint8_t*)((uint8_t*)blockette+28))
|
||||
#define pMS2B201_LOOPBACK(blockette) ((uint8_t*)((uint8_t*)blockette+34))
|
||||
#define pMS2B201_PICKALGORITHM(blockette) ((uint8_t*)((uint8_t*)blockette+35))
|
||||
#define pMS2B201_DETECTOR(blockette) ((char*)((uint8_t*)blockette+36))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 300 - step calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* num calibrations uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* step duration uint32_t 16
|
||||
* interval duration uint32_t 20
|
||||
* amplitude float 24
|
||||
* input channel char[3] 28
|
||||
* reserved uint8_t 31
|
||||
* reference amplitude uint32_t 32
|
||||
* coupling char[12] 36
|
||||
* rolloff char[12] 48
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B300_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B300_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B300_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B300_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B300_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B300_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B300_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B300_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B300_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B300_NUMCALIBRATIONS(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B300_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B300_STEPDURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B300_INTERVALDURATION(blockette) ((uint32_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B300_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+24))
|
||||
#define pMS2B300_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+28))
|
||||
#define pMS2B300_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+31))
|
||||
#define pMS2B300_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+32))
|
||||
#define pMS2B300_COUPLING(blockette) ((char*)((uint8_t*)blockette+36))
|
||||
#define pMS2B300_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+48))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 310 - sine calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved1 uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* duration uint32_t 16
|
||||
* period float 20
|
||||
* amplitude float 24
|
||||
* input channel char[3] 28
|
||||
* reserved2 uint8_t 31
|
||||
* reference amplitude uint32_t 32
|
||||
* coupling char[12] 36
|
||||
* rolloff char[12] 48
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B310_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B310_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B310_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B310_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B310_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B310_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B310_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B310_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B310_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B310_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B310_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B310_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B310_PERIOD(blockette) ((float*)((uint8_t*)blockette+20))
|
||||
#define pMS2B310_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+24))
|
||||
#define pMS2B310_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+28))
|
||||
#define pMS2B310_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+31))
|
||||
#define pMS2B310_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+32))
|
||||
#define pMS2B310_COUPLING(blockette) ((char*)((uint8_t*)blockette+36))
|
||||
#define pMS2B310_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+48))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 320 - pseudo-random calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved1 uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* duration uint32_t 16
|
||||
* PtP amplitude float 20
|
||||
* input channel char[3] 24
|
||||
* reserved2 uint8_t 27
|
||||
* reference amplitude uint32_t 28
|
||||
* coupling char[12] 32
|
||||
* rolloff char[12] 44
|
||||
* noise type char[8] 56
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B320_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B320_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B320_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B320_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B320_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B320_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B320_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B320_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B320_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B320_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B320_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B320_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B320_PTPAMPLITUDE(blockette) ((float*)((uint8_t*)blockette+20))
|
||||
#define pMS2B320_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+24))
|
||||
#define pMS2B320_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+27))
|
||||
#define pMS2B320_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+28))
|
||||
#define pMS2B320_COUPLING(blockette) ((char*)((uint8_t*)blockette+32))
|
||||
#define pMS2B320_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+44))
|
||||
#define pMS2B320_NOISETYPE(blockette) ((char*)((uint8_t*)blockette+56))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 390 - generic calibration
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved1 uint8_t 14
|
||||
* flags uint8_t 15
|
||||
* duration uint32_t 16
|
||||
* amplitude float 20
|
||||
* input channel char[3] 24
|
||||
* reserved2 uint8_t 27
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B390_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B390_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B390_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B390_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B390_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B390_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B390_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B390_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B390_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B390_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B390_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B390_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B390_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+20))
|
||||
#define pMS2B390_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+24))
|
||||
#define pMS2B390_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+27))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 395 - calibration abort
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* year uint16_t 4
|
||||
* day uint16_t 6
|
||||
* hour uint8_t 8
|
||||
* min uint8_t 9
|
||||
* sec uint8_t 10
|
||||
* unused uint8_t 11
|
||||
* fract uint16_t 12
|
||||
* reserved uint8_t[2] 14
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B395_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B395_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B395_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B395_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B395_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B395_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
|
||||
#define pMS2B395_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B395_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
|
||||
#define pMS2B395_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B395_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 400 - beam
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* azimuth float 4
|
||||
* slowness float 8
|
||||
* configuration uint16_t 12
|
||||
* reserved uint8_t[2] 14
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B400_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B400_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B400_AZIMUTH(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B400_SLOWNESS(blockette) ((float*)((uint8_t*)blockette+8))
|
||||
#define pMS2B400_CONFIGURATION(blockette) ((uint16_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B400_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 405 - beam delay
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* delay values uint16_t[1] 4
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B405_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B405_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B405_DELAYVALUES(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 500 - timing
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* VCO correction float 4
|
||||
* year uint16_t 8
|
||||
* day uint16_t 10
|
||||
* hour uint8_t 12
|
||||
* min uint8_t 13
|
||||
* sec uint8_t 14
|
||||
* unused uint8_t 15
|
||||
* fract uint16_t 16
|
||||
* microsecond int8_t 18
|
||||
* reception quality uint8_t 19
|
||||
* exception count uint32_t 20
|
||||
* exception type char[16] 24
|
||||
* clock model char[32] 40
|
||||
* clock status char[128] 72
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B500_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B500_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B500_VCOCORRECTION(blockette) ((float*)((uint8_t*)blockette+4))
|
||||
#define pMS2B500_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B500_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+10))
|
||||
#define pMS2B500_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B500_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+13))
|
||||
#define pMS2B500_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B500_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+15))
|
||||
#define pMS2B500_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+16))
|
||||
#define pMS2B500_MICROSECOND(blockette) ((int8_t*)((uint8_t*)blockette+18))
|
||||
#define pMS2B500_RECEPTIONQUALITY(blockette) ((uint8_t*)((uint8_t*)blockette+19))
|
||||
#define pMS2B500_EXCEPTIONCOUNT(blockette) ((uint32_t*)((uint8_t*)blockette+20))
|
||||
#define pMS2B500_EXCEPTIONTYPE(blockette) ((char*)((uint8_t*)blockette+24))
|
||||
#define pMS2B500_CLOCKMODEL(blockette) ((char*)((uint8_t*)blockette+40))
|
||||
#define pMS2B500_CLOCKSTATUS(blockette) ((char*)((uint8_t*)blockette+72))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 1000 - data only SEED (miniSEED)
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* encoding uint8_t 4
|
||||
* byteorder uint8_t 5
|
||||
* reclen uint8_t 6
|
||||
* reserved uint8_t 7
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B1000_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B1000_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B1000_ENCODING(blockette) ((uint8_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B1000_BYTEORDER(blockette) ((uint8_t*)((uint8_t*)blockette+5))
|
||||
#define pMS2B1000_RECLEN(blockette) ((uint8_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B1000_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+7))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 1001 - data extension
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* timing quality uint8_t 4
|
||||
* microsecond int8_t 5
|
||||
* reserved uint8_t 6
|
||||
* frame count uint8_t 7
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B1001_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B1001_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B1001_TIMINGQUALITY(blockette) ((uint8_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B1001_MICROSECOND(blockette) ((int8_t*)((uint8_t*)blockette+5))
|
||||
#define pMS2B1001_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B1001_FRAMECOUNT(blockette) ((uint8_t*)((uint8_t*)blockette+7))
|
||||
|
||||
/***************************************************************************
|
||||
* miniSEED 2.4 Blockette 2000 - opaque data
|
||||
*
|
||||
* FIELD TYPE OFFSET
|
||||
* type uint16_t 0
|
||||
* next offset uint16_t 2
|
||||
* length uint16_t 4
|
||||
* data offset uint16_t 6
|
||||
* recnum uint32_t 8
|
||||
* byteorder uint8_t 12
|
||||
* flags uint8_t 13
|
||||
* numheaders uint8_t 14
|
||||
* payload char[1] 15
|
||||
*
|
||||
* Convenience macros for accessing the fields via typed pointers follow:
|
||||
***************************************************************************/
|
||||
#define pMS2B2000_TYPE(blockette) ((uint16_t*)(blockette))
|
||||
#define pMS2B2000_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
|
||||
#define pMS2B2000_LENGTH(blockette) ((uint16_t*)((uint8_t*)blockette+4))
|
||||
#define pMS2B2000_DATAOFFSET(blockette) ((uint16_t*)((uint8_t*)blockette+6))
|
||||
#define pMS2B2000_RECNUM(blockette) ((uint32_t*)((uint8_t*)blockette+8))
|
||||
#define pMS2B2000_BYTEORDER(blockette) ((uint8_t*)((uint8_t*)blockette+12))
|
||||
#define pMS2B2000_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+13))
|
||||
#define pMS2B2000_NUMHEADERS(blockette) ((uint8_t*)((uint8_t*)blockette+14))
|
||||
#define pMS2B2000_PAYLOAD(blockette) ((char*)((uint8_t*)blockette+15))
|
||||
|
||||
/***************************************************************************
|
||||
* Simple static inline convenience functions to swap bytes to "host
|
||||
* order", as determined by the swap flag.
|
||||
***************************************************************************/
|
||||
static inline int16_t
|
||||
HO2d (int16_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap2 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline uint16_t
|
||||
HO2u (uint16_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap2 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline int32_t
|
||||
HO4d (int32_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap4 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline uint32_t
|
||||
HO4u (uint32_t value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap4 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline float
|
||||
HO4f (float value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap4 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
static inline double
|
||||
HO8f (double value, int swapflag)
|
||||
{
|
||||
if (swapflag)
|
||||
{
|
||||
ms_gswap8 (&value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Macro to test for sane year and day values, used primarily to
|
||||
* determine if byte order swapping is needed for miniSEED 2.x.
|
||||
*
|
||||
* 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.
|
||||
* If you are using this in 2056 to determine the byte order of miniSEED 2
|
||||
* you have my deepest sympathies.
|
||||
*/
|
||||
#define MS_ISVALIDYEARDAY(Y,D) (Y >= 1900 && Y <= 2100 && D >= 1 && D <= 366)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -2,25 +2,185 @@
|
||||
|
||||
All notable changes to the CAPS client library will be documented in this file.
|
||||
|
||||
## 2021-04-21 1.0.0
|
||||
## 2026.069 3.2.0
|
||||
|
||||
### Added
|
||||
|
||||
- Allow to override host operating system information
|
||||
|
||||
## 2026.068 3.1.1
|
||||
|
||||
### Added
|
||||
|
||||
- Support system load reporting
|
||||
|
||||
## 2026.057 3.1.0
|
||||
|
||||
### Added
|
||||
|
||||
- Support for CAPS API 7 features
|
||||
|
||||
## 2025.206 3.0.1
|
||||
|
||||
### Added
|
||||
|
||||
- Stream ID check. Before sending data, the stream ID is checked to ensure
|
||||
that it meets the server requirements. Specical characters like '?' are
|
||||
not allowed.
|
||||
|
||||
## 2025.163 3.0.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Make session table item start and end time optional
|
||||
|
||||
## 2024.352 2.7.4
|
||||
|
||||
### Changed
|
||||
|
||||
- Optimize package encoding
|
||||
|
||||
## 2024.226 2.7.3
|
||||
|
||||
### Fixed
|
||||
|
||||
- Parse server output address correctly
|
||||
|
||||
## 2024.162 2.7.2
|
||||
|
||||
### Fixed
|
||||
|
||||
- Do not crash when the journal file does not follow the format
|
||||
|
||||
## 2024.162 2.7.1
|
||||
|
||||
### Changed
|
||||
|
||||
- Redirect log messages to SeisComP log by default
|
||||
|
||||
## 2024.151 2.7.0
|
||||
|
||||
### Added
|
||||
|
||||
- Add plugin instance pointer to log messages
|
||||
|
||||
## 2023.184 2.6.0
|
||||
|
||||
### Added
|
||||
|
||||
- More convenience push functions
|
||||
|
||||
## 2023.184 2.5.0
|
||||
|
||||
### Added
|
||||
|
||||
- Direct API access to last acknowledged packet end time
|
||||
|
||||
## 2023.107 2.4.0
|
||||
|
||||
### Added
|
||||
|
||||
- PluginApplication class logs CAPS connection settings
|
||||
|
||||
### Changed
|
||||
|
||||
- Reworked connection handling to perfom better in poor network environments
|
||||
- Removed unnecessary debug output
|
||||
|
||||
## 2022.284 2.3.1
|
||||
|
||||
### Changed
|
||||
|
||||
- Minor changes
|
||||
|
||||
## 2022-04-20 2.3.0
|
||||
|
||||
### Added
|
||||
|
||||
- CAPS agent support
|
||||
|
||||
## 2022-04-20 2.2.0
|
||||
|
||||
### Added
|
||||
|
||||
- API function to access internal packet buffer that keeps packets until
|
||||
they have been acknowledged by CAPS
|
||||
|
||||
## 2021-09-01 2.1.0
|
||||
|
||||
### Added
|
||||
|
||||
- Extended plugin class by the possibility to dump **outgoing** RAW and MSEED
|
||||
packets to stdout. RAW data ouput is in SLIST format and MSEED packets are
|
||||
dumped as binary MSEED. Applications derived from the plugin application class
|
||||
can enable this feature with the command line option ``--dump-packets``.
|
||||
|
||||
## 2021-06-21 2.0.3
|
||||
|
||||
### Fixed
|
||||
|
||||
- CAPS Python encoder factory ownership
|
||||
|
||||
## 2021-06-15 2.0.2
|
||||
|
||||
### Fixed
|
||||
|
||||
- Broken uncompressed MSEED support
|
||||
|
||||
## 2021-05-10 2.0.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- Unit tests that work on 64-bit systems only
|
||||
|
||||
## 2021-05-10 2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Log status responses from server in plugin application
|
||||
- SSL and authentication support for plugin application.
|
||||
With this version the data output URL can be set with the
|
||||
config option ``output.address``. The formal definition of
|
||||
the field is: [[caps|capss]://][user:pass@]host[:port] e.g.
|
||||
|
||||
```script
|
||||
output.address = capss://caps:caps@localhost:18003
|
||||
```
|
||||
|
||||
The new output.address parameter superseds the output.host and
|
||||
output.port parameter of previous versions and takes precedence.
|
||||
The old parameters are kept for compatibility reasons but are
|
||||
marked as deprecated.
|
||||
|
||||
## 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.
|
||||
```
|
||||
|
||||
```script
|
||||
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.
|
||||
@@ -30,15 +190,21 @@ All notable changes to the CAPS client library will be documented in this file.
|
||||
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
|
||||
@@ -49,102 +215,144 @@ All notable changes to the CAPS client library will be documented in this file.
|
||||
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.
|
||||
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
|
||||
|
||||
### Fixed
|
||||
|
||||
- SSL support
|
||||
|
||||
## 2017-11-20
|
||||
|
||||
### Added
|
||||
- float and double support for Steim encoders. All values will be converted implicitly
|
||||
to int 32 values
|
||||
|
||||
- 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.
|
||||
|
||||
- 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
|
||||
|
||||
- Do not flush encoders after reconnect
|
||||
|
||||
## 2017-10-26
|
||||
|
||||
### Added
|
||||
|
||||
- SSL support
|
||||
|
||||
|
||||
## 2017-10-24
|
||||
|
||||
### Fixed
|
||||
- packet synchronization error after reconnect
|
||||
|
||||
- Packet synchronization error after reconnect
|
||||
|
||||
@@ -16,7 +16,7 @@ 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)
|
||||
SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES VERSION 2.0.0 SOVERSION 2)
|
||||
TARGET_LINK_LIBRARIES(${LIB_NAME} mseed)
|
||||
|
||||
INSTALL(TARGETS ${LIB_NAME} DESTINATION lib)
|
||||
|
||||
@@ -84,6 +84,11 @@ void AnyDataRecord::setSamplingFrequency(uint16_t numerator, uint16_t denominato
|
||||
}
|
||||
|
||||
|
||||
DataRecord *AnyDataRecord::clone() const {
|
||||
return new AnyDataRecord(*this);
|
||||
}
|
||||
|
||||
|
||||
const char *AnyDataRecord::formatName() const {
|
||||
return "ANY";
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#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;
|
||||
@@ -74,37 +74,37 @@ class AnyDataRecord : public DataRecord {
|
||||
bool setType(const char *type);
|
||||
const char *type() const;
|
||||
|
||||
virtual const char *formatName() const;
|
||||
DataRecord *clone() const override;
|
||||
const char *formatName() const override;
|
||||
|
||||
virtual bool readMetaData(std::streambuf &buf, int size,
|
||||
bool readMetaData(std::streambuf &buf, int size,
|
||||
Header &header,
|
||||
Time &startTime,
|
||||
Time &endTime);
|
||||
Time &endTime) override;
|
||||
|
||||
virtual const Header *header() const;
|
||||
virtual Time startTime() const;
|
||||
virtual Time endTime() const;
|
||||
const Header *header() const override;
|
||||
Time startTime() const override;
|
||||
Time endTime() const override;
|
||||
|
||||
virtual bool canTrim() const;
|
||||
virtual bool canMerge() const;
|
||||
bool canTrim() const override;
|
||||
bool canMerge() const override;
|
||||
|
||||
virtual bool trim(const Time &start,
|
||||
const Time &end) const;
|
||||
bool trim(const Time &start, const Time &end) const override;
|
||||
|
||||
virtual size_t dataSize(bool withHeader) const;
|
||||
size_t dataSize(bool withHeader) const override;
|
||||
|
||||
virtual ReadStatus get(std::streambuf &buf, int size,
|
||||
ReadStatus get(std::streambuf &buf, int size,
|
||||
const Time &start = Time(),
|
||||
const Time &end = Time(),
|
||||
int maxSize = -1);
|
||||
int maxSize = -1) override;
|
||||
|
||||
virtual bool put(std::streambuf &buf, bool withHeader) const;
|
||||
bool put(std::streambuf &buf, bool withHeader) const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the packet type
|
||||
* @return The packet type
|
||||
*/
|
||||
PacketType packetType() const { return ANYPacket; }
|
||||
PacketType packetType() const override { return ANYPacket; }
|
||||
|
||||
/**
|
||||
* @brief Sets the start time of the record
|
||||
@@ -129,14 +129,15 @@ class AnyDataRecord : public DataRecord {
|
||||
* @brief Returns the data vector to be filled by the caller
|
||||
* @return The pointer to the internal buffer
|
||||
*/
|
||||
Buffer *data() { return &_data; }
|
||||
Buffer *data() override { 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);
|
||||
void setData(char *data, size_t size);
|
||||
|
||||
|
||||
protected:
|
||||
AnyHeader _header;
|
||||
|
||||
@@ -16,11 +16,14 @@
|
||||
#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);
|
||||
@@ -99,6 +102,7 @@ class SC_GEMPA_CAPS_API Application {
|
||||
static Application *_app;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#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>
|
||||
@@ -27,12 +28,15 @@
|
||||
//#include <iostream>
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
class SessionTableItem;
|
||||
|
||||
struct SessionTableItem;
|
||||
class Time;
|
||||
|
||||
|
||||
class Connection {
|
||||
public:
|
||||
//! ConnectionStates:
|
||||
@@ -171,10 +175,12 @@ class Connection {
|
||||
bool _ssl;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Connection> ConnectionPtr;
|
||||
|
||||
using ConnectionPtr = boost::shared_ptr<Connection>;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <time.h>
|
||||
@@ -168,6 +169,26 @@ inline void normalize(T &sec, U &usec) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *timeFormats[] = {
|
||||
"%FT%T.%fZ", // YYYY-MM-DDThh:mm:ss.ssssssZ
|
||||
"%FT%T.%f", // YYYY-MM-DDThh:mm:ss.ssssss
|
||||
"%FT%TZ", // YYYY-MM-DDThh:mm:ssZ
|
||||
"%FT%T", // YYYY-MM-DDThh:mm:ss
|
||||
"%FT%R", // YYYY-MM-DDThh:mm
|
||||
"%FT%H", // YYYY-MM-DDThh
|
||||
"%Y-%jT%T.%f", // YYYY-DDDThh:mm:ss.ssssss
|
||||
"%Y-%jT%T", // YYYY-DDDThh:mm:ss
|
||||
"%Y-%jT%R", // YYYY-DDDThh:mm
|
||||
"%Y-%jT%H", // YYYY-DDDThh
|
||||
"%F %T.%f", // YYYY-MM-DD hh:mm:ss.ssssss
|
||||
"%F %T", // YYYY-MM-DD hh:mm:ss
|
||||
"%F %R", // YYYY-MM-DD hh:mm
|
||||
"%F %H", // YYYY-MM-DD hh
|
||||
"%F", // YYYY-MM-DD
|
||||
"%Y-%j", // YYYY-DDD
|
||||
"%Y", // YYYY
|
||||
};
|
||||
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
@@ -342,6 +363,17 @@ TimeSpan& TimeSpan::operator=(long t) {
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
TimeSpan& TimeSpan::operator=(const TimeSpan& t) {
|
||||
_timeval = t._timeval;
|
||||
|
||||
return *this;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
TimeSpan& TimeSpan::operator=(double t) {
|
||||
if( t > (double)0x7fffffff || t < -(double)0x80000000 )
|
||||
@@ -802,16 +834,9 @@ Time& Time::localtime() {
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
Time &Time::gmt() {
|
||||
gettimeofday(&_timeval, NULL);
|
||||
time_t secs = (time_t)_timeval.tv_sec;
|
||||
struct tm _tm;
|
||||
#ifndef WIN32
|
||||
_timeval.tv_sec = (long)mktime(::localtime_r(&secs, &_tm));
|
||||
#else
|
||||
// We use the native localtime function of windows, which is thread safe. (But it's not reentrant)
|
||||
_timeval.tv_sec = (long)timegm(::localtime(&secs));
|
||||
#endif
|
||||
|
||||
auto us = chrono::duration_cast<chrono::microseconds>(chrono::high_resolution_clock::now().time_since_epoch()).count();
|
||||
_timeval.tv_sec = us / 1000000;
|
||||
_timeval.tv_usec = us % 1000000;
|
||||
return *this;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
@@ -1055,9 +1080,50 @@ bool Time::fromString(const char* str, const char* fmt) {
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
bool Time::fromString(const char* str) {
|
||||
for ( size_t i = 0; i < sizeof(timeFormats) / sizeof(const char*); ++i ) {
|
||||
if ( fromString(str, timeFormats[i]) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
bool Time::fromString(const std::string& str) {
|
||||
return fromString(str.c_str());
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
Time Time::FromString(const char* str, const char* fmt) {
|
||||
Time t;
|
||||
t.fromString(str, fmt);
|
||||
return t;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
Time Time::FromString(const char* str) {
|
||||
Time t;
|
||||
t.fromString(str);
|
||||
return t;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
Time Time::FromString(const std::string& str) {
|
||||
return FromString(str.c_str());
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifndef GEMPA_CAPS_DATETIME_H
|
||||
#define GEMPA_CAPS_DATETIME_H
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
@@ -24,8 +25,10 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
struct tm;
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
@@ -64,6 +67,7 @@ class TimeSpan {
|
||||
//! Assignment
|
||||
TimeSpan& operator=(long t);
|
||||
TimeSpan& operator=(double t);
|
||||
TimeSpan& operator=(const TimeSpan& t);
|
||||
|
||||
//! Arithmetic
|
||||
TimeSpan operator+(const TimeSpan&) const;
|
||||
@@ -205,24 +209,25 @@ class Time : public TimeSpan {
|
||||
//! 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
|
||||
/**
|
||||
* @brief 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
|
||||
* @brief 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.
|
||||
* @brief 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)
|
||||
@@ -230,11 +235,37 @@ class Time : public TimeSpan {
|
||||
*/
|
||||
bool fromString(const char* str, const char* fmt);
|
||||
|
||||
/**
|
||||
* @brief Converts a string into a time representation trying a common
|
||||
* set of date formats.
|
||||
* @param str The string representation of the time.
|
||||
* @return The conversion result
|
||||
*/
|
||||
bool fromString(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Convenience method for fromString(const char*).
|
||||
*/
|
||||
bool fromString(const std::string& str);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @brief Static methods that converts a string into a time
|
||||
* representation trying a common set of date formats.
|
||||
* @param str The string representation of the time.
|
||||
* @return The conversion result
|
||||
*/
|
||||
static Time FromString(const char* str);
|
||||
|
||||
/**
|
||||
* @brief Convenience method for FromString(const char*).
|
||||
*/
|
||||
static Time FromString(const std::string& str);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ const string& EncoderFactory::errorString() const {
|
||||
MSEEDEncoderFactory::MSEEDEncoderFactory()
|
||||
: _recordLength(9) {}
|
||||
|
||||
bool MSEEDEncoderFactory::setRecordLength(uint recordLength) {
|
||||
bool MSEEDEncoderFactory::setRecordLength(unsigned int recordLength) {
|
||||
if ( recordLength < 7 || recordLength > 32) {
|
||||
_errorString = "MSEED record length out of range [7, 32]";
|
||||
return false;
|
||||
|
||||
@@ -12,16 +12,19 @@
|
||||
* from gempa GmbH. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef GEMPA_CAPS_ENCODERFACTORY_H
|
||||
#define GEMPA_CAPS_ENCODERFACTORY_H
|
||||
|
||||
#include "mseed/encoder.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
|
||||
@@ -84,7 +87,7 @@ class MSEEDEncoderFactory : public EncoderFactory {
|
||||
* @param recLen The record length expressed as a power of 2
|
||||
* @return True if the record length is valid
|
||||
*/
|
||||
bool setRecordLength(uint recordLength);
|
||||
bool setRecordLength(unsigned int recordLength);
|
||||
|
||||
protected:
|
||||
uint8_t _recordLength;
|
||||
@@ -158,7 +161,9 @@ class Steim2EncoderFactory : public SteimEncoderFactory {
|
||||
int samplingFrequencyDenominator);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifndef GEMPA_CAPS_ENDIANESS_H
|
||||
#define GEMPA_CAPS_ENDIANESS_H
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <streambuf>
|
||||
@@ -25,6 +26,7 @@ namespace Gempa {
|
||||
namespace CAPS {
|
||||
namespace Endianess {
|
||||
|
||||
|
||||
template <typename T1, typename T2> inline const T1* lvalue(const T2 &value) {
|
||||
return reinterpret_cast<const T1*>(&value);
|
||||
}
|
||||
@@ -203,8 +205,10 @@ struct Writer {
|
||||
bool good;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,10 @@ MetaDataRecord::Buffer *MetaDataRecord::data() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DataRecord *MetaDataRecord::clone() const {
|
||||
return new MetaDataRecord(*this);
|
||||
}
|
||||
|
||||
const char *MetaDataRecord::formatName() const {
|
||||
return "META";
|
||||
}
|
||||
|
||||
@@ -16,18 +16,17 @@
|
||||
#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>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
struct SC_GEMPA_CAPS_API MetaResponseHeader {
|
||||
struct Time {
|
||||
int64_t seconds;
|
||||
@@ -95,15 +94,16 @@ class MetaDataRecord : public DataRecord {
|
||||
//! Returns the data vector to be filled by the caller
|
||||
Buffer *data();
|
||||
|
||||
virtual const char *formatName() const;
|
||||
DataRecord *clone() const override;
|
||||
const char *formatName() const override;
|
||||
|
||||
virtual bool readMetaData(std::streambuf &buf, int size,
|
||||
bool readMetaData(std::streambuf &buf, int size,
|
||||
Header &header,
|
||||
Time &startTime, Time &endTime) {
|
||||
Time &startTime, Time &endTime) override {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const Header *header() const;
|
||||
const Header *header() const override;
|
||||
|
||||
//! Sets a custom header and updates all internal structures
|
||||
//! based on the current data. If the data has changed, make
|
||||
@@ -111,23 +111,24 @@ class MetaDataRecord : public DataRecord {
|
||||
//! is set get will not read the header information from stream
|
||||
void setHeader(const MetaHeader &header);
|
||||
|
||||
virtual Time startTime() const;
|
||||
virtual Time endTime() const;
|
||||
Time startTime() const override;
|
||||
Time endTime() const override;
|
||||
|
||||
virtual bool canTrim() const { return false; }
|
||||
virtual bool canMerge() const { return false; }
|
||||
bool canTrim() const override { return false; }
|
||||
bool canMerge() const override { return false; }
|
||||
|
||||
virtual bool trim(const Time &start, const Time &end) const { return false; }
|
||||
bool trim(const Time &start, const Time &end) const override { return false; }
|
||||
|
||||
virtual size_t dataSize(bool withHeader) const;
|
||||
size_t dataSize(bool withHeader) const override;
|
||||
|
||||
virtual ReadStatus get(std::streambuf &buf, int size,
|
||||
ReadStatus get(std::streambuf &buf, int size,
|
||||
const Time &start, const Time &end,
|
||||
int maxBytes);
|
||||
int maxBytes) override;
|
||||
|
||||
virtual bool put(std::streambuf &buf, bool withHeader) const { return false; }
|
||||
bool put(std::streambuf &buf, bool withHeader) const override { return false; }
|
||||
|
||||
PacketType packetType() const override { return MetaDataPacket; }
|
||||
|
||||
PacketType packetType() const { return MetaDataPacket; }
|
||||
|
||||
private:
|
||||
MetaHeader _header;
|
||||
@@ -136,6 +137,7 @@ class MetaDataRecord : public DataRecord {
|
||||
mutable Time _endTime;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,11 @@ namespace CAPS {
|
||||
|
||||
class Encoder {
|
||||
public:
|
||||
Encoder(int freqn, int freqd) : _clk(freqn, freqd),
|
||||
_sampleCount(0), _timingQuality(-1) {}
|
||||
Encoder(int freqn, int freqd)
|
||||
: _clk(freqn, freqd)
|
||||
, _sampleCount(0), _timingQuality(-1)
|
||||
, _context{nullptr} {}
|
||||
|
||||
virtual ~Encoder() {}
|
||||
|
||||
virtual void push(void *sample) = 0;
|
||||
@@ -46,16 +49,21 @@ class Encoder {
|
||||
|
||||
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); }
|
||||
void setStartTime(const Time &time) { _clk.syncTime(time); }
|
||||
const Time currentTime() const { return _clk.getTime(0); }
|
||||
|
||||
int timingQuality() { return _timingQuality; }
|
||||
void setTimingQuality(int quality) { _timingQuality = quality; }
|
||||
int timingQuality() { return _timingQuality; }
|
||||
|
||||
void setContext(void *context) { _context = context; }
|
||||
|
||||
PacketPtr pop() {
|
||||
if ( _packetQueue.empty() ) return PacketPtr();
|
||||
if ( _packetQueue.empty() ) {
|
||||
return PacketPtr();
|
||||
}
|
||||
|
||||
PacketPtr rec = _packetQueue.front();
|
||||
rec->context = _context;
|
||||
_packetQueue.pop_front();
|
||||
return rec;
|
||||
}
|
||||
@@ -66,6 +74,7 @@ class Encoder {
|
||||
int _sampleCount;
|
||||
PacketQueue _packetQueue;
|
||||
int _timingQuality;
|
||||
void *_context;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include <gempa/caps/mseedpacket.h>
|
||||
#include <gempa/caps/rawpacket.h>
|
||||
|
||||
#include "mseed.h"
|
||||
#include "slink.h"
|
||||
@@ -27,23 +26,26 @@
|
||||
#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,
|
||||
unsigned short packType,
|
||||
uint8_t recordLength)
|
||||
: networkCode(netcode), stationCode(stacode), locationCode(loccode),
|
||||
channelCode(chacode), packType(packtype_init), recordLength(recordLength)
|
||||
: networkCode(netcode)
|
||||
, stationCode(stacode)
|
||||
, locationCode(loccode)
|
||||
, channelCode(chacode)
|
||||
, packType(packType)
|
||||
, recordLength(recordLength)
|
||||
{
|
||||
if(freqn == 0 || freqd == 0) {
|
||||
sample_rate_factor = 0;
|
||||
@@ -63,8 +65,10 @@ MSEEDFormat::MSEEDFormat(const std::string &netcode, const std::string &stacode,
|
||||
}
|
||||
}
|
||||
|
||||
MSEEDDataRecord *MSEEDFormat::get_buffer(const SPClock::INT_TIME &it, int usec_correction,
|
||||
int timing_quality, void *&dataptr, int &datalen) {
|
||||
|
||||
MSEEDDataRecord *MSEEDFormat::getBuffer(const 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);
|
||||
@@ -139,9 +143,8 @@ MSEEDDataRecord *MSEEDFormat::get_buffer(const SPClock::INT_TIME &it, int usec_c
|
||||
|
||||
void MSEEDFormat::updateBuffer(MSEEDDataRecord *rec, int samples, int frames) {
|
||||
sl_fsdh_s* fsdh = (sl_fsdh_s *)rec->data()->data();
|
||||
char temp[7];
|
||||
char temp[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
sprintf(temp, "%06d", (int)0);
|
||||
memcpy(fsdh->sequence_number, temp, 6);
|
||||
fsdh->dhq_indicator = 'D';
|
||||
fsdh->num_samples = htons(samples);
|
||||
@@ -151,12 +154,12 @@ void MSEEDFormat::updateBuffer(MSEEDDataRecord *rec, int samples, int frames) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,16 +58,16 @@ struct MSEEDFormat {
|
||||
|
||||
template<class T>
|
||||
MSEEDEncoderPacket<T>
|
||||
get_packet(const SPClock::INT_TIME &it, int usec_correction, int timing_quality) {
|
||||
getPacket(const 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);
|
||||
MSEEDDataRecord *rec = getBuffer(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,
|
||||
MSEEDDataRecord *getBuffer(const Time &it, int usec_correction,
|
||||
int timing_quality,
|
||||
void *&dataptr, int &datalen);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef CAPS_MSEED_SPCLOCK_H
|
||||
#define CAPS_MSEED_SPCLOCK_H
|
||||
|
||||
@@ -28,46 +29,38 @@ namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
class SPClock
|
||||
{
|
||||
class SPClock {
|
||||
public:
|
||||
typedef Gempa::CAPS::Time INT_TIME;
|
||||
SPClock(int freqn, int freqd)
|
||||
: freqn(freqn), freqd(freqd) {}
|
||||
|
||||
private:
|
||||
INT_TIME itime;
|
||||
int ticks;
|
||||
int corr;
|
||||
void syncTime(const Time &time) {
|
||||
_itime = time;
|
||||
_ticks = 0;
|
||||
_corr = 0;
|
||||
}
|
||||
|
||||
void tick() {
|
||||
++_ticks;
|
||||
}
|
||||
|
||||
Time getTime(int tickDiff) const {
|
||||
int64_t correctness = (double)freqd / (double)freqn * 1000000 * (_ticks - tickDiff - _corr);
|
||||
return _itime + TimeSpan(long(correctness / 1000000), long(correctness % 1000000));
|
||||
}
|
||||
|
||||
int correction() const {
|
||||
return _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;
|
||||
}
|
||||
private:
|
||||
Time _itime;
|
||||
int _ticks{0};
|
||||
int _corr{0};
|
||||
};
|
||||
|
||||
|
||||
@@ -75,4 +68,4 @@ class SPClock
|
||||
}
|
||||
|
||||
|
||||
#endif // SPCLOCK_H
|
||||
#endif
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace CAPS {
|
||||
//*****************************************************************************
|
||||
|
||||
struct Steim1Frame {
|
||||
u_int32_t nibble_word;
|
||||
u_int32_t sample_word[15];
|
||||
u_int32_t nibbleWord;
|
||||
u_int32_t sampleWord[15];
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -43,42 +43,44 @@ struct Steim1Frame {
|
||||
|
||||
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) {}
|
||||
: Encoder(freqn, freqd), _format(format), _frameCount(0)
|
||||
, _bp(0), _fp(0), _spw(4), _lastSample(0), _nibbleWord(0) {}
|
||||
virtual ~Steim1Encoder();
|
||||
|
||||
virtual void flush();
|
||||
virtual void push(void *value);
|
||||
virtual int type() const { return DE_STEIM1; }
|
||||
|
||||
private:
|
||||
void updateSpw(int bp);
|
||||
void store(int32_t value);
|
||||
void initPacket();
|
||||
void updatePacket();
|
||||
void finishPacket();
|
||||
|
||||
MSEEDEncoderPacket<Steim1Frame> getPacket() {
|
||||
return _format->getPacket<Steim1Frame>(_clk.getTime(_bp),
|
||||
_clk.correction(), _timingQuality);
|
||||
}
|
||||
|
||||
void queuePacket(MSEEDEncoderPacket<Steim1Frame> &pckt);
|
||||
|
||||
int numberOfFrames(const MSEEDEncoderPacket<Steim1Frame> &packet) {
|
||||
return (packet.datalen >> 6);
|
||||
}
|
||||
|
||||
private:
|
||||
MSEEDFormat *_format;
|
||||
int _frameCount;
|
||||
int _bp;
|
||||
int _fp;
|
||||
int _spw;
|
||||
int32_t _lastSample;
|
||||
int32_t _buf[5];
|
||||
u_int32_t _nibbleWord;
|
||||
MSEEDEncoderPacket<Steim1Frame> _currentPacket;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -27,158 +27,181 @@
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
template<typename T> Steim1Encoder<T>::~Steim1Encoder() {
|
||||
if ( format != NULL ) delete format;
|
||||
template<typename T>
|
||||
Steim1Encoder<T>::~Steim1Encoder() {
|
||||
if ( _format ) {
|
||||
delete _format;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> void Steim1Encoder<T>::update_spw(int bp) {
|
||||
int spw1 = 4;
|
||||
template<typename T>
|
||||
void Steim1Encoder<T>::updateSpw(int bp) {
|
||||
int spw = 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;
|
||||
if ( _buf[bp] < -32768 || _buf[bp] > 32767 ) spw = 1;
|
||||
else if ( _buf[bp] < -128 || _buf[bp] > 127 ) spw = 2;
|
||||
if ( spw < _spw ) _spw = spw;
|
||||
}
|
||||
|
||||
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>::store(int32_t value) {
|
||||
assert(_bp < 4);
|
||||
_buf[_bp] = value - _lastSample;
|
||||
_lastSample = value;
|
||||
updateSpw(_bp);
|
||||
++_bp;
|
||||
}
|
||||
|
||||
template<typename T> void Steim1Encoder<T>::init_packet() {
|
||||
template<typename T>
|
||||
void Steim1Encoder<T>::initPacket() {
|
||||
int i;
|
||||
int32_t begin_sample = last_sample;
|
||||
int32_t beginSample = _lastSample;
|
||||
|
||||
for(i = 1; i < bp; ++i) {
|
||||
begin_sample -= buf[i];
|
||||
for ( i = 1; i < _bp; ++i ) {
|
||||
beginSample -= _buf[i];
|
||||
}
|
||||
|
||||
reset();
|
||||
current_packet.data[0].sample_word[0] = htonl(begin_sample);
|
||||
frame_count = 0;
|
||||
nibble_word = 0;
|
||||
fp = 2;
|
||||
_currentPacket.data[0].sampleWord[0] = htonl(beginSample);
|
||||
_frameCount = 0;
|
||||
_nibbleWord = 0;
|
||||
_fp = 2;
|
||||
}
|
||||
|
||||
template<typename T> void Steim1Encoder<T>::finish_packet() {
|
||||
template<typename T>
|
||||
void Steim1Encoder<T>::finishPacket() {
|
||||
int i;
|
||||
int32_t end_sample = last_sample;
|
||||
int32_t endSample = _lastSample;
|
||||
|
||||
for(i = 0; i < bp; ++i) {
|
||||
end_sample -= buf[i];
|
||||
for ( i = 0; i < _bp; ++i ) {
|
||||
endSample -= _buf[i];
|
||||
}
|
||||
|
||||
current_packet.data[0].sample_word[1] = htonl(end_sample);
|
||||
_currentPacket.data[0].sampleWord[1] = htonl(endSample);
|
||||
}
|
||||
|
||||
template<typename T> void Steim1Encoder<T>::update_packet() {
|
||||
template<typename T>
|
||||
void Steim1Encoder<T>::updatePacket() {
|
||||
unsigned int nibble = 0;
|
||||
u_int32_t sample_word = 0;
|
||||
u_int32_t sampleWord = 0;
|
||||
|
||||
assert(bp < 5);
|
||||
assert(_bp < 5);
|
||||
|
||||
int used = bp;
|
||||
int used = _bp;
|
||||
|
||||
while(used > spw) {
|
||||
while ( used > _spw ) {
|
||||
--used;
|
||||
spw = 4;
|
||||
for(int i = 0; i < used; ++i) update_spw(i);
|
||||
_spw = 4;
|
||||
for ( int i = 0; i < used; ++i ) {
|
||||
updateSpw(i);
|
||||
}
|
||||
}
|
||||
|
||||
while(used < spw) spw >>= 1;
|
||||
while ( used < _spw ) {
|
||||
_spw >>= 1;
|
||||
}
|
||||
|
||||
used = spw;
|
||||
used = _spw;
|
||||
|
||||
switch(spw) {
|
||||
switch ( _spw ) {
|
||||
case 4:
|
||||
nibble = 1;
|
||||
sample_word = ((buf[0] & 0xff) << 24) | ((buf[1] & 0xff) << 16) |
|
||||
((buf[2] & 0xff) << 8) | (buf[3] & 0xff);
|
||||
sampleWord = ((_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);
|
||||
sampleWord = ((_buf[0] & 0xffff) << 16) | (_buf[1] & 0xffff);
|
||||
break;
|
||||
case 1:
|
||||
nibble = 3;
|
||||
sample_word = buf[0];
|
||||
sampleWord = _buf[0];
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
nibble_word |= (nibble << (30 - ((fp + 1) << 1)));
|
||||
_nibbleWord |= (nibble << (30 - ((_fp + 1) << 1)));
|
||||
|
||||
spw = 4;
|
||||
for(int i = 0; i < bp - used; ++i) {
|
||||
buf[i] = buf[i + used];
|
||||
update_spw(i);
|
||||
_spw = 4;
|
||||
for ( int i = 0; i < _bp - used; ++i ) {
|
||||
_buf[i] = _buf[i + used];
|
||||
updateSpw(i);
|
||||
}
|
||||
|
||||
bp -= used;
|
||||
_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;
|
||||
_currentPacket.data[_frameCount].nibbleWord = htonl(_nibbleWord);
|
||||
_currentPacket.data[_frameCount].sampleWord[_fp] = htonl(sampleWord);
|
||||
|
||||
nibble_word = 0;
|
||||
fp = 0;
|
||||
++frame_count;
|
||||
if ( ++_fp < 15 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T> void Steim1Encoder<T>::queue_packet(MSEEDEncoderPacket<Steim1Frame> &pckt) {
|
||||
format->updateBuffer(pckt.record, _sampleCount, frame_count + (fp > 0));
|
||||
_nibbleWord = 0;
|
||||
_fp = 0;
|
||||
++_frameCount;
|
||||
|
||||
Packet *packet = new Packet(DataRecordPtr(pckt.record), format->networkCode, format->stationCode,
|
||||
format->locationCode, format->channelCode);
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Steim1Encoder<T>::queuePacket(MSEEDEncoderPacket<Steim1Frame> &pckt) {
|
||||
_format->updateBuffer(pckt.record, _sampleCount, _frameCount + (_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) {
|
||||
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();
|
||||
while ( _bp >= _spw ) {
|
||||
if ( !_currentPacket.valid() ) {
|
||||
_currentPacket = getPacket();
|
||||
initPacket();
|
||||
}
|
||||
|
||||
update_packet();
|
||||
if(frame_count == number_of_frames(current_packet)) {
|
||||
finish_packet();
|
||||
queue_packet(current_packet);
|
||||
updatePacket();
|
||||
if ( _frameCount == numberOfFrames(_currentPacket) ) {
|
||||
finishPacket();
|
||||
queuePacket(_currentPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> void Steim1Encoder<T>::flush() {
|
||||
while(bp) {
|
||||
if(!current_packet.valid()) {
|
||||
current_packet = get_packet();
|
||||
init_packet();
|
||||
template<typename T>
|
||||
void Steim1Encoder<T>::flush() {
|
||||
while ( _bp ) {
|
||||
if ( !_currentPacket.valid() ) {
|
||||
_currentPacket = getPacket();
|
||||
initPacket();
|
||||
}
|
||||
|
||||
update_packet();
|
||||
if(frame_count == number_of_frames(current_packet)) {
|
||||
finish_packet();
|
||||
queue_packet(current_packet);
|
||||
updatePacket();
|
||||
if ( _frameCount == numberOfFrames(_currentPacket) ) {
|
||||
finishPacket();
|
||||
queuePacket(_currentPacket);
|
||||
}
|
||||
}
|
||||
|
||||
if(current_packet.valid()) {
|
||||
finish_packet();
|
||||
queue_packet(current_packet);
|
||||
if ( _currentPacket.valid() ) {
|
||||
finishPacket();
|
||||
queuePacket(_currentPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace CAPS {
|
||||
//*****************************************************************************
|
||||
|
||||
struct Steim2Frame {
|
||||
u_int32_t nibble_word;
|
||||
u_int32_t sample_word[15];
|
||||
u_int32_t nibbleWord;
|
||||
u_int32_t sampleWord[15];
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -43,8 +43,8 @@ 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) {
|
||||
: Encoder(freqn, freqd), _format(format), _frameCount(0)
|
||||
, _bp(0), _fp(0), _spw(4), _lastSample(0), _nibbleWord(0) {
|
||||
}
|
||||
virtual ~Steim2Encoder();
|
||||
virtual void flush();
|
||||
@@ -53,34 +53,34 @@ class Steim2Encoder : public Encoder {
|
||||
virtual int type() const { return DE_STEIM2; }
|
||||
|
||||
private:
|
||||
void update_spw(int bp);
|
||||
void updateSpw(int bp);
|
||||
void store(int32_t value);
|
||||
void init_packet();
|
||||
void finish_packet();
|
||||
void update_packet();
|
||||
void initPacket();
|
||||
void updatePacket();
|
||||
void finishPacket();
|
||||
|
||||
MSEEDEncoderPacket<Steim2Frame> get_packet() {
|
||||
return format->get_packet<Steim2Frame>(_clk.get_time(bp),
|
||||
MSEEDEncoderPacket<Steim2Frame> getPacket() {
|
||||
return _format->getPacket<Steim2Frame>(_clk.getTime(_bp),
|
||||
_clk.correction(), _timingQuality);
|
||||
}
|
||||
|
||||
void queue_packet(MSEEDEncoderPacket<Steim2Frame> &pckt);
|
||||
void queuePacket(MSEEDEncoderPacket<Steim2Frame> &pckt);
|
||||
|
||||
int number_of_frames(const MSEEDEncoderPacket<Steim2Frame> &packet) {
|
||||
int numberOfFrames(const MSEEDEncoderPacket<Steim2Frame> &packet) const {
|
||||
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;
|
||||
MSEEDFormat *_format;
|
||||
int _frameCount;
|
||||
int _bp;
|
||||
int _fp;
|
||||
int32_t _last_s;
|
||||
int _spw;
|
||||
int32_t _lastSample;
|
||||
int32_t _buf[8];
|
||||
u_int32_t _nibbleWord;
|
||||
MSEEDEncoderPacket<Steim2Frame> _currentPacket;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -32,163 +32,174 @@ namespace CAPS {
|
||||
|
||||
|
||||
template<typename T> Steim2Encoder<T>::~Steim2Encoder() {
|
||||
if ( format != NULL ) delete format;
|
||||
if ( _format ) {
|
||||
delete _format;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::update_spw(int bp) {
|
||||
template<typename T> void Steim2Encoder<T>::updateSpw(int bp) {
|
||||
assert(bp < 7);
|
||||
|
||||
if(buf[bp] < -536870912) {
|
||||
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;
|
||||
_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) {
|
||||
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;
|
||||
_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;
|
||||
int spw = 7;
|
||||
if ( _buf[bp] < -16384 || _buf[bp] > 16383 ) spw = 1;
|
||||
else if ( _buf[bp] < -512 || _buf[bp] > 511 ) spw = 2;
|
||||
else if ( _buf[bp] < -128 || _buf[bp] > 127 ) spw = 3;
|
||||
else if ( _buf[bp] < -32 || _buf[bp] > 31 ) spw = 4;
|
||||
else if ( _buf[bp] < -16 || _buf[bp] > 15 ) spw = 5;
|
||||
else if ( _buf[bp] < -8 || _buf[bp] > 7 ) spw = 6;
|
||||
if ( spw < _spw ) _spw = spw;
|
||||
}
|
||||
|
||||
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;
|
||||
assert(_bp < 7);
|
||||
_buf[_bp] = value - _lastSample;
|
||||
_lastSample = value;
|
||||
updateSpw(_bp);
|
||||
++_bp;
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::init_packet() {
|
||||
template<typename T> void Steim2Encoder<T>::initPacket() {
|
||||
int i;
|
||||
int32_t begin_sample = last_sample;
|
||||
int32_t begin_sample = _lastSample;
|
||||
|
||||
for(i = 1; i < bp; ++i) {
|
||||
begin_sample -= buf[i];
|
||||
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;
|
||||
_currentPacket.data[0].sampleWord[0] = htonl(begin_sample);
|
||||
_frameCount = 0;
|
||||
_nibbleWord = 0;
|
||||
_fp = 2;
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::finish_packet() {
|
||||
template<typename T> void Steim2Encoder<T>::finishPacket() {
|
||||
int i;
|
||||
int32_t end_sample = last_sample;
|
||||
int32_t endSample = _lastSample;
|
||||
|
||||
for(i = 0; i < bp; ++i) {
|
||||
end_sample -= buf[i];
|
||||
for ( i = 0; i < _bp; ++i ) {
|
||||
endSample -= _buf[i];
|
||||
}
|
||||
|
||||
current_packet.data[0].sample_word[1] = htonl(end_sample);
|
||||
_currentPacket.data[0].sampleWord[1] = htonl(endSample);
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::update_packet() {
|
||||
template<typename T> void Steim2Encoder<T>::updatePacket() {
|
||||
unsigned int nibble = 0;
|
||||
u_int32_t sample_word = 0;
|
||||
u_int32_t sampleWord = 0;
|
||||
|
||||
assert(bp < 8);
|
||||
assert(_bp < 8);
|
||||
|
||||
int used = bp;
|
||||
int used = _bp;
|
||||
|
||||
while(used > spw) {
|
||||
while ( used > _spw ) {
|
||||
--used;
|
||||
spw = 7;
|
||||
for(int i = 0; i < used; ++i) update_spw(i);
|
||||
_spw = 7;
|
||||
|
||||
for ( int i = 0; i < used; ++i ) {
|
||||
updateSpw(i);
|
||||
}
|
||||
}
|
||||
|
||||
spw = used;
|
||||
_spw = used;
|
||||
|
||||
switch(spw) {
|
||||
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);
|
||||
sampleWord = (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);
|
||||
sampleWord = (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);
|
||||
sampleWord = ((_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);
|
||||
sampleWord = ((_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);
|
||||
sampleWord = (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);
|
||||
sampleWord = (2U << 30) | ((_buf[0] & 0x7fff) << 15) |
|
||||
(_buf[1] & 0x7fff);
|
||||
break;
|
||||
case 1:
|
||||
nibble = 2;
|
||||
sample_word = (1U << 30) | (buf[0] & 0x3fffffff);
|
||||
sampleWord = (1U << 30) | (_buf[0] & 0x3fffffff);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
nibble_word |= (nibble << (30 - ((fp + 1) << 1)));
|
||||
_nibbleWord |= (nibble << (30 - ((_fp + 1) << 1)));
|
||||
|
||||
spw = 7;
|
||||
for(int i = 0; i < bp - used; ++i) {
|
||||
buf[i] = buf[i + used];
|
||||
update_spw(i);
|
||||
_spw = 7;
|
||||
for ( int i = 0; i < _bp - used; ++i ) {
|
||||
_buf[i] = _buf[i + used];
|
||||
updateSpw(i);
|
||||
}
|
||||
|
||||
bp -= used;
|
||||
_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;
|
||||
_currentPacket.data[_frameCount].nibbleWord = htonl(_nibbleWord);
|
||||
_currentPacket.data[_frameCount].sampleWord[_fp] = htonl(sampleWord);
|
||||
|
||||
nibble_word = 0;
|
||||
fp = 0;
|
||||
++frame_count;
|
||||
if ( ++_fp < 15 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::queue_packet(MSEEDEncoderPacket<Steim2Frame> &pckt) {
|
||||
format->updateBuffer(pckt.record, _sampleCount, frame_count + (fp > 0));
|
||||
_nibbleWord = 0;
|
||||
_fp = 0;
|
||||
++_frameCount;
|
||||
|
||||
Packet *packet = new Packet(DataRecordPtr(pckt.record), format->networkCode, format->stationCode,
|
||||
format->locationCode, format->channelCode);
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::queuePacket(MSEEDEncoderPacket<Steim2Frame> &pckt) {
|
||||
_format->updateBuffer(pckt.record, _sampleCount, _frameCount + (_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();
|
||||
@@ -200,37 +211,37 @@ template<typename T> void Steim2Encoder<T>::push(void *value) {
|
||||
store(sample_val);
|
||||
_clk.tick();
|
||||
|
||||
while ( bp >= spw ) {
|
||||
if( !current_packet.valid() ) {
|
||||
current_packet = get_packet();
|
||||
init_packet();
|
||||
while ( _bp >= _spw ) {
|
||||
if ( !_currentPacket.valid() ) {
|
||||
_currentPacket = getPacket();
|
||||
initPacket();
|
||||
}
|
||||
|
||||
update_packet();
|
||||
if ( frame_count == number_of_frames(current_packet) ) {
|
||||
finish_packet();
|
||||
queue_packet(current_packet);
|
||||
updatePacket();
|
||||
if ( _frameCount == numberOfFrames(_currentPacket) ) {
|
||||
finishPacket();
|
||||
queuePacket(_currentPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> void Steim2Encoder<T>::flush() {
|
||||
while ( bp ) {
|
||||
if ( !current_packet.valid() ) {
|
||||
current_packet = get_packet();
|
||||
init_packet();
|
||||
while ( _bp ) {
|
||||
if ( !_currentPacket.valid() ) {
|
||||
_currentPacket = getPacket();
|
||||
initPacket();
|
||||
}
|
||||
|
||||
update_packet();
|
||||
if( frame_count == number_of_frames(current_packet) ) {
|
||||
finish_packet();
|
||||
queue_packet(current_packet);
|
||||
updatePacket();
|
||||
if ( _frameCount == numberOfFrames(_currentPacket) ) {
|
||||
finishPacket();
|
||||
queuePacket(_currentPacket);
|
||||
}
|
||||
}
|
||||
|
||||
if ( current_packet.valid() ) {
|
||||
finish_packet();
|
||||
queue_packet(current_packet);
|
||||
if ( _currentPacket.valid() ) {
|
||||
finishPacket();
|
||||
queuePacket(_currentPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,28 +12,29 @@
|
||||
* 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),
|
||||
return _format->getPacket<T>(_clk.getTime(-_bp),
|
||||
_clk.correction(), _timingQuality);
|
||||
}
|
||||
|
||||
void queue_packet(MSEEDEncoderPacket<T> &pckt) {
|
||||
void queuePacket(MSEEDEncoderPacket<T> &pckt) {
|
||||
_format->updateBuffer(pckt.record, _sampleCount, 1);
|
||||
|
||||
Packet *packet = new Packet(DataRecordPtr(pckt.record), _format->networkCode, _format->stationCode,
|
||||
@@ -51,7 +52,7 @@ template<typename T> class UncompressedMSEED : public Encoder {
|
||||
virtual ~UncompressedMSEED() { if ( _format ) delete _format; }
|
||||
virtual void flush() {
|
||||
if ( _current_packet.valid() ) {
|
||||
queue_packet(_current_packet);
|
||||
queuePacket(_current_packet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +79,9 @@ template<typename T> class UncompressedMSEED : public Encoder {
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // __STEIM1_H__
|
||||
|
||||
@@ -13,16 +13,24 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <gempa/caps/endianess.h>
|
||||
#include <gempa/caps/mseedpacket.h>
|
||||
#include <gempa/caps/log.h>
|
||||
#include <gempa/caps/utils.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <numeric>
|
||||
#include <streambuf>
|
||||
#include <iostream>
|
||||
#include <libmseed.h>
|
||||
|
||||
namespace {
|
||||
// Force local include
|
||||
#include "./3rd-party/libmseed/libmseed.h"
|
||||
#include "./3rd-party/libmseed/mseedformat.h"
|
||||
|
||||
|
||||
#define MS_ISVALIDYEARDAY(Y,D) (Y >= 1900 && Y <= 2100 && D >= 1 && D <= 366)
|
||||
|
||||
#define LOG_SID(FUNC, format,...)\
|
||||
do {\
|
||||
@@ -30,44 +38,151 @@ do {\
|
||||
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);\
|
||||
ms_strncpclean(n, pMS2FSDH_NETWORK(head), 2);\
|
||||
ms_strncpclean(s, pMS2FSDH_STATION(head), 5);\
|
||||
ms_strncpclean(l, pMS2FSDH_LOCATION(head), 2);\
|
||||
ms_strncpclean(c, pMS2FSDH_CHANNEL(head), 3);\
|
||||
FUNC("[%s.%s.%s.%s] " format, n, s, l, c, ##__VA_ARGS__);\
|
||||
} while(0)
|
||||
|
||||
}
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
uint16_t ms2_blktlen(uint16_t blkttype, const char *blkt, int8_t 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 ) {
|
||||
blktlen = *reinterpret_cast<const uint16_t*>(blkt + 4);
|
||||
if ( swapflag ) {
|
||||
ms_gswap2(&blktlen);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return blktlen;
|
||||
}
|
||||
|
||||
|
||||
bool double2frac(uint16_t &numerator, uint16_t &denominator, double value) {
|
||||
using namespace std;
|
||||
|
||||
// Check numeric limits
|
||||
if ( value > numeric_limits<uint16_t>::max() ) {
|
||||
numerator = numeric_limits<uint16_t>::max();
|
||||
denominator = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( value < numeric_limits<uint16_t>::min() ) {
|
||||
numerator = numeric_limits<uint16_t>::min();
|
||||
denominator = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Operate on positive numbers
|
||||
int sign = 1;
|
||||
if ( value < 0 ) {
|
||||
sign = -1;
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// Calculatate the largest possible power of 10 giving numeric integer
|
||||
// limits and the current input number
|
||||
static auto max_exp = floor(log10(numeric_limits<uint16_t>::max())) - 1.0;
|
||||
auto exp = max_exp;
|
||||
if ( value >= 10 ) {
|
||||
exp -= floor(log10(value));
|
||||
}
|
||||
|
||||
// Expand input number with power of 10
|
||||
denominator = static_cast<int>(pow(10, exp));
|
||||
numerator = static_cast<int>(round(value * denominator));
|
||||
|
||||
// Simplify the fraction by calculating the greatest common divisor
|
||||
int gcd_ = gcd(numerator, denominator);
|
||||
|
||||
numerator = sign * numerator / gcd_;
|
||||
denominator = denominator / gcd_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
MSEEDDataRecord::MSEEDDataRecord() {}
|
||||
|
||||
|
||||
DataRecord *MSEEDDataRecord::clone() const {
|
||||
return new MSEEDDataRecord(*this);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
Header &header, Time &startTime, Time &endTime) {
|
||||
char head[48];
|
||||
|
||||
if ( size <= 0 ) {
|
||||
CAPS_WARNING("read metadata: invalid size of record: %d", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( size < MINRECLEN || size > MAXRECLEN ) {
|
||||
if ( (size < MINRECLEN) || (size > MAXRECLEN) ) {
|
||||
CAPS_WARNING("read metadata: invalid MSEED record size: %d", size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read first 32 byte
|
||||
// Read first 40 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",
|
||||
@@ -75,48 +190,52 @@ bool MSEEDDataRecord::readMetaData(std::streambuf &buf, int size,
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !MS_ISVALIDHEADER(((char*)&head)) ) {
|
||||
CAPS_WARNING("read metadata: invalid MSEED header");
|
||||
return false;
|
||||
if ( MS2_ISVALIDHEADER(((char*)&head)) ) {
|
||||
int headerswapflag = 0;
|
||||
|
||||
// Swap byte order?
|
||||
if ( !MS_ISVALIDYEARDAY(*pMS2FSDH_YEAR(head), *pMS2FSDH_DAY(head)) ) {
|
||||
headerswapflag = 1;
|
||||
|
||||
ms_gswap2(pMS2FSDH_YEAR(head));
|
||||
ms_gswap2(pMS2FSDH_DAY(head));
|
||||
ms_gswap2(pMS2FSDH_FSEC(head));
|
||||
|
||||
ms_gswap2(pMS2FSDH_NUMSAMPLES(head));
|
||||
ms_gswap2(pMS2FSDH_SAMPLERATEFACT(head));
|
||||
ms_gswap2(pMS2FSDH_SAMPLERATEMULT(head));
|
||||
ms_gswap4(pMS2FSDH_TIMECORRECT(head));
|
||||
ms_gswap2(pMS2FSDH_DATAOFFSET(head));
|
||||
ms_gswap2(pMS2FSDH_BLOCKETTEOFFSET(head));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
auto year = *pMS2FSDH_YEAR(head);
|
||||
auto yday = *pMS2FSDH_DAY(head);
|
||||
auto hours = *pMS2FSDH_HOUR(head);
|
||||
auto minutes = *pMS2FSDH_MIN(head);
|
||||
auto seconds = *pMS2FSDH_SEC(head);
|
||||
auto fsec = *pMS2FSDH_FSEC(head) * 100;
|
||||
|
||||
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;
|
||||
}
|
||||
startTime = Time::FromYearDay(year, yday);
|
||||
startTime += TimeSpan(hours * 3600 + minutes * 60 + seconds, fsec);
|
||||
|
||||
header.quality.ID = 0;
|
||||
header.quality.str[0] = head.dataquality;
|
||||
header.quality.str[0] = *pMS2FSDH_DATAQUALITY(head);
|
||||
|
||||
if ( head.time_correct != 0 && !(head.act_flags & 0x02) )
|
||||
hptime += (hptime_t)head.time_correct * (HPTMODULUS / 10000);
|
||||
if ( *pMS2FSDH_TIMECORRECT(head) != 0 && !(*pMS2FSDH_ACTFLAGS(head) & 0x02) ) {
|
||||
startTime += TimeSpan(0, *pMS2FSDH_TIMECORRECT(head) * 100);
|
||||
}
|
||||
|
||||
// Parse blockettes
|
||||
uint32_t blkt_offset = head.blockette_offset;
|
||||
uint32_t blkt_offset = *pMS2FSDH_BLOCKETTEOFFSET(head);
|
||||
uint32_t blkt_length;
|
||||
uint16_t blkt_type;
|
||||
uint16_t next_blkt;
|
||||
|
||||
if ( blkt_offset < sizeof(head) ) {
|
||||
LOG_SID(CAPS_DEBUG, "read metadata: blockette "
|
||||
LOG_SID(CAPS_DEBUG, "%s", "read metadata: blockette "
|
||||
"offset points into header");
|
||||
return false;
|
||||
}
|
||||
@@ -124,13 +243,13 @@ bool MSEEDDataRecord::readMetaData(std::streambuf &buf, int size,
|
||||
uint32_t coffs = 0;
|
||||
|
||||
while ( (blkt_offset != 0) && ((int)blkt_offset < size) &&
|
||||
(blkt_offset < MAXRECLEN) ) {
|
||||
(blkt_offset < static_cast<uint32_t>(size)) ) {
|
||||
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: "
|
||||
LOG_SID(CAPS_DEBUG, "%s", "read metadata: "
|
||||
"failed to read blockette header");
|
||||
break;
|
||||
}
|
||||
@@ -145,7 +264,7 @@ bool MSEEDDataRecord::readMetaData(std::streambuf &buf, int size,
|
||||
ms_gswap2(&next_blkt);
|
||||
}
|
||||
|
||||
blkt_length = ms_blktlen(blkt_type, bhead, headerswapflag);
|
||||
blkt_length = ms2_blktlen(blkt_type, bhead, headerswapflag);
|
||||
|
||||
if ( blkt_length == 0 ) {
|
||||
LOG_SID(CAPS_DEBUG, "read metadata: "
|
||||
@@ -195,7 +314,7 @@ bool MSEEDDataRecord::readMetaData(std::streambuf &buf, int size,
|
||||
}
|
||||
else if ( blkt_type == 1001 ) {
|
||||
// Add usec correction
|
||||
hptime += ((hptime_t)bhead[5]) * (HPTMODULUS / 1000000);
|
||||
startTime += TimeSpan(0, *reinterpret_cast<int8_t*>(bhead + 5));
|
||||
}
|
||||
|
||||
/* Check that the next blockette offset is beyond the current blockette */
|
||||
@@ -217,44 +336,102 @@ bool MSEEDDataRecord::readMetaData(std::streambuf &buf, int size,
|
||||
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;
|
||||
if ( *pMS2FSDH_SAMPLERATEFACT(head) > 0 ) {
|
||||
header.samplingFrequencyNumerator = *pMS2FSDH_SAMPLERATEFACT(head);
|
||||
header.samplingFrequencyDenominator = 1;
|
||||
}
|
||||
else {
|
||||
header.samplingFrequencyNumerator = 1;
|
||||
header.samplingFrequencyDenominator = -head.samprate_fact;
|
||||
header.samplingFrequencyDenominator = -*pMS2FSDH_SAMPLERATEFACT(head);
|
||||
}
|
||||
|
||||
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);
|
||||
if ( *pMS2FSDH_SAMPLERATEMULT(head) > 0 ) {
|
||||
header.samplingFrequencyNumerator *= *pMS2FSDH_SAMPLERATEMULT(head);
|
||||
}
|
||||
else {
|
||||
header.samplingFrequencyDenominator *= -*pMS2FSDH_SAMPLERATEMULT(head);
|
||||
}
|
||||
|
||||
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;
|
||||
if ( header.samplingFrequencyNumerator > 0.0 && *pMS2FSDH_NUMSAMPLES(head) > 0 ) {
|
||||
int64_t dt = static_cast<int64_t>(*pMS2FSDH_NUMSAMPLES(head)) * 1000000 * header.samplingFrequencyDenominator / header.samplingFrequencyNumerator;
|
||||
endTime += TimeSpan(0, dt);
|
||||
}
|
||||
|
||||
unpackHeader(&data[0], data.size());
|
||||
timeToTimestamp(header.samplingTime, startTime);
|
||||
}
|
||||
else if ( MS3_ISVALIDHEADER(((char*)&head)) ) {
|
||||
startTime = Time::FromYearDay(
|
||||
Endianess::Converter::ToLittleEndian(*pMS3FSDH_YEAR(head)),
|
||||
Endianess::Converter::ToLittleEndian(*pMS3FSDH_DAY(head))
|
||||
);
|
||||
|
||||
header = _header;
|
||||
startTime = _startTime;
|
||||
endTime = _endTime;
|
||||
#endif
|
||||
startTime += TimeSpan(
|
||||
Endianess::Converter::ToLittleEndian(*pMS3FSDH_HOUR(head)) * 3600 +
|
||||
Endianess::Converter::ToLittleEndian(*pMS3FSDH_MIN(head)) * 60 +
|
||||
Endianess::Converter::ToLittleEndian(*pMS3FSDH_SEC(head)),
|
||||
Endianess::Converter::ToLittleEndian(*pMS3FSDH_NSEC(head)) / 1000
|
||||
);
|
||||
|
||||
auto nsamp = Endianess::Converter::ToLittleEndian(*pMS3FSDH_NUMSAMPLES(head));
|
||||
auto fsamp = Endianess::Converter::ToLittleEndian(*pMS3FSDH_SAMPLERATE(head));
|
||||
if ( fsamp < 0 ) {
|
||||
fsamp = -1.0 / fsamp;
|
||||
}
|
||||
auto encoding = Endianess::Converter::ToLittleEndian(*pMS3FSDH_ENCODING(head));
|
||||
|
||||
header.dataType = DT_Unknown;
|
||||
switch ( encoding ) {
|
||||
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;
|
||||
}
|
||||
|
||||
header.quality.ID = 0;
|
||||
|
||||
if ( !double2frac(header.samplingFrequencyNumerator, header.samplingFrequencyDenominator, fsamp) ) {
|
||||
CAPS_WARNING("read metadata: invalid sampling rate: %f", fsamp);
|
||||
return false;
|
||||
}
|
||||
|
||||
endTime = startTime;
|
||||
if ( header.samplingFrequencyNumerator > 0.0 && *pMS3FSDH_NUMSAMPLES(head) > 0 ) {
|
||||
int64_t dt = static_cast<int64_t>(nsamp) * 1000000 * header.samplingFrequencyDenominator / header.samplingFrequencyNumerator;
|
||||
endTime += TimeSpan(0, dt);
|
||||
}
|
||||
|
||||
timeToTimestamp(header.samplingTime, startTime);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
CAPS_WARNING("read metadata: invalid MSEED header");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -328,93 +505,6 @@ DataRecord::ReadStatus MSEEDDataRecord::get(std::streambuf &buf, int size,
|
||||
}
|
||||
|
||||
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;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -422,68 +512,19 @@ 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;
|
||||
|
||||
void MSEEDDataRecord::unpackHeader() {
|
||||
arraybuf tmp(_data.data(), _data.size());
|
||||
if ( !readMetaData(tmp, _data.size(), _header, _startTime, _endTime) ) {
|
||||
CAPS_WARNING("invalid MSEED header");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
|
||||
#include <gempa/caps/packet.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
@@ -29,46 +28,47 @@ class MSEEDDataRecord : public DataRecord {
|
||||
public:
|
||||
MSEEDDataRecord();
|
||||
|
||||
virtual const char *formatName() const;
|
||||
DataRecord *clone() const override;
|
||||
const char *formatName() const override;
|
||||
|
||||
virtual bool readMetaData(std::streambuf &buf, int size,
|
||||
bool readMetaData(std::streambuf &buf, int size,
|
||||
Header &header,
|
||||
Time &startTime,
|
||||
Time &endTime);
|
||||
Time &endTime) override;
|
||||
|
||||
virtual const Header *header() const;
|
||||
virtual Time startTime() const;
|
||||
virtual Time endTime() const;
|
||||
const Header *header() const override;
|
||||
Time startTime() const override;
|
||||
Time endTime() const override;
|
||||
|
||||
virtual bool canTrim() const;
|
||||
virtual bool canMerge() const;
|
||||
bool canTrim() const override;
|
||||
bool canMerge() const override;
|
||||
|
||||
virtual bool trim(const Time &start,
|
||||
const Time &end) const;
|
||||
bool trim(const Time &start,
|
||||
const Time &end) const override;
|
||||
|
||||
virtual size_t dataSize(bool withHeader) const;
|
||||
size_t dataSize(bool withHeader) const override;
|
||||
|
||||
virtual ReadStatus get(std::streambuf &buf, int size,
|
||||
ReadStatus get(std::streambuf &buf, int size,
|
||||
const Time &start = Time(),
|
||||
const Time &end = Time(),
|
||||
int maxSize = -1);
|
||||
int maxSize = -1) override;
|
||||
|
||||
virtual bool put(std::streambuf &buf, bool withHeader) const;
|
||||
bool put(std::streambuf &buf, bool withHeader) const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the packet type
|
||||
* @return The packet type
|
||||
*/
|
||||
PacketType packetType() const { return MSEEDPacket; }
|
||||
PacketType packetType() const override { 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 setData(const void *data, size_t size);
|
||||
|
||||
void unpackHeader() { unpackHeader(_data.data(), _data.size()); }
|
||||
void unpackHeader();
|
||||
|
||||
|
||||
protected:
|
||||
@@ -78,10 +78,6 @@ class MSEEDDataRecord : public DataRecord {
|
||||
Time _endTime;
|
||||
|
||||
int _dataType;
|
||||
|
||||
|
||||
private:
|
||||
void unpackHeader(char *data, size_t size);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifndef GEMPA_CAPS_PACKET_H
|
||||
#define GEMPA_CAPS_PACKET_H
|
||||
|
||||
|
||||
#include <gempa/caps/api.h>
|
||||
|
||||
#include <gempa/caps/endianess.h>
|
||||
@@ -24,12 +25,11 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
@@ -320,6 +320,7 @@ class SC_GEMPA_CAPS_API DataRecord {
|
||||
public:
|
||||
virtual ~DataRecord();
|
||||
|
||||
virtual DataRecord *clone() const = 0;
|
||||
virtual const char *formatName() const = 0;
|
||||
|
||||
virtual bool readMetaData(std::streambuf &buf, int size,
|
||||
@@ -393,7 +394,8 @@ class SC_GEMPA_CAPS_API DataRecord {
|
||||
Buffer _data;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<DataRecord> DataRecordPtr;
|
||||
|
||||
using DataRecordPtr = boost::shared_ptr<DataRecord>;
|
||||
|
||||
|
||||
struct RawPacket {
|
||||
@@ -403,6 +405,7 @@ struct RawPacket {
|
||||
DataRecord *record;
|
||||
};
|
||||
|
||||
|
||||
struct MetaPacket {
|
||||
std::string SID[4];
|
||||
PacketDataHeader packetDataHeader;
|
||||
@@ -413,6 +416,7 @@ struct MetaPacket {
|
||||
Time timestamp;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@
|
||||
#ifndef GEMPA_CAPS_PLUGIN_H
|
||||
#define GEMPA_CAPS_PLUGIN_H
|
||||
|
||||
|
||||
/*
|
||||
// Enable/disable journal
|
||||
#define CAPS_FEATURES_JOURNAL 1
|
||||
@@ -34,8 +35,8 @@
|
||||
|
||||
#include <gempa/caps/packet.h>
|
||||
#include <gempa/caps/socket.h>
|
||||
#include <gempa/caps/url.h>
|
||||
#include <gempa/caps/version.h>
|
||||
|
||||
#include <gempa/caps/pluginpacket.h>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
@@ -49,10 +50,10 @@
|
||||
#include <list>
|
||||
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
class SC_GEMPA_CAPS_API Plugin {
|
||||
public:
|
||||
enum Status {
|
||||
@@ -70,8 +71,25 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
size_t maxBytesBuffered;
|
||||
};
|
||||
|
||||
struct HostInfo {
|
||||
std::string agent;
|
||||
std::string agentVersion;
|
||||
std::string os;
|
||||
int64_t totalMem{-1};
|
||||
int64_t totalDisc{-1};
|
||||
};
|
||||
|
||||
struct RuntimeInfo {
|
||||
int64_t availableMem{-1};
|
||||
int64_t procUsedMem{-1};
|
||||
int64_t availableDisc{-1};
|
||||
int cpuUsage{-1};
|
||||
double systemLoad{-1};
|
||||
};
|
||||
|
||||
typedef std::vector<char> Buffer;
|
||||
typedef boost::shared_ptr<Buffer> BufferPtr;
|
||||
typedef std::deque<PacketPtr> PacketBuffer;
|
||||
|
||||
#if !defined(CAPS_FEATURES_BACKFILLING) || CAPS_FEATURES_BACKFILLING
|
||||
typedef std::list<PacketPtr> BackfillingBuffer;
|
||||
@@ -88,13 +106,15 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
typedef std::map<std::string, StreamState> StreamStates;
|
||||
|
||||
typedef boost::function<void (const std::string &, const CAPS::Time &,
|
||||
const CAPS::Time &)> PacketAckFunc;
|
||||
const CAPS::Time &, void *context)> PacketAckFunc;
|
||||
typedef boost::function<void ()> ConnectedCallback;
|
||||
typedef boost::function<void ()> DisconnectedCallback;
|
||||
|
||||
|
||||
public:
|
||||
Plugin(const std::string &name, const std::string &options = "",
|
||||
const std::string &description = "");
|
||||
~Plugin();
|
||||
virtual ~Plugin();
|
||||
|
||||
void close();
|
||||
void quit();
|
||||
@@ -139,11 +159,19 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
*/
|
||||
void setEncoderFactory(EncoderFactory *factory);
|
||||
|
||||
void setHost(const std::string &host) { _host = host; }
|
||||
const std::string &host() const { return _host; }
|
||||
/**
|
||||
* @brief Parses connection parameters from address string. Format
|
||||
* is [[caps|capss]://][user:pass@]host[:port]
|
||||
* @param addr The address of the caps server as string
|
||||
* @param defaultPort The default port used when the port is omitted
|
||||
*/
|
||||
bool setAddress(const std::string &addr, uint16_t defaultPort = 18003);
|
||||
|
||||
void setPort(unsigned short port) { _port = port; }
|
||||
unsigned short port() const { return _port; }
|
||||
void setHost(const std::string &host) { _url.host = host; }
|
||||
const std::string &host() const { return _url.host; }
|
||||
|
||||
void setPort(unsigned short port) { _url.port = port; }
|
||||
unsigned short port() const { return _url.port; }
|
||||
|
||||
void setBufferSize(size_t bufferSize) { _bufferSize = bufferSize; }
|
||||
size_t bufferSize() const { return _bufferSize; }
|
||||
@@ -159,8 +187,8 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
* @param password The password
|
||||
*/
|
||||
void setCredentials(const std::string &user, const std::string &password) {
|
||||
_user = user;
|
||||
_password = password;
|
||||
_url.user = user;
|
||||
_url.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,15 +204,31 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
|
||||
void setPacketAckFunc(const PacketAckFunc &func) { _packetAckFunc = func; }
|
||||
|
||||
void setSendTimeout(int timeout) {
|
||||
_sendTimeout = timeout;
|
||||
/**
|
||||
* @brief Sets the connection timout used when the plugin
|
||||
* tries to establish a connection to CAPS
|
||||
* @param sec The seconds
|
||||
*/
|
||||
void setConnectionTimeout(int sec) {
|
||||
_connectionTimeout = sec;
|
||||
}
|
||||
|
||||
void setTimeouts(int ack, int lastAck) {
|
||||
_ackTimeout = ack;
|
||||
_lastAckTimeout = lastAck;
|
||||
/**
|
||||
* @brief Sets the maximum number of seconds to wait until
|
||||
* the file descriptor is ready for writing.
|
||||
* @param sec The seconds
|
||||
*/
|
||||
void setSendTimeout(int sec) {
|
||||
_sendTimeout = sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets timeout values
|
||||
* @param ack The acknowledgement message value
|
||||
* @param lastAck The last acknowledgement message value
|
||||
* @param send See setSendTimeout
|
||||
* @
|
||||
*/
|
||||
void setTimeouts(int ack, int lastAck, int send) {
|
||||
_ackTimeout = ack;
|
||||
_lastAckTimeout = lastAck;
|
||||
@@ -199,11 +243,18 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
const StreamStates &streamStates() const { return _states; }
|
||||
bool writeJournal();
|
||||
bool writeJournal(std::ostream &ostream);
|
||||
|
||||
/**
|
||||
* @brief Gets end time of the last acknowledged packet
|
||||
* @param id The stream ID, e.g., GE.APE..BHZ
|
||||
* @return The last end time or an invalid time
|
||||
*/
|
||||
Gempa::CAPS::Time lastEndTime(const std::string &id);
|
||||
#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);
|
||||
int timingQuality = -1, void *context = nullptr);
|
||||
|
||||
Status push(const std::string &net, const std::string &sta,
|
||||
const std::string &loc, const std::string &cha,
|
||||
@@ -211,7 +262,53 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
uint16_t numerator, uint16_t denominator,
|
||||
const std::string &uom,
|
||||
void *data, size_t count,
|
||||
DataType dt, int timingQuality = -1);
|
||||
DataType dt, int timingQuality = -1,
|
||||
void *context = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sends CAPS data record to CAPS
|
||||
* @param net Network code
|
||||
* @param sta Station code
|
||||
* @param loc Location code
|
||||
* @param cha Channel code
|
||||
* @param rec CAPS data record
|
||||
* @param uom Unit of measurement
|
||||
* @param timingQuality Data timing quality. Ususally between 0 and 100 or -1
|
||||
* if unset
|
||||
* @param context Pointer to user-defined context data
|
||||
* @return Status Packet status
|
||||
*/
|
||||
Status pushRecord(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, void *context = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sends C array data as RAW record to CAPS
|
||||
* @param net Network code
|
||||
* @param sta Station code
|
||||
* @param loc Location code
|
||||
* @param cha Channel code
|
||||
* @param stime Packet start time
|
||||
* @param numerator Sampling frequency numerator
|
||||
* @param denominator Sampling frequency denominator
|
||||
* @param uom Unit of measurement
|
||||
* @param data Pointer to data array
|
||||
* @param count Number of samples
|
||||
* @param dt Data type, e.g., DT_DOUBLE
|
||||
* @param timingQuality Data timing quality. Ususally between 0 and 100 or -1
|
||||
* if unset
|
||||
* @param context Pointer to user-defined context data
|
||||
* @return Status Packet status
|
||||
*/
|
||||
Status pushRaw(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,
|
||||
void *context = nullptr);
|
||||
|
||||
/*
|
||||
* Sends given data as any packet. Before sending the data will be
|
||||
@@ -223,21 +320,151 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
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);
|
||||
char *data, size_t count, void *context = nullptr);
|
||||
|
||||
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);
|
||||
const std::string &data, void *context = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sends C array data as any record to CAPS
|
||||
* @param net Network code
|
||||
* @param sta Station code
|
||||
* @param loc Location code
|
||||
* @param cha Channel code
|
||||
* @param stime Packet start time
|
||||
* @param etime Packet end time
|
||||
* @param numerator Sampling frequency numerator. Use 1 / 0
|
||||
* for packets without sampling frequency.
|
||||
* @param denominator Sampling frequency denominator
|
||||
* @param format Data format of the provided data
|
||||
* @param uom Unit of measurement, e.g., px
|
||||
* @param data Pointer to data array
|
||||
* @param count Number of data elements
|
||||
* @param context Pointer to user-defined context data
|
||||
* @return Status Packet status
|
||||
*/
|
||||
Status pushAny(const std::string &net, const std::string &sta,
|
||||
const std::string &loc, const std::string &cha,
|
||||
const Time &stime, const Time &etime,
|
||||
uint16_t numerator, uint16_t denominator,
|
||||
const std::string &format, const std::string &uom,
|
||||
char *data, size_t count, void *context = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Sends STL string as any record to CAPS
|
||||
* @param net Network code
|
||||
* @param sta Station code
|
||||
* @param loc Location code
|
||||
* @param cha Channel code
|
||||
* @param stime Packet start time
|
||||
* @param etime Packet end time
|
||||
* @param numerator Sampling frequency numerator. Use 1 / 0
|
||||
* for packets without sampling frequency.
|
||||
* @param denominator Sampling frequency denominator
|
||||
* @param format Data format of the provided data
|
||||
* @param uom Unit of measurement, e.g., px
|
||||
* @param data Data as string
|
||||
* @param context Pointer to user-defined context data
|
||||
* @return Status Packet status
|
||||
*/
|
||||
Status pushAny(const std::string &net, const std::string &sta,
|
||||
const std::string &loc, const std::string &cha,
|
||||
const Time &stime, const Time &etime,
|
||||
uint16_t numerator, uint16_t denominator,
|
||||
const std::string &format, const std::string &uom,
|
||||
const std::string &data, void *context = nullptr);
|
||||
#endif
|
||||
|
||||
void flushEncoders();
|
||||
|
||||
void dumpPackets(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Returns the internal packet buffer that
|
||||
* keeps packets until they have been acknowledged
|
||||
* by CAPS
|
||||
* @return The interal packet buffer
|
||||
*/
|
||||
const PacketBuffer &packetBuffer() const {
|
||||
return _packetBuffer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set host information like agent or total mem
|
||||
* @param info The host info struct
|
||||
*/
|
||||
void setHostInfo(const HostInfo &info);
|
||||
|
||||
/**
|
||||
* @brief Set runtime information like CPU load or process memory usage.
|
||||
* This methods blocks until sent.
|
||||
* @param info The runtime info struct
|
||||
*/
|
||||
void setRuntimeInfo(const RuntimeInfo &info);
|
||||
|
||||
/**
|
||||
* @brief Sets the connection ID. If not set, the server generates an ID
|
||||
* during the first connection attempt.
|
||||
* @param id The connection ID string
|
||||
*/
|
||||
void setConnectionID(const std::string &id);
|
||||
|
||||
/**
|
||||
* @brief Set the connection ID file to read the connection ID from
|
||||
* @param filename The filename
|
||||
* @return True if the connection could be read from the given file
|
||||
*/
|
||||
bool setConnectionIDFile(const std::string &filename);
|
||||
|
||||
/**
|
||||
* @brief Returns the connection ID
|
||||
* @return Returns the connection ID
|
||||
*/
|
||||
const std::string &connectionID() const;
|
||||
|
||||
/**
|
||||
* @brief Set function that gets called if the connection to the server
|
||||
* has been established.
|
||||
*/
|
||||
void setConnectedCallback(ConnectedCallback f);
|
||||
|
||||
/**
|
||||
* @brief Set function that gets called if the connection to the server
|
||||
* was disconnected.
|
||||
*/
|
||||
void setDisconnectedCallback(DisconnectedCallback f);
|
||||
|
||||
const char *version() {
|
||||
return LIB_CAPS_VERSION_NAME;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Sends HELLO request and parses API version
|
||||
* from server response. If the server does not support
|
||||
* the API feature the method sets the version to 0.
|
||||
* @param version The CAPS API version, e.g., 5
|
||||
* @return True on success
|
||||
*/
|
||||
bool getAPIVersion(int &version);
|
||||
|
||||
/**
|
||||
* @brief Get connection ID from server. If the plugin sends no
|
||||
* connection ID the server generates one.
|
||||
* @return True on success
|
||||
*/
|
||||
bool getConnectionID();
|
||||
|
||||
/**
|
||||
* brief Send runtime information
|
||||
*/
|
||||
void sendRuntimeInfo();
|
||||
|
||||
private:
|
||||
typedef std::deque<PacketPtr> PacketBuffer;
|
||||
typedef boost::shared_ptr<Encoder> EncoderPtr;
|
||||
|
||||
struct EncoderItem {
|
||||
@@ -250,6 +477,7 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
private:
|
||||
bool connect();
|
||||
void disconnect();
|
||||
void dumpPacket(Packet *packet);
|
||||
bool isConnected() const;
|
||||
Encoder* getEncoder(PacketPtr packet);
|
||||
bool readResponse(unsigned int sec = 0);
|
||||
@@ -265,7 +493,6 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
void tryFlushBackfillingBuffer(StreamState &state);
|
||||
void trimBackfillingBuffer(StreamState &state);
|
||||
bool flush();
|
||||
void flushEncoders();
|
||||
bool send(char *data, int len, int timeout = 60);
|
||||
void wait();
|
||||
|
||||
@@ -279,13 +506,13 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
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;
|
||||
int _readTimeout;
|
||||
int _connectionTimeout;
|
||||
#if !defined(CAPS_FEATURES_JOURNAL) || CAPS_FEATURES_JOURNAL
|
||||
std::string _journalFile;
|
||||
bool _journalDirty;
|
||||
@@ -306,16 +533,25 @@ class SC_GEMPA_CAPS_API Plugin {
|
||||
|
||||
PacketAckFunc _packetAckFunc;
|
||||
|
||||
std::string _user;
|
||||
std::string _password;
|
||||
Url _url;
|
||||
#if !defined(CAPS_FEATURES_SSL) || CAPS_FEATURES_SSL
|
||||
bool _useSSL;
|
||||
#endif
|
||||
Stats _stats;
|
||||
TimeSpan _maxFutureEndTime;
|
||||
|
||||
bool _dumpPackets;
|
||||
HostInfo _hostInfo;
|
||||
RuntimeInfo _runtimeInfo;
|
||||
std::string _connectionID;
|
||||
std::string _connectionIDFile;
|
||||
ConnectedCallback _connectedCallback;
|
||||
DisconnectedCallback _disconnectedCallback;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Plugin> PluginPtr;
|
||||
|
||||
using PluginPtr = boost::shared_ptr<Plugin>;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,17 @@
|
||||
#include <gempa/caps/log.h>
|
||||
#include <gempa/caps/utils.h>
|
||||
|
||||
#include <seiscomp3/core/system.h>
|
||||
#include <seiscomp3/logging/log.h>
|
||||
#include <seiscomp/core/system.h>
|
||||
#include <seiscomp/logging/log.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#ifdef SC_GEMPA_SEATTLE
|
||||
#include <seiscomp3/system/environment.h>
|
||||
#else
|
||||
#include <seiscomp3/config/environment.h>
|
||||
#endif
|
||||
#include <seiscomp/system/environment.h>
|
||||
|
||||
using namespace std;
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace sc = Seiscomp::Core;
|
||||
|
||||
namespace {
|
||||
@@ -73,49 +71,93 @@ void LogDebug(const char *fmt, ...) {
|
||||
}
|
||||
|
||||
const size_t MIN_BUFFER_SIZE = 1024*16;
|
||||
const uint16_t DEFAULT_PORT = 18003;
|
||||
|
||||
bool readKeyValueFile(std::map<std::string, std::string> &data,
|
||||
const std::string &filename, const char *sep) {
|
||||
std::ifstream ifs(filename.c_str());
|
||||
if ( !ifs.is_open() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while ( getline(ifs, line) ) {
|
||||
const char* str = line.c_str();
|
||||
int len = strlen(str);
|
||||
const char *tok = nullptr;
|
||||
int tok_len = 0;
|
||||
int tok_count = 0;
|
||||
|
||||
std::string key;
|
||||
|
||||
for ( ; (tok = Gempa::CAPS::tokenize(str, sep, len, tok_len)) != nullptr;
|
||||
++tok_count ) {
|
||||
Gempa::CAPS::trim(tok, tok_len);
|
||||
if ( tok_count == 0 ) {
|
||||
if ( len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
key.assign(tok, tok_len);
|
||||
}
|
||||
else if ( tok_count == 1 ) {
|
||||
data.insert({key, std::string(tok, tok_len)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t getAvailableMemory() {
|
||||
std::map<std::string, std::string> data;
|
||||
if ( !readKeyValueFile(data, "/proc/meminfo", ":") ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto it = data.find("MemAvailable");
|
||||
if ( it == data.end() ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
sc::split(tokens, it->second.c_str(), "kB");
|
||||
if ( tokens.empty() ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sc::trim(tokens[0]);
|
||||
int64_t availableMemory = 0;
|
||||
sc::fromString(availableMemory, tokens[0]);
|
||||
|
||||
return availableMemory;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
namespace Gempa::CAPS {
|
||||
|
||||
PluginApplication::PluginApplication(int argc, char **argv, const string &desc)
|
||||
PluginApplication::PluginApplication(int argc, char **argv, const std::string &name)
|
||||
: 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;
|
||||
, _plugin(Plugin(name)) {
|
||||
|
||||
_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;
|
||||
fs::path path("@ROOTDIR@/var/run/" + SCCoreApp->name());
|
||||
_journalFile = (path / "journal").string();
|
||||
|
||||
// By default we disable the acquisition autostart because not all plugins
|
||||
// require this feature. It must be enabled explicitly if required.
|
||||
setAutoAcquisitionStart(false);
|
||||
setRecordStreamEnabled(true);
|
||||
}
|
||||
|
||||
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", "output,O",
|
||||
"Data output address. Format:\n"
|
||||
"[[caps|capss]://][user:pass@]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);
|
||||
@@ -128,10 +170,13 @@ void PluginApplication::createCommandLineDescription() {
|
||||
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 "
|
||||
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.",
|
||||
"value the packet will be discarded. By default this value is set to 120 seconds. "
|
||||
"A negative value disables the check.",
|
||||
&_maxFutureEndTime);
|
||||
commandline().addOption("Output", "dump-packets", "Dump packets to stdout");
|
||||
commandline().addGroup("Journal");
|
||||
commandline().addOption("Journal", "journal,j",
|
||||
"File to store stream states. Use an empty string to disable this feature.", &_journalFile);
|
||||
@@ -148,6 +193,14 @@ void PluginApplication::createCommandLineDescription() {
|
||||
commandline().addOption("Status", "status-flush", "Flush status every n "
|
||||
"seconds to disk",
|
||||
&_statusFlushInterval);
|
||||
|
||||
commandline().addGroup("Host");
|
||||
commandline().addOption("Host", "host-storage",
|
||||
"Determine disc capacity and available space from this path",
|
||||
&_host.storage);
|
||||
commandline().addOption("Host", "host-os",
|
||||
"Set host operating system information",
|
||||
&_host.os);
|
||||
}
|
||||
|
||||
void PluginApplication::done() {
|
||||
@@ -163,6 +216,8 @@ void PluginApplication::done() {
|
||||
_stats.endTime.valid()?_stats.endTime.iso().c_str():"",
|
||||
_stats.files);
|
||||
|
||||
_plugin.close();
|
||||
|
||||
Seiscomp::Client::StreamApplication::done();
|
||||
}
|
||||
|
||||
@@ -173,17 +228,29 @@ void PluginApplication::exit(int returnCode) {
|
||||
}
|
||||
|
||||
void PluginApplication::handleTimeout() {
|
||||
sc::Time time = sc::Time::GMT().toLocalTime();
|
||||
auto time = Time::GMT();
|
||||
auto seconds = time.seconds();
|
||||
|
||||
if ( _logStatus && (seconds % _statusFlushInterval == 0) ) {
|
||||
Plugin::Stats stats = _plugin.stats();
|
||||
_statusFile.stream() << time.toString("%Y/%m/%d %T") << " " << stats.maxBytesBuffered << endl;
|
||||
|
||||
|
||||
_statusFile.stream() << time.toLocalTime().toString("%Y/%m/%d %T") << " "
|
||||
<< stats.maxBytesBuffered << std::endl;
|
||||
_plugin.resetMaxBytesBuffered();
|
||||
}
|
||||
|
||||
if ( seconds % 3 == 0 ) {
|
||||
updateRuntimeInfo();
|
||||
}
|
||||
|
||||
if ( seconds % 10 == 0 ) {
|
||||
sendRuntimeInfo();
|
||||
}
|
||||
}
|
||||
|
||||
bool PluginApplication::init() {
|
||||
if ( !Seiscomp::Client::StreamApplication::init() ) return false;
|
||||
if ( !Seiscomp::Client::StreamApplication::init() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup log handlers
|
||||
Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_ERROR, LogError);
|
||||
@@ -192,12 +259,31 @@ bool PluginApplication::init() {
|
||||
Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_INFO, LogInfo);
|
||||
Gempa::CAPS::SetLogHandler(Gempa::CAPS::LL_DEBUG, LogDebug);
|
||||
|
||||
_plugin.setHost(_host);
|
||||
_plugin.setPort(_port);
|
||||
Plugin::HostInfo hostInfo;
|
||||
if ( !getHostInfo(hostInfo) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_plugin.setBufferSize(_bufferSize);
|
||||
_plugin.setFlushInterval(_flushInterval);
|
||||
_plugin.setConnectionTimeout(_connectionTimeout);
|
||||
_plugin.setTimeouts(_ackTimeout, _lastAckTimeout, _sendTimeout);
|
||||
_plugin.setMaxFutureEndTime(_maxFutureEndTime);
|
||||
_plugin.dumpPackets(_dumpPackets);
|
||||
_plugin.setHostInfo(hostInfo);
|
||||
|
||||
LogInfo("CAPS connection settings\n"
|
||||
" Output CAPS server : %s\n"
|
||||
" Buffer size : %zu bytes\n"
|
||||
" Backfilling buffer size : %zu s\n"
|
||||
" Max future end time : %d s\n"
|
||||
" Connection timeout : %d s\n"
|
||||
" Timeouts Ack/LastAck/Send : %d s/%d s/%d s\n"
|
||||
" Agent : %s\n"
|
||||
" Agent version : %s",
|
||||
_strAddr.c_str(), _bufferSize, _backfillingBufferSize, _maxFutureEndTime,
|
||||
_connectionTimeout, _ackTimeout, _lastAckTimeout, _sendTimeout,
|
||||
hostInfo.agent.data(), hostInfo.agentVersion.data());
|
||||
|
||||
if ( _mseedEnabled ) {
|
||||
MSEEDEncoderFactory *factory = nullptr;
|
||||
@@ -211,7 +297,7 @@ bool PluginApplication::init() {
|
||||
factory = new Steim1EncoderFactory();
|
||||
_plugin.setEncoderFactory(factory);
|
||||
}
|
||||
if ( _mseedEncoding == Steim2 ) {
|
||||
else if ( _mseedEncoding == Steim2 ) {
|
||||
SEISCOMP_INFO("Output stream encoding set to MiniSEED/Steim2");
|
||||
factory = new Steim2EncoderFactory();
|
||||
_plugin.setEncoderFactory(factory);
|
||||
@@ -232,7 +318,13 @@ bool PluginApplication::init() {
|
||||
|
||||
if ( _backfillingBufferSize > 0 ) {
|
||||
_plugin.setBackfillingBufferSize(_backfillingBufferSize);
|
||||
LogInfo("Backfilling buffer size set to %d", _backfillingBufferSize);
|
||||
}
|
||||
|
||||
std::string connectionIDFile = "@ROOTDIR@/var/run/" + name() + "/id";
|
||||
connectionIDFile = Seiscomp::Environment::Instance()->absolutePath(connectionIDFile);
|
||||
LogInfo("Reading connection ID from %s", connectionIDFile.c_str());
|
||||
if ( !_plugin.setConnectionIDFile(connectionIDFile) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !_journalFile.empty() ) {
|
||||
@@ -245,35 +337,46 @@ bool PluginApplication::init() {
|
||||
}
|
||||
|
||||
if ( _logStatus ) {
|
||||
string filename = Seiscomp::Environment::Instance()->logDir() + "/" + SCCoreApp->name() + "-stats.log";
|
||||
std::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);
|
||||
}
|
||||
|
||||
// This causes a connect
|
||||
updateRuntimeInfo();
|
||||
_plugin.setRuntimeInfo(_runtimeInfo);
|
||||
enableTimer(1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginApplication::initConfiguration() {
|
||||
if ( !Seiscomp::Client::StreamApplication::initConfiguration() ) return false;
|
||||
if ( !Seiscomp::Client::StreamApplication::initConfiguration() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try { _host = configGetString("output.host"); }
|
||||
catch ( ... ) { }
|
||||
try {
|
||||
_plugin.setHost(configGetString("output.host"));
|
||||
}
|
||||
catch ( ... ) {
|
||||
}
|
||||
|
||||
try { _port = configGetInt("output.port"); }
|
||||
try {
|
||||
_plugin.setPort(configGetInt("output.port"));
|
||||
}
|
||||
catch ( ... ) { }
|
||||
|
||||
try { _sendTimeout = configGetInt("output.timeout"); }
|
||||
catch ( ... ) { }
|
||||
|
||||
try { _connectionTimeout = configGetInt("output.connectionTimeout"); }
|
||||
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());
|
||||
std::string addr = configGetString("output.address");
|
||||
if ( !_plugin.setAddress(addr) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -296,8 +399,10 @@ bool PluginApplication::initConfiguration() {
|
||||
catch ( ... ) {}
|
||||
|
||||
try {
|
||||
string str = configGetString("output.mseed.encoding");
|
||||
if ( !fromString(_mseedEncoding, str)) return false;
|
||||
std::string str = configGetString("output.mseed.encoding");
|
||||
if ( !fromString(_mseedEncoding, str)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch ( ... ) {}
|
||||
|
||||
@@ -307,6 +412,9 @@ bool PluginApplication::initConfiguration() {
|
||||
try { _backfillingBufferSize = configGetInt("output.backfillingBufferSize"); }
|
||||
catch ( ... ) { }
|
||||
|
||||
try { _maxFutureEndTime = configGetInt("output.maxFutureEndTime"); }
|
||||
catch ( ... ) { }
|
||||
|
||||
try { _journalFile = configGetString("journal.file"); }
|
||||
catch ( ... ) {}
|
||||
|
||||
@@ -319,20 +427,27 @@ bool PluginApplication::initConfiguration() {
|
||||
try { _lastAckTimeout = configGetInt("journal.waitForLastAck"); }
|
||||
catch ( ... ) { }
|
||||
|
||||
_host.agent = name();
|
||||
try { _host.storage = configGetString("host.storage"); }
|
||||
catch ( ... ) { }
|
||||
|
||||
try { _host.os = configGetString("host.os"); }
|
||||
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 ( !Seiscomp::Client::StreamApplication::validateParameters() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( commandline().hasOption("mseed") ) {
|
||||
_mseedEnabled = true;
|
||||
@@ -342,8 +457,14 @@ bool PluginApplication::validateParameters() {
|
||||
_logStatus = true;
|
||||
}
|
||||
|
||||
if ( commandline().hasOption("dump-packets") ) {
|
||||
_dumpPackets = true;
|
||||
}
|
||||
|
||||
if ( commandline().hasOption("encoding") ) {
|
||||
if ( !fromString(_mseedEncoding, _strMseedEncoding)) return false;
|
||||
if ( !fromString(_mseedEncoding, _strMseedEncoding)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( _bufferSize < MIN_BUFFER_SIZE ) {
|
||||
@@ -352,25 +473,28 @@ bool PluginApplication::validateParameters() {
|
||||
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());
|
||||
if ( commandline().hasOption("output") ) {
|
||||
if ( !_plugin.setAddress(_strAddr, 18003) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_host.storage = Seiscomp::Environment::Instance()->absolutePath(_host.storage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginApplication::fromString(MseedEncoding &enc, string str) {
|
||||
bool PluginApplication::fromString(MseedEncoding &enc, std::string str) {
|
||||
boost::to_lower(str);
|
||||
if( str == "uncompressed" )
|
||||
if( str == "uncompressed" ) {
|
||||
enc = Uncompressed;
|
||||
else if ( str == "steim1" )
|
||||
}
|
||||
else if ( str == "steim1" ) {
|
||||
enc = Steim1;
|
||||
else if ( str == "steim2" )
|
||||
}
|
||||
else if ( str == "steim2" ) {
|
||||
enc = Steim2;
|
||||
}
|
||||
else {
|
||||
SEISCOMP_ERROR("Unsupported encoding %s", str.c_str());
|
||||
return false;
|
||||
@@ -379,5 +503,60 @@ bool PluginApplication::fromString(MseedEncoding &enc, string str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginApplication::getHostInfo(Plugin::HostInfo &hostInfo) {
|
||||
hostInfo.agent = _host.agent;
|
||||
hostInfo.agentVersion = version() ? version() : "";
|
||||
hostInfo.totalMem = _hostInfo.totalMemory();
|
||||
|
||||
try {
|
||||
auto spaceInfo = fs::space(_host.storage);
|
||||
hostInfo.totalDisc = spaceInfo.capacity / 1024;
|
||||
}
|
||||
catch ( const fs::filesystem_error& e ) {
|
||||
SEISCOMP_ERROR("Failed to determine filesystem information: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
hostInfo.os = _host.os;
|
||||
if ( hostInfo.os.empty() ) {
|
||||
std::map<std::string, std::string> osRelease;
|
||||
if ( !readKeyValueFile(osRelease, "/etc/os-release", "=") ) {
|
||||
SEISCOMP_WARNING("Unable to read file /etc/os-release");
|
||||
}
|
||||
|
||||
auto it = osRelease.find("PRETTY_NAME");
|
||||
if ( it != osRelease.end() ) {
|
||||
auto unquote = [](const std::string& str) {
|
||||
if ( str.length() >= 2 && str.front() == '"' && str.back() == '"' ) {
|
||||
return str.substr(1, str.length() - 2);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
hostInfo.os = unquote(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PluginApplication::updateRuntimeInfo() {
|
||||
_runtimeInfo.cpuUsage = std::max(0, static_cast<int>(_hostInfo.getCurrentCpuUsage() * 1000));
|
||||
_runtimeInfo.procUsedMem = _hostInfo.getCurrentMemoryUsage();
|
||||
_runtimeInfo.availableMem = getAvailableMemory();
|
||||
getloadavg(&_runtimeInfo.systemLoad, 1);
|
||||
|
||||
try {
|
||||
auto spaceInfo = fs::space(_host.storage);
|
||||
_runtimeInfo.availableDisc = spaceInfo.available / 1024;
|
||||
}
|
||||
catch ( const fs::filesystem_error& e ) {
|
||||
SEISCOMP_WARNING("Failed to determine filesystem information: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void PluginApplication::sendRuntimeInfo() {
|
||||
_plugin.setRuntimeInfo(_runtimeInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,98 +16,153 @@
|
||||
#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>
|
||||
#include <seiscomp/core/version.h>
|
||||
#include <seiscomp/client/streamapplication.h>
|
||||
#if SC_API_VERSION < SC_API_VERSION_CHECK(17, 0, 0)
|
||||
#include <seiscomp/logging/filerotator.h>
|
||||
#else
|
||||
#include <seiscomp/logging/output/filerotator.h>
|
||||
#endif
|
||||
#include <seiscomp/system/hostinfo.h>
|
||||
#include <seiscomp/utils/timer.h>
|
||||
|
||||
|
||||
namespace Gempa::CAPS {
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
class SC_GEMPA_CAPS_API PluginApplication : public Seiscomp::Client::StreamApplication {
|
||||
public:
|
||||
PluginApplication(int argc, char **argv,
|
||||
const std::string &desc = "");
|
||||
const std::string &name = "");
|
||||
|
||||
protected:
|
||||
struct Statistics {
|
||||
Statistics() = default;
|
||||
|
||||
uint32_t records{0};
|
||||
uint32_t samples{0};
|
||||
Time startTime;
|
||||
Time endTime;
|
||||
uint32_t gaps{0};
|
||||
uint32_t files{0};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The MseedEncoding enum defines supported MSEED encodings.
|
||||
*/
|
||||
enum MseedEncoding {Uncompressed, Steim1, Steim2};
|
||||
|
||||
/**
|
||||
* @brief Adds common plugin commandline options.
|
||||
*/
|
||||
virtual void createCommandLineDescription();
|
||||
void createCommandLineDescription() override;
|
||||
|
||||
virtual void done();
|
||||
/**
|
||||
* @brief Cleanup method called before exec() returns.
|
||||
*/
|
||||
void done() override;
|
||||
|
||||
virtual void exit(int returnCode);
|
||||
/**
|
||||
* @brief This method is called before the applications exits.
|
||||
* @param returnCode The exit code
|
||||
*/
|
||||
void exit(int returnCode) override;
|
||||
|
||||
virtual void handleRecord(Seiscomp::Record *record) {}
|
||||
virtual void handleTimeout();
|
||||
/**
|
||||
* @brief Handles records. This is dummy implemenation as the base
|
||||
* class requires to implement the method.
|
||||
* @param record Pointer to record
|
||||
*/
|
||||
void handleRecord(Seiscomp::Record *record) override {}
|
||||
|
||||
/**
|
||||
* @brief Handles timer events. For instance writes the plugin states
|
||||
* information to file.
|
||||
*/
|
||||
void handleTimeout() override;
|
||||
|
||||
/**
|
||||
* @brief Initialization method.
|
||||
*/
|
||||
virtual bool init();
|
||||
bool init() override;
|
||||
|
||||
/**
|
||||
* @brief Reads common plugin configuration options.
|
||||
*/
|
||||
virtual bool initConfiguration();
|
||||
bool initConfiguration() override;
|
||||
|
||||
/**
|
||||
* @brief Validates command line parameters.
|
||||
*/
|
||||
virtual bool validateParameters();
|
||||
bool validateParameters() override;
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get MSEED encoding value from string
|
||||
* @param enc The encoding
|
||||
* @param str The encoding as string
|
||||
* @return True on success
|
||||
*/
|
||||
static bool fromString(MseedEncoding &enc, std::string str);
|
||||
|
||||
/**
|
||||
* @brief Get host information like total mem or OS
|
||||
* @param hostInfo Host info struct
|
||||
* @return True on success
|
||||
*/
|
||||
bool getHostInfo(Plugin::HostInfo &hostInfo);
|
||||
|
||||
/**
|
||||
* @brief Get runtime information
|
||||
*/
|
||||
void updateRuntimeInfo();
|
||||
|
||||
virtual void sendRuntimeInfo();
|
||||
|
||||
protected:
|
||||
struct Host {
|
||||
std::string agent;
|
||||
std::string storage{"@LOGDIR@"};
|
||||
std::string os;
|
||||
};
|
||||
|
||||
Plugin _plugin;
|
||||
std::string _host;
|
||||
ushort _port;
|
||||
std::string _strAddr;
|
||||
size_t _bufferSize;
|
||||
size_t _backfillingBufferSize;
|
||||
std::string _strAddr{"localhost:18003"};
|
||||
size_t _bufferSize{1 << 20};
|
||||
size_t _backfillingBufferSize{180};
|
||||
bool _mseed;
|
||||
std::string _journalFile;
|
||||
int _flushInterval;
|
||||
int _ackTimeout;
|
||||
int _lastAckTimeout;
|
||||
int _sendTimeout;
|
||||
int _maxFutureEndTime;
|
||||
int _flushInterval{10};
|
||||
int _ackTimeout{60};
|
||||
int _lastAckTimeout{5};
|
||||
int _sendTimeout{60};
|
||||
int _connectionTimeout{30};
|
||||
int _maxFutureEndTime{120};
|
||||
Statistics _stats;
|
||||
bool _mseedEnabled;
|
||||
MseedEncoding _mseedEncoding;
|
||||
uint _mseedRecordLength;
|
||||
std::string _strMseedEncoding;
|
||||
bool _mseedEnabled{false};
|
||||
MseedEncoding _mseedEncoding{Steim2};
|
||||
uint _mseedRecordLength{9};
|
||||
std::string _strMseedEncoding{"Steim2"};
|
||||
std::string _strPacketType;
|
||||
Seiscomp::Util::Timer _timer;
|
||||
FileRotator _statusFile;
|
||||
bool _logStatus;
|
||||
uint _statusFlushInterval;
|
||||
bool _logStatus{false};
|
||||
uint _statusFlushInterval{10};
|
||||
bool _dumpPackets{false};
|
||||
Seiscomp::System::HostInfo _hostInfo;
|
||||
Host _host;
|
||||
Plugin::RuntimeInfo _runtimeInfo;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,18 +16,28 @@
|
||||
#ifndef GEMPA_CAPS_PLUGINPACKET_H
|
||||
#define GEMPA_CAPS_PLUGINPACKET_H
|
||||
|
||||
#include "mseed/encoder.h"
|
||||
|
||||
#include "packet.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) {
|
||||
const std::string &locationCode, const std::string &channelCode,
|
||||
void *context = nullptr)
|
||||
: record(rec)
|
||||
, networkCode(networkCode)
|
||||
, stationCode(stationCode)
|
||||
, locationCode(locationCode)
|
||||
, channelCode(channelCode)
|
||||
, timingQuality(-1)
|
||||
, context(context)
|
||||
{
|
||||
streamID = networkCode + "." + stationCode + "." +
|
||||
locationCode + "." + channelCode;
|
||||
}
|
||||
@@ -42,8 +52,8 @@ struct Packet {
|
||||
return packet;
|
||||
}
|
||||
|
||||
typedef std::vector<char> Buffer;
|
||||
typedef boost::shared_ptr<Buffer> BufferPtr;
|
||||
using Buffer = std::vector<char>;
|
||||
using BufferPtr = boost::shared_ptr<Buffer>;
|
||||
|
||||
BufferPtr buffer; // PacketDataHeader, PacketHeader[V1|V2], Data
|
||||
DataRecordPtr record;
|
||||
@@ -58,12 +68,17 @@ struct Packet {
|
||||
#endif
|
||||
std::string uom;
|
||||
int timingQuality;
|
||||
void *context;
|
||||
|
||||
size_t size() const { return buffer->size(); }
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Packet> PacketPtr;
|
||||
|
||||
using PacketPtr = boost::shared_ptr<Packet>;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -83,6 +83,10 @@ inline Time getEndTime(const Time &stime, size_t count, const DataRecord::Header
|
||||
|
||||
RawDataRecord::RawDataRecord() : _dataOfs(0), _dataSize(0), _dirty(false) {}
|
||||
|
||||
DataRecord *RawDataRecord::clone() const {
|
||||
return new RawDataRecord(*this);
|
||||
}
|
||||
|
||||
const char *RawDataRecord::formatName() const {
|
||||
DT2STR("RAW/", _currentHeader.dataType)
|
||||
}
|
||||
@@ -249,31 +253,36 @@ DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
|
||||
_startTime = timestampToTime(_header.samplingTime);
|
||||
|
||||
if ( _header.samplingFrequencyDenominator > 0 &&
|
||||
_header.samplingFrequencyNumerator > 0 )
|
||||
_header.samplingFrequencyNumerator > 0 ) {
|
||||
_endTime = _startTime + samplesToTimeSpan(_header, sampleCount);
|
||||
else
|
||||
}
|
||||
else {
|
||||
_endTime = Time();
|
||||
}
|
||||
|
||||
if ( (start.valid() || end.valid()) && _endTime.valid() ) {
|
||||
// Out of bounds?
|
||||
if ( end.valid() && (end <= _startTime) )
|
||||
if ( end.valid() && (end <= _startTime) ) {
|
||||
return RS_AfterTimeWindow;
|
||||
}
|
||||
|
||||
if ( start.valid() && (start >= _endTime) )
|
||||
if ( start.valid() && (start >= _endTime) ) {
|
||||
return RS_BeforeTimeWindow;
|
||||
}
|
||||
|
||||
// Trim packet front
|
||||
if ( _startTime < start ) {
|
||||
TimeSpan ofs = start - _startTime;
|
||||
sampleOfs = timeSpanToSamplesCeil(_header, ofs);
|
||||
sampleOfs = timeSpanToSamplesFloor(_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
|
||||
else {
|
||||
sampleOfs = 0;
|
||||
}
|
||||
|
||||
if ( maxBytes > 0 ) {
|
||||
int maxSamples = maxBytes / dataTypeSize;
|
||||
@@ -296,10 +305,13 @@ DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
|
||||
CAPS_DEBUG("Triming packet end: added offset of %d samples", trimEnd);
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
sampleOfs = 0;
|
||||
}
|
||||
|
||||
if ( sampleCount == 0 ) return RS_Error;
|
||||
if ( sampleCount == 0 ) {
|
||||
return RS_Error;
|
||||
}
|
||||
|
||||
_currentHeader = _header;
|
||||
|
||||
@@ -308,7 +320,9 @@ DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
|
||||
{
|
||||
// Stay with little endian data
|
||||
RIFF::VectorChunk<1,false> dataChunk(_data, sampleOfs, sampleCount);
|
||||
if ( !dataChunk.get(buf, size) ) return RS_Error;
|
||||
if ( !dataChunk.get(buf, size) ) {
|
||||
return RS_Error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -316,7 +330,9 @@ DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
|
||||
{
|
||||
// Stay with little endian data
|
||||
RIFF::VectorChunk<2,false> dataChunk(_data, sampleOfs, sampleCount);
|
||||
if ( !dataChunk.get(buf, size) ) return RS_Error;
|
||||
if ( !dataChunk.get(buf, size) ) {
|
||||
return RS_Error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -325,7 +341,9 @@ DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
|
||||
{
|
||||
// Stay with little endian data
|
||||
RIFF::VectorChunk<4,false> dataChunk(_data, sampleOfs, sampleCount);
|
||||
if ( !dataChunk.get(buf, size) ) return RS_Error;
|
||||
if ( !dataChunk.get(buf, size) ) {
|
||||
return RS_Error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -334,7 +352,9 @@ DataRecord::ReadStatus RawDataRecord::getData(streambuf &buf, int size,
|
||||
{
|
||||
// Stay with little endian data
|
||||
RIFF::VectorChunk<8,false> dataChunk(_data, sampleOfs, sampleCount);
|
||||
if ( !dataChunk.get(buf, size) ) return RS_Error;
|
||||
if ( !dataChunk.get(buf, size) ) {
|
||||
return RS_Error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
|
||||
#include <gempa/caps/packet.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
struct SC_GEMPA_CAPS_API RawResponseHeader {
|
||||
int64_t timeSeconds;
|
||||
int32_t timeMicroSeconds;
|
||||
@@ -47,7 +47,8 @@ class RawDataRecord : public DataRecord {
|
||||
public:
|
||||
RawDataRecord();
|
||||
|
||||
const char *formatName() const;
|
||||
DataRecord *clone() const override;
|
||||
const char *formatName() const override;
|
||||
|
||||
/**
|
||||
* @brief Reads metadata from data record header
|
||||
@@ -59,7 +60,7 @@ class RawDataRecord : public DataRecord {
|
||||
*/
|
||||
bool readMetaData(std::streambuf &buf, int size,
|
||||
Header &header,
|
||||
Time &startTime, Time &endTime);
|
||||
Time &startTime, Time &endTime) override;
|
||||
|
||||
void setHeader(const Header &header);
|
||||
|
||||
@@ -67,33 +68,33 @@ class RawDataRecord : public DataRecord {
|
||||
* @brief Returns the meta information of the data if supported
|
||||
* @return The data record header
|
||||
*/
|
||||
const Header *header() const;
|
||||
const Header *header() const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the start time of the record
|
||||
* @return The start time
|
||||
*/
|
||||
Time startTime() const;
|
||||
Time startTime() const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the end time of the record
|
||||
* @return The end time
|
||||
*/
|
||||
Time endTime() const;
|
||||
Time endTime() const override;
|
||||
|
||||
/**
|
||||
* @brief canTrim checks if data trimming is possible
|
||||
* without modifying preceding data
|
||||
* @return True, if data trimming is possible
|
||||
*/
|
||||
bool canTrim() const;
|
||||
bool canTrim() const override;
|
||||
|
||||
/**
|
||||
* @brief canMerge checks if data merging is possible
|
||||
* without modifying preceding data
|
||||
* @return True, if data merging is possible
|
||||
*/
|
||||
bool canMerge() const;
|
||||
bool canMerge() const override;
|
||||
|
||||
/**
|
||||
* @brief Trims a record to start and end time. Trimming
|
||||
@@ -109,7 +110,7 @@ class RawDataRecord : public DataRecord {
|
||||
* @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;
|
||||
bool trim(const Time &start, const Time &end) const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the data size in bytes if the current state would
|
||||
@@ -118,7 +119,7 @@ class RawDataRecord : public DataRecord {
|
||||
* @param withHeader Take header into account
|
||||
* @return Returns the data size in bytes
|
||||
*/
|
||||
size_t dataSize(bool withHeader) const;
|
||||
size_t dataSize(bool withHeader) const override;
|
||||
|
||||
/**
|
||||
* @brief Reads the packet data including header from a streambuf
|
||||
@@ -137,7 +138,7 @@ class RawDataRecord : public DataRecord {
|
||||
ReadStatus get(std::streambuf &buf, int size,
|
||||
const Time &start = Time(),
|
||||
const Time &end = Time(),
|
||||
int maxBytes = -1);
|
||||
int maxBytes = -1) override;
|
||||
|
||||
/**
|
||||
* @brief Reads the packet data without header from a streambuf
|
||||
@@ -167,13 +168,13 @@ class RawDataRecord : public DataRecord {
|
||||
* @param Take header into account
|
||||
* @return True, if the data has been written
|
||||
*/
|
||||
bool put(std::streambuf &buf, bool withHeader) const;
|
||||
bool put(std::streambuf &buf, bool withHeader) const override;
|
||||
|
||||
/**
|
||||
* @brief Returns the packet type
|
||||
* @return The packet type
|
||||
*/
|
||||
PacketType packetType() const { return RawDataPacket; }
|
||||
PacketType packetType() const override { return RawDataPacket; }
|
||||
|
||||
/**
|
||||
* @brief Sets the start time of the record
|
||||
@@ -218,18 +219,19 @@ class RawDataRecord : public DataRecord {
|
||||
|
||||
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,
|
||||
bool canTrim() const override { return false; }
|
||||
bool canMerge() const override { return false; }
|
||||
bool trim(const Time &start, const Time &end) const override { return false; }
|
||||
const char *formatName() const override;
|
||||
ReadStatus get(std::streambuf &buf, int size,
|
||||
const Time &/*start*/, const Time &/*end*/,
|
||||
int maxBytes) {
|
||||
int maxBytes) override {
|
||||
return RawDataRecord::get(buf, size, Time(), Time(), maxBytes);
|
||||
}
|
||||
PacketType packetType() const { return FixedRawDataPacket; }
|
||||
PacketType packetType() const override { return FixedRawDataPacket; }
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,18 @@
|
||||
#ifndef GEMPA_CAPS_RECORD_SAMPLER_H
|
||||
#define GEMPA_CAPS_RECORD_SAMPLER_H
|
||||
|
||||
#include <gempa/caps/datetime.h>
|
||||
|
||||
#include <gempa/caps/datetime.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
template<typename T> class RecordBuilder {
|
||||
public:
|
||||
struct Record {
|
||||
@@ -40,7 +43,8 @@ template<typename T> class RecordBuilder {
|
||||
void *userData;
|
||||
};
|
||||
typedef boost::shared_ptr<Record> RecordPtr;
|
||||
typedef boost::function<void (Record *rec, void*)> FlushCallback;
|
||||
typedef std::function<void (Record *rec, void*)> FlushCallback;
|
||||
|
||||
|
||||
public:
|
||||
RecordBuilder() : _bufSize(64) {}
|
||||
@@ -130,6 +134,7 @@ template<typename T> class RecordBuilder {
|
||||
void *_userData;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,11 @@ void RTCM2DataRecord::setSamplingFrequency(uint16_t numerator, uint16_t denomina
|
||||
}
|
||||
|
||||
|
||||
DataRecord *RTCM2DataRecord::clone() const {
|
||||
return new RTCM2DataRecord(*this);
|
||||
}
|
||||
|
||||
|
||||
const char *RTCM2DataRecord::formatName() const {
|
||||
return "RTC2";
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#include <gempa/caps/endianess.h>
|
||||
#include <gempa/caps/packet.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
class RTCM2DataRecord : public DataRecord {
|
||||
public:
|
||||
struct RTCM2Header : Header {
|
||||
@@ -61,37 +61,38 @@ class RTCM2DataRecord : public DataRecord {
|
||||
|
||||
RTCM2DataRecord();
|
||||
|
||||
const char* formatName() const;
|
||||
DataRecord *clone() const override;
|
||||
const char* formatName() const override;
|
||||
|
||||
void setTimeStamp(const Time &ts);
|
||||
|
||||
void setSamplingFrequency(uint16_t numerator, uint16_t denominator);
|
||||
|
||||
virtual bool readMetaData(std::streambuf &buf, int size,
|
||||
bool readMetaData(std::streambuf &buf, int size,
|
||||
Header &header,
|
||||
Time &startTime,
|
||||
Time &endTime);
|
||||
Time &endTime) override;
|
||||
|
||||
virtual const Header *header() const;
|
||||
virtual Time startTime() const;
|
||||
virtual Time endTime() const;
|
||||
const Header *header() const override;
|
||||
Time startTime() const override;
|
||||
Time endTime() const override;
|
||||
|
||||
virtual bool canTrim() const;
|
||||
virtual bool canMerge() const;
|
||||
bool canTrim() const override;
|
||||
bool canMerge() const override;
|
||||
|
||||
virtual bool trim(const Time &start,
|
||||
const Time &end) const;
|
||||
bool trim(const Time &start,
|
||||
const Time &end) const override;
|
||||
|
||||
virtual size_t dataSize(bool withHeader) const;
|
||||
size_t dataSize(bool withHeader) const override;
|
||||
|
||||
virtual ReadStatus get(std::streambuf &buf, int size,
|
||||
ReadStatus get(std::streambuf &buf, int size,
|
||||
const Time &start,
|
||||
const Time &end,
|
||||
int maxSize = -1);
|
||||
int maxSize = -1) override;
|
||||
|
||||
virtual bool put(std::streambuf &buf, bool withHeader) const;
|
||||
bool put(std::streambuf &buf, bool withHeader) const override;
|
||||
|
||||
PacketType packetType() const { return RTCM2Packet; }
|
||||
PacketType packetType() const override { return RTCM2Packet; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#ifndef GEMPA_CAPS_SESSIONTABLE_H
|
||||
#define GEMPA_CAPS_SESSIONTABLE_H
|
||||
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
@@ -26,6 +28,7 @@
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
struct SessionTableItem {
|
||||
SessionTableItem() : samplingFrequency(0), samplingFrequencyDivider(0),
|
||||
fSamplingFrequency(0.0), dataType(DT_Unknown),
|
||||
@@ -42,8 +45,8 @@ struct SessionTableItem {
|
||||
DataType dataType;
|
||||
int dataSize;
|
||||
UOM uom;
|
||||
Time startTime;
|
||||
Time endTime;
|
||||
std::optional<Time> startTime;
|
||||
std::optional<Time> endTime;
|
||||
void *userData;
|
||||
|
||||
bool splitStreamID();
|
||||
@@ -54,7 +57,7 @@ class SC_GEMPA_CAPS_API SessionTable : public std::map<int, SessionTableItem> {
|
||||
public:
|
||||
enum Status {Success, Error, EOD};
|
||||
|
||||
typedef std::function<void (SessionTableItem*)> CallbackFunc;
|
||||
using CallbackFunc = std::function<void (SessionTableItem*)>;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
@@ -97,6 +100,7 @@ class SC_GEMPA_CAPS_API SessionTable : public std::map<int, SessionTableItem> {
|
||||
CallbackFunc _itemAboutToBeRemovedFunc;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ Socket::Device::Status Socket::setNonBlocking(bool nb) {
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
Socket::Status Socket::connect(const std::string &hostname, uint16_t port) {
|
||||
Socket::Status Socket::connect(const std::string &hostname, uint16_t port, int timeout) {
|
||||
if ( _fd != -1 ) {
|
||||
//CAPS_WARNING("closing stale socket");
|
||||
close();
|
||||
@@ -250,7 +250,7 @@ Socket::Status Socket::connect(const std::string &hostname, uint16_t port) {
|
||||
|
||||
int ret = getaddrinfo(hostname.c_str(), strPort.c_str(), &hints, &res);
|
||||
if ( ret ) {
|
||||
CAPS_DEBUG("Test3 Socket::connect(%s:%d): %s",
|
||||
CAPS_DEBUG("Socket::connect(%s:%d): %s",
|
||||
hostname.c_str(), port,
|
||||
#ifndef WIN32
|
||||
strerror(errno));
|
||||
@@ -271,14 +271,46 @@ Socket::Status Socket::connect(const std::string &hostname, uint16_t port) {
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
if ( ::connect(_fd, (struct sockaddr *)&addr, addrlen) == -1 ) {
|
||||
if ( errno != EINPROGRESS ) {
|
||||
setNonBlocking(true);
|
||||
|
||||
int res2 = ::connect(_fd, &addr, addrlen);
|
||||
if ( res2 == -1 ) {
|
||||
if ( errno == EINPROGRESS || errno == EAGAIN ) {
|
||||
fd_set wfds;
|
||||
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(_fd, &wfds);
|
||||
|
||||
struct timeval tv{timeout, 0};
|
||||
|
||||
int res = select(_fd + 1, nullptr, &wfds, nullptr, &tv);
|
||||
if ( res == -1 ) {
|
||||
close();
|
||||
return ConnectError;
|
||||
}
|
||||
else if ( res ) {
|
||||
res = ::connect(_fd, &addr, addrlen);
|
||||
if ( res == -1 ) {
|
||||
close();
|
||||
CAPS_DEBUG("Socket::connect(%s:%d): %s",
|
||||
hostname.c_str(), port, strerror(errno));
|
||||
return ConnectError;
|
||||
}
|
||||
}
|
||||
else {
|
||||
close();
|
||||
return Timeout;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*CAPS_DEBUG("Socket::connect(%s:%d): %s",
|
||||
hostname.c_str(), port, strerror(errno));*/
|
||||
close();
|
||||
return errno == ETIMEDOUT ? Timeout : ConnectError;
|
||||
}
|
||||
}
|
||||
|
||||
setNonBlocking(false);
|
||||
#else
|
||||
if ( ::connect(_fd, (struct sockaddr *)&addr, addrlen) == SOCKET_ERROR ) {
|
||||
int err = WSAGetLastError();
|
||||
@@ -445,7 +477,8 @@ int SSLSocket::read(char *data, int len) {
|
||||
|
||||
|
||||
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
Socket::Status SSLSocket::connect(const std::string &hostname, uint16_t port) {
|
||||
Socket::Status SSLSocket::connect(const std::string &hostname, uint16_t port,
|
||||
int timeout) {
|
||||
cleanUp();
|
||||
|
||||
_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
@@ -469,14 +502,52 @@ Socket::Status SSLSocket::connect(const std::string &hostname, uint16_t port) {
|
||||
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));
|
||||
|
||||
setNonBlocking(true);
|
||||
|
||||
int res = 0;
|
||||
while ( (res = SSL_connect(_ssl)) != 1 ) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(_fd, &fds);
|
||||
struct timeval tv{timeout, 0};
|
||||
|
||||
switch ( SSL_get_error(_ssl, res) ) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
res = select(_fd + 1, &fds, nullptr, nullptr, &tv);
|
||||
if ( res == 0 ) {
|
||||
close();
|
||||
return Timeout;
|
||||
}
|
||||
else if ( res == - 1 ) {
|
||||
close();
|
||||
return ConnectError;
|
||||
}
|
||||
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
res = select(_fd + 1, nullptr, &fds, nullptr, &tv);
|
||||
if ( res == 0 ) {
|
||||
close();
|
||||
return Timeout;
|
||||
}
|
||||
else if ( res == - 1 ) {
|
||||
close();
|
||||
return ConnectError;
|
||||
}
|
||||
|
||||
break;
|
||||
default: {
|
||||
CAPS_ERROR("Failed to connect with SSL, error %d",
|
||||
SSL_get_error(_ssl, res));
|
||||
close();
|
||||
return ConnectError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setNonBlocking(false);
|
||||
|
||||
return Success;
|
||||
}
|
||||
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
#include <streambuf>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
class SC_GEMPA_CAPS_API Socket {
|
||||
public:
|
||||
typedef uint64_t count_t;
|
||||
@@ -89,7 +89,8 @@ class SC_GEMPA_CAPS_API Socket {
|
||||
|
||||
Device::Status setNonBlocking(bool nb);
|
||||
|
||||
virtual Status connect(const std::string &hostname, uint16_t port);
|
||||
virtual Status connect(const std::string &hostname, uint16_t port,
|
||||
int timeout = 30);
|
||||
|
||||
count_t rx() const { return _bytesReceived; }
|
||||
count_t tx() const { return _bytesSent; }
|
||||
@@ -122,7 +123,7 @@ class SSLSocket : public Socket {
|
||||
int write(const char *data, int len);
|
||||
int read(char *data, int len);
|
||||
|
||||
Status connect(const std::string &hostname, uint16_t port);
|
||||
Status connect(const std::string &hostname, uint16_t port, int timeout = 30);
|
||||
|
||||
virtual const unsigned char *sessionID() const;
|
||||
virtual unsigned int sessionIDLength() const;
|
||||
@@ -161,10 +162,6 @@ class socketbuf : public std::streambuf {
|
||||
_sock = sock;
|
||||
}
|
||||
|
||||
void settimeout(const struct timeval &tv) {
|
||||
_timeout = tv;
|
||||
}
|
||||
|
||||
void set_read_limit(int bytes) {
|
||||
_allowed_reads = bytes;
|
||||
|
||||
@@ -258,7 +255,6 @@ class socketbuf : public std::streambuf {
|
||||
|
||||
private:
|
||||
T *_sock;
|
||||
timeval _timeout;
|
||||
char _in[N];
|
||||
char _out[N];
|
||||
bool _block_write;
|
||||
@@ -266,6 +262,7 @@ class socketbuf : public std::streambuf {
|
||||
int _allowed_reads;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
#ifndef STRPTIME_H
|
||||
#define STRPTIME_H
|
||||
|
||||
|
||||
struct tm;
|
||||
/*
|
||||
* Version of "strptime()", for the benefit of OSes that don't have it.
|
||||
*/
|
||||
extern char *strptime(const char *, const char *, struct tm *);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@ SET(TESTS
|
||||
datetime_time.cpp
|
||||
endianess.cpp
|
||||
mseedpacket.cpp
|
||||
url.cpp
|
||||
)
|
||||
|
||||
FOREACH(testSrc ${TESTS})
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
#include <gempa/caps/datetime.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/datetime.h>
|
||||
|
||||
@@ -146,9 +146,9 @@ BOOST_AUTO_TEST_CASE(construction) {
|
||||
|
||||
// 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);
|
||||
double secondsPerDay = 86400;
|
||||
double secondsPerYear = 31536000;
|
||||
BOOST_WARN_CLOSE(double(date), secondsPerDay*2 + secondsPerYear,0.3);
|
||||
}
|
||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
@@ -393,13 +393,14 @@ BOOST_AUTO_TEST_CASE(setAndGet) {
|
||||
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);
|
||||
// Won't work on 32-bit systems
|
||||
// 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);
|
||||
@@ -409,12 +410,12 @@ BOOST_AUTO_TEST_CASE(setAndGet) {
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
@@ -477,9 +478,9 @@ BOOST_AUTO_TEST_CASE(localTime) {
|
||||
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);
|
||||
double secondsPerDay = 86400;
|
||||
double secondsPerYear = 31536000;
|
||||
BOOST_CHECK_EQUAL(double(yearDay),secondsPerDay*2 + secondsPerYear);
|
||||
}
|
||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/endianess.h>
|
||||
#include <gempa/caps/rawpacket.cpp>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include "test_utils.h"
|
||||
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/mseedpacket.h>
|
||||
#include <gempa/caps/rawpacket.cpp>
|
||||
@@ -27,10 +27,8 @@
|
||||
#include <gempa/caps/datetime.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <streambuf>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace bu = boost::unit_test;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/packet.h>
|
||||
#include <gempa/caps/rawpacket.cpp>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include "test_utils.h"
|
||||
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/rawpacket.cpp>
|
||||
#include <gempa/caps/mseedpacket.cpp>
|
||||
|
||||
101
libs/gempa/caps/test/url.cpp
Normal file
101
libs/gempa/caps/test/url.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2021 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_TEST_MODULE gempa
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/url.h>
|
||||
|
||||
|
||||
namespace gc = Gempa::CAPS;
|
||||
namespace bu = boost::unit_test;
|
||||
|
||||
using namespace gc;
|
||||
using namespace std;
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(gempa_common_caps_url)
|
||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
||||
|
||||
|
||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
BOOST_AUTO_TEST_CASE(url_construct) {
|
||||
Url url;
|
||||
BOOST_CHECK_EQUAL(url.host, "");
|
||||
BOOST_CHECK_EQUAL(url.user, "");
|
||||
BOOST_CHECK_EQUAL(url.password, "");
|
||||
BOOST_CHECK_EQUAL(url.port, 0);
|
||||
BOOST_CHECK_EQUAL(url.protocol, "");
|
||||
}
|
||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
||||
|
||||
|
||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
BOOST_AUTO_TEST_CASE(url_parse) {
|
||||
{
|
||||
Url url;
|
||||
BOOST_CHECK(url.parse("localhost"));
|
||||
BOOST_CHECK_EQUAL(url.host, "localhost");
|
||||
BOOST_CHECK_EQUAL(url.port, 18002);
|
||||
}
|
||||
|
||||
{
|
||||
Url url;
|
||||
BOOST_CHECK(url.parse("localhost:18003"));
|
||||
BOOST_CHECK_EQUAL(url.host, "localhost");
|
||||
BOOST_CHECK_EQUAL(url.port, 18003);
|
||||
BOOST_CHECK_EQUAL(url.protocol, "caps");
|
||||
}
|
||||
|
||||
{
|
||||
Url url;
|
||||
BOOST_CHECK(!url.parse("localhost:65536"));
|
||||
BOOST_CHECK(!url.parse("localhost:-1"));
|
||||
BOOST_CHECK(!url.parse("localhost:0"));
|
||||
}
|
||||
|
||||
{
|
||||
Url url;
|
||||
BOOST_CHECK(url.parse("caps:gempa@localhost:18003"));
|
||||
BOOST_CHECK_EQUAL(url.host, "localhost");
|
||||
BOOST_CHECK_EQUAL(url.user, "caps");
|
||||
BOOST_CHECK_EQUAL(url.password, "gempa");
|
||||
BOOST_CHECK_EQUAL(url.port, 18003);
|
||||
BOOST_CHECK_EQUAL(url.protocol, "caps");
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
Url url;
|
||||
BOOST_CHECK(url.parse("capss://guest:guest@caps.gempa.de:18008"));
|
||||
BOOST_CHECK_EQUAL(url.host, "caps.gempa.de");
|
||||
BOOST_CHECK_EQUAL(url.user, "guest");
|
||||
BOOST_CHECK_EQUAL(url.password, "guest");
|
||||
BOOST_CHECK_EQUAL(url.port, 18008);
|
||||
BOOST_CHECK_EQUAL(url.protocol, "capss");
|
||||
}
|
||||
|
||||
}
|
||||
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
|
||||
|
||||
|
||||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
#define SEISCOMP_TEST_MODULE gempa
|
||||
#include <seiscomp3/unittest/unittests.h>
|
||||
#include <seiscomp/unittest/unittests.h>
|
||||
|
||||
#include <gempa/caps/utils.h>
|
||||
|
||||
|
||||
77
libs/gempa/caps/url.cpp
Normal file
77
libs/gempa/caps/url.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2021 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 "url.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
const string CAPS_PROTOCOL = "caps";
|
||||
const string CAPS_SSL_PROTOCOL = "capss";
|
||||
|
||||
}
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
Url::Url()
|
||||
: port(0) {}
|
||||
|
||||
bool Url::parse(const string &address, uint16_t defaultPort) {
|
||||
string addr = trim(address);
|
||||
|
||||
// step 1: protocol
|
||||
size_t pos = addr.find("://");
|
||||
if ( pos == string::npos ) {
|
||||
protocol = CAPS_PROTOCOL;
|
||||
}
|
||||
else {
|
||||
protocol = addr.substr(0, pos);
|
||||
addr = addr.substr(pos + 3);
|
||||
}
|
||||
|
||||
if ( !boost::iequals(protocol, CAPS_PROTOCOL) &&
|
||||
!boost::iequals(protocol, CAPS_SSL_PROTOCOL) ) {
|
||||
errorString = "Unsupported protocol: %" + protocol;
|
||||
return false;
|
||||
}
|
||||
|
||||
// step 2: user:pass
|
||||
vector<string> toks;
|
||||
boost::split(toks, addr, boost::is_any_of("@"), boost::token_compress_on);
|
||||
if ( toks.size() >= 2 ) {
|
||||
string login = toks[0];
|
||||
addr = toks[1];
|
||||
boost::split(toks, login, boost::is_any_of(":"), boost::token_compress_on);
|
||||
user = toks.size() > 0 ? toks[0] : "";
|
||||
password = toks.size() > 1 ? toks[1] : "";
|
||||
}
|
||||
|
||||
// step 3: address
|
||||
if ( !splitAddress(host, port, addr, defaultPort) ) {
|
||||
errorString = "Wrong address format, expected "
|
||||
"[[caps|capss]://][user:pass@]host[:port]";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
53
libs/gempa/caps/url.h
Normal file
53
libs/gempa/caps/url.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2021 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_URL_H
|
||||
#define GEMPA_CAPS_URL_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
struct Url {
|
||||
Url();
|
||||
|
||||
/**
|
||||
* @brief Reads url parameters from address string. The
|
||||
* addr format is [[caps|capss]://][user:pass@]host[:port].
|
||||
* @param address The address as string
|
||||
* @param defaultPort Default port
|
||||
* @return True if the address could be parsed
|
||||
*/
|
||||
bool parse(const std::string &address, uint16_t defaultPort = 18002);
|
||||
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
std::string user;
|
||||
std::string password;
|
||||
std::string protocol;
|
||||
std::string errorString;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifndef GEMPA_CAPS_UTILS_H
|
||||
#define GEMPA_CAPS_UTILS_H
|
||||
|
||||
|
||||
#include <gempa/caps/packet.h>
|
||||
|
||||
#include <cerrno>
|
||||
@@ -32,6 +33,7 @@
|
||||
namespace Gempa {
|
||||
namespace CAPS {
|
||||
|
||||
|
||||
class arraybuf : public std::streambuf {
|
||||
public:
|
||||
typedef std::streambuf::pos_type pos_type;
|
||||
@@ -371,7 +373,9 @@ inline uint8_t dataTypeSize(DataType dt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __GEMPA_CAPS_VERSION_H__
|
||||
#define __GEMPA_CAPS_VERSION_H__
|
||||
#ifndef GEMPA_CAPS_VERSION_H
|
||||
#define GEMPA_CAPS_VERSION_H
|
||||
|
||||
|
||||
/* #if (LIB_CAPS_VERSION >= LIB_CAPS_VERSION_CHECK(1, 0, 0)) */
|
||||
@@ -18,15 +18,36 @@
|
||||
#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"
|
||||
#define LIB_CAPS_VERSION 0x030200
|
||||
#define LIB_CAPS_VERSION_NAME "3.2.0"
|
||||
|
||||
/******************************************************************************
|
||||
API Changelog
|
||||
******************************************************************************
|
||||
"3.2.0" 0x030200
|
||||
- Add Plugin::lastEndTime
|
||||
- Add Plugin::setConnectionIDFile
|
||||
- Add Plugin::connectionID
|
||||
- Add Plugin::setConnectedCallback
|
||||
- Add Plugin::setDisconnectedCallback
|
||||
- Add Plugin::setHostInfo
|
||||
- Add Plugin::setRuntimeInfo
|
||||
- Add Plugin::pushAny
|
||||
- Add Plugin::pushRaw
|
||||
- Add Plugin::pushRecord
|
||||
- Change Plugin push signature
|
||||
"2.0.0" 0x020000
|
||||
- Add Plugin::setAddress
|
||||
- Add Plugin::flushEncoders
|
||||
- Add Plugin::dumpPackets
|
||||
- Add Plugin::packetBuffer
|
||||
- Add Plugin::setAgent
|
||||
- Add Plugin::getAPIVersion
|
||||
- Change Plugin memory layout
|
||||
|
||||
"1.0.0" 0x010000
|
||||
- Initial version
|
||||
|
||||
*/
|
||||
|
||||
#endif // __GEMPA_CAPS_VERSION_H__
|
||||
#endif // GEMPA_CAPS_VERSION_H
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%feature("notabstract") Gempa::CAPS::AnyDataRecord;
|
||||
%feature("notabstract") Gempa::CAPS::AnyDataRecord;
|
||||
%include "stdint.i"
|
||||
|
||||
%init
|
||||
@@ -31,14 +31,13 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
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
|
||||
) {
|
||||
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);
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, NPY_INT8, 1, 1);
|
||||
if ( arr == NULL )
|
||||
break;
|
||||
|
||||
@@ -46,7 +45,7 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
uom, (int8_t*)(arr->data), arr->dimensions[0], dataType);
|
||||
break;
|
||||
case Gempa::CAPS::DT_INT16:
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_INT16, 1, 1);
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, NPY_INT16, 1, 1);
|
||||
if ( arr == NULL )
|
||||
break;
|
||||
|
||||
@@ -54,7 +53,7 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
uom, (int16_t*)(arr->data), arr->dimensions[0], dataType);
|
||||
break;
|
||||
case Gempa::CAPS::DT_INT32:
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_INT32, 1, 1);
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, NPY_INT32, 1, 1);
|
||||
if ( arr == NULL )
|
||||
break;
|
||||
|
||||
@@ -62,7 +61,7 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
uom, (int32_t*)(arr->data), arr->dimensions[0], dataType);
|
||||
break;
|
||||
case Gempa::CAPS::DT_FLOAT:
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_FLOAT32, 1, 1);
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, NPY_FLOAT32, 1, 1);
|
||||
if ( arr == NULL )
|
||||
break;
|
||||
|
||||
@@ -70,7 +69,7 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
uom, (float*)(arr->data), arr->dimensions[0], dataType);
|
||||
break;
|
||||
case Gempa::CAPS::DT_DOUBLE:
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, PyArray_FLOAT64, 1, 1);
|
||||
arr = (PyArrayObject*) PyArray_ContiguousFromObject(obj, NPY_FLOAT64, 1, 1);
|
||||
if ( arr == NULL )
|
||||
break;
|
||||
|
||||
@@ -85,6 +84,21 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
return status;
|
||||
}
|
||||
|
||||
Gempa::CAPS::Plugin::Status push(const std::string &net, const std::string &sta,
|
||||
const std::string &loc, const std::string &cha,
|
||||
const std::string &uom, PyObject *obj) {
|
||||
char *data;
|
||||
Py_ssize_t len;
|
||||
if ( PyBytes_AsStringAndSize(obj, &data, &len) == -1 )
|
||||
return Gempa::CAPS::Plugin::PacketLoss;
|
||||
|
||||
Gempa::CAPS::MSEEDDataRecord *mseed = new Gempa::CAPS::MSEEDDataRecord;
|
||||
Gempa::CAPS::DataRecordPtr rec(mseed);
|
||||
mseed->setData(data ,len);
|
||||
|
||||
return self->push(net, sta, loc, cha, rec, uom);
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -98,12 +112,37 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
return self->push(net, sta, loc, cha, stime, numerator,
|
||||
denominator, format, data, len);
|
||||
}
|
||||
|
||||
Gempa::CAPS::Plugin::Status pushAny(const std::string &net, const std::string &sta,
|
||||
const std::string &loc, const std::string &cha,
|
||||
const Time &stime, const Time &etime,
|
||||
uint16_t numerator, uint16_t denominator,
|
||||
const std::string &format, const std::string &uom,
|
||||
PyObject *obj) {
|
||||
char *data;
|
||||
Py_ssize_t len;
|
||||
if ( PyBytes_AsStringAndSize(obj, &data, &len) == -1 )
|
||||
return Gempa::CAPS::Plugin::PacketLoss;
|
||||
|
||||
return self->pushAny(net, sta, loc, cha, stime, etime,
|
||||
numerator, denominator, format, uom, data, len);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
%include "exception.i"
|
||||
%include "std_string.i"
|
||||
%include "numpy.i"
|
||||
|
||||
|
||||
%exception Gempa::CAPS::Plugin::push {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
$action
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
|
||||
|
||||
%include "gempa/caps/api.h"
|
||||
%include "gempa/caps/datetime.h"
|
||||
%include "gempa/caps/packet.h"
|
||||
@@ -115,7 +154,9 @@ typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
%include "gempa/caps/encoderfactory.h"
|
||||
%include "gempa/caps/mseedpacket.h"
|
||||
typedef Gempa::CAPS::Plugin::Buffer Buffer;
|
||||
%apply SWIGTYPE *DISOWN {Gempa::CAPS::EncoderFactory *factory};
|
||||
%include "gempa/caps/plugin.h"
|
||||
%clear Gempa::CAPS::EncoderFactory *factory;
|
||||
%include "gempa/caps/rawpacket.h"
|
||||
%include "gempa/caps/riff.h"
|
||||
%include "gempa/caps/rtcm2packet.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user