|
|
|
/*****************************************************************************
|
|
|
|
* mseed.cpp
|
|
|
|
*
|
|
|
|
* Mini-SEED format implementation
|
|
|
|
*
|
|
|
|
* (c) 2000 Andres Heinloo, GFZ Potsdam
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any later
|
|
|
|
* version. For more information, see http://www.gnu.org/
|
|
|
|
*
|
|
|
|
* ================
|
|
|
|
* Change log
|
|
|
|
* ===============
|
|
|
|
*
|
|
|
|
* 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH)
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include <gempa/caps/mseedpacket.h>
|
|
|
|
|
|
|
|
#include "mseed.h"
|
|
|
|
#include "slink.h"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
#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,
|
|
|
|
uint8_t recordLength)
|
|
|
|
: networkCode(netcode)
|
|
|
|
, stationCode(stacode)
|
|
|
|
, locationCode(loccode)
|
|
|
|
, channelCode(chacode)
|
|
|
|
, packType(packType)
|
|
|
|
, recordLength(recordLength)
|
|
|
|
{
|
|
|
|
if(freqn == 0 || freqd == 0) {
|
|
|
|
sample_rate_factor = 0;
|
|
|
|
sample_rate_multiplier = 0;
|
|
|
|
}
|
|
|
|
else if(!(freqn % freqd)) {
|
|
|
|
sample_rate_factor = freqn / freqd;
|
|
|
|
sample_rate_multiplier = 1;
|
|
|
|
}
|
|
|
|
else if(!(freqd % freqn)) {
|
|
|
|
sample_rate_factor = -freqd / freqn;
|
|
|
|
sample_rate_multiplier = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sample_rate_factor = -freqd;
|
|
|
|
sample_rate_multiplier = freqn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MSEEDDataRecord *MSEEDFormat::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);
|
|
|
|
|
|
|
|
char *buf = record->data()->data();
|
|
|
|
int n;
|
|
|
|
|
|
|
|
sl_fsdh_s* fsdh = (sl_fsdh_s *)buf;
|
|
|
|
|
|
|
|
memset(fsdh, 0, buflen);
|
|
|
|
|
|
|
|
const int start_frames = (sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s) +
|
|
|
|
sizeof(sl_blkt_1001_s) + 63) & 0xffffffc0; // align to 64 bytes
|
|
|
|
|
|
|
|
dataptr = (void *)((char *) fsdh + start_frames);
|
|
|
|
datalen = buflen - start_frames;
|
|
|
|
|
|
|
|
fsdh->dhq_indicator = 'D';
|
|
|
|
fsdh->reserved = ' ';
|
|
|
|
|
|
|
|
strncpy(fsdh->station, stationCode.c_str(), 5);
|
|
|
|
if((n = stationCode.length()) < 5) memset(fsdh->station + n, 32, 5 - n);
|
|
|
|
strncpy(fsdh->location, locationCode.c_str(), 2);
|
|
|
|
if((n = locationCode.length()) < 2) memset(fsdh->location + n, 32, 2 - n);
|
|
|
|
strncpy(fsdh->channel, channelCode.c_str(), 3);
|
|
|
|
if((n = channelCode.length()) < 3) memset(fsdh->channel + n, 32, 3 - n);
|
|
|
|
strncpy(fsdh->network, networkCode.c_str(), 2);
|
|
|
|
if((n = networkCode.length()) < 2) memset(fsdh->network + n, 32, 2 - n);
|
|
|
|
|
|
|
|
int year, doy, hour, min, sec;
|
|
|
|
it.get2(&year, &doy, &hour, &min, &sec);
|
|
|
|
|
|
|
|
fsdh->start_time.year = htons(year);
|
|
|
|
fsdh->start_time.day = htons(doy+1);
|
|
|
|
fsdh->start_time.hour = hour;
|
|
|
|
fsdh->start_time.min = min;
|
|
|
|
fsdh->start_time.sec = sec;
|
|
|
|
fsdh->start_time.fract = htons(it.microseconds() / 100);
|
|
|
|
fsdh->samprate_fact = (int16_t)htons(sample_rate_factor);
|
|
|
|
fsdh->samprate_mult = (int16_t)htons(sample_rate_multiplier);
|
|
|
|
fsdh->num_blockettes = 1;
|
|
|
|
|
|
|
|
div_t d_corr = div(usec_correction + ((usec_correction < 0) ? -50: 50), 100);
|
|
|
|
fsdh->time_correct = (int32_t)htonl(d_corr.quot);
|
|
|
|
|
|
|
|
fsdh->begin_data = htons(start_frames);
|
|
|
|
fsdh->begin_blockette = htons(sizeof(sl_fsdh_s));
|
|
|
|
|
|
|
|
sl_blkt_1000_s* blkt_1000 = (sl_blkt_1000_s *)((char *) fsdh + sizeof(sl_fsdh_s));
|
|
|
|
blkt_1000->blkt_type = htons(1000); // Data Only SEED Blockette
|
|
|
|
|
|
|
|
blkt_1000->encoding = packType;
|
|
|
|
blkt_1000->word_swap = 1; // big endian
|
|
|
|
blkt_1000->rec_len = recordLength; // 9 = 512 bytes
|
|
|
|
|
|
|
|
if ( timing_quality >= 0 ) {
|
|
|
|
blkt_1000->next_blkt = htons(sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s));
|
|
|
|
++fsdh->num_blockettes;
|
|
|
|
|
|
|
|
sl_blkt_1001_s* blkt_1001 = (sl_blkt_1001_s *)((char *) fsdh +
|
|
|
|
sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s));
|
|
|
|
|
|
|
|
blkt_1001->blkt_type = htons(1001); // Data Extension Blockette
|
|
|
|
blkt_1001->timing_qual = timing_quality;
|
|
|
|
|
|
|
|
blkt_1001->usec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return record;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MSEEDFormat::updateBuffer(MSEEDDataRecord *rec, int samples, int frames) {
|
|
|
|
sl_fsdh_s* fsdh = (sl_fsdh_s *)rec->data()->data();
|
|
|
|
char temp[7];
|
|
|
|
|
|
|
|
sprintf(temp, "%06d", (int)0);
|
|
|
|
memcpy(fsdh->sequence_number,temp,6);
|
|
|
|
fsdh->dhq_indicator = 'D';
|
|
|
|
fsdh->num_samples = htons(samples);
|
|
|
|
|
|
|
|
sl_blkt_1000_s* blkt_1000 = (sl_blkt_1000_s *)((char *) fsdh + sizeof(sl_fsdh_s));
|
|
|
|
|
|
|
|
if ( ntohs(blkt_1000->next_blkt) != 0 ) {
|
|
|
|
sl_blkt_1001_s* blkt_1001 = (sl_blkt_1001_s *)((char *) fsdh +
|
|
|
|
sizeof(sl_fsdh_s) + sizeof(sl_blkt_1000_s));
|
|
|
|
blkt_1001->frame_cnt = frames;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|