You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1180 lines
42 KiB
C
1180 lines
42 KiB
C
4 years ago
|
/***************************************************************************
|
||
|
* msrutils.c:
|
||
|
*
|
||
|
* Generic routines to operate on Mini-SEED records.
|
||
|
*
|
||
|
* Written by Chad Trabant
|
||
|
* ORFEUS/EC-Project MEREDIAN
|
||
|
* IRIS Data Management Center
|
||
|
*
|
||
|
* modified: 2012.088
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <time.h>
|
||
|
|
||
|
#include "libmseed.h"
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_init:
|
||
|
*
|
||
|
* Initialize and return an MSRecord struct, allocating memory if
|
||
|
* needed. If memory for the fsdh and datasamples fields has been
|
||
|
* allocated the pointers will be retained for reuse. If a blockette
|
||
|
* chain is present all associated memory will be released.
|
||
|
*
|
||
|
* Returns a pointer to a MSRecord struct on success or NULL on error.
|
||
|
***************************************************************************/
|
||
|
MSRecord *
|
||
|
msr_init ( MSRecord *msr )
|
||
|
{
|
||
|
void *fsdh = 0;
|
||
|
void *datasamples = 0;
|
||
|
|
||
|
if ( ! msr )
|
||
|
{
|
||
|
msr = (MSRecord *) malloc (sizeof(MSRecord));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fsdh = msr->fsdh;
|
||
|
datasamples = msr->datasamples;
|
||
|
|
||
|
if ( msr->blkts )
|
||
|
msr_free_blktchain (msr);
|
||
|
|
||
|
if ( msr->ststate )
|
||
|
free (msr->ststate);
|
||
|
}
|
||
|
|
||
|
if ( msr == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_init(): Cannot allocate memory\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
memset (msr, 0, sizeof (MSRecord));
|
||
|
|
||
|
msr->fsdh = fsdh;
|
||
|
msr->datasamples = datasamples;
|
||
|
|
||
|
msr->reclen = -1;
|
||
|
msr->samplecnt = -1;
|
||
|
msr->byteorder = -1;
|
||
|
msr->encoding = -1;
|
||
|
|
||
|
return msr;
|
||
|
} /* End of msr_init() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_free:
|
||
|
*
|
||
|
* Free all memory associated with a MSRecord struct.
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
msr_free ( MSRecord **ppmsr )
|
||
|
{
|
||
|
if ( ppmsr != NULL && *ppmsr != 0 )
|
||
|
{
|
||
|
/* Free fixed section header if populated */
|
||
|
if ( (*ppmsr)->fsdh )
|
||
|
free ((*ppmsr)->fsdh);
|
||
|
|
||
|
/* Free blockette chain if populated */
|
||
|
if ( (*ppmsr)->blkts )
|
||
|
msr_free_blktchain (*ppmsr);
|
||
|
|
||
|
/* Free datasamples if present */
|
||
|
if ( (*ppmsr)->datasamples )
|
||
|
free ((*ppmsr)->datasamples);
|
||
|
|
||
|
/* Free stream processing state if present */
|
||
|
if ( (*ppmsr)->ststate )
|
||
|
free ((*ppmsr)->ststate);
|
||
|
|
||
|
free (*ppmsr);
|
||
|
|
||
|
*ppmsr = NULL;
|
||
|
}
|
||
|
} /* End of msr_free() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_free_blktchain:
|
||
|
*
|
||
|
* Free all memory associated with a blockette chain in a MSRecord
|
||
|
* struct and set MSRecord->blkts to NULL. Also reset the shortcut
|
||
|
* blockette pointers.
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
msr_free_blktchain ( MSRecord *msr )
|
||
|
{
|
||
|
if ( msr )
|
||
|
{
|
||
|
if ( msr->blkts )
|
||
|
{
|
||
|
BlktLink *bc = msr->blkts;
|
||
|
BlktLink *nb = NULL;
|
||
|
|
||
|
while ( bc )
|
||
|
{
|
||
|
nb = bc->next;
|
||
|
|
||
|
if ( bc->blktdata )
|
||
|
free (bc->blktdata);
|
||
|
|
||
|
free (bc);
|
||
|
|
||
|
bc = nb;
|
||
|
}
|
||
|
|
||
|
msr->blkts = 0;
|
||
|
}
|
||
|
|
||
|
msr->Blkt100 = 0;
|
||
|
msr->Blkt1000 = 0;
|
||
|
msr->Blkt1001 = 0;
|
||
|
}
|
||
|
} /* End of msr_free_blktchain() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_addblockette:
|
||
|
*
|
||
|
* Add a blockette to the blockette chain of an MSRecord. 'blktdata'
|
||
|
* should be the body of the blockette type 'blkttype' of 'length'
|
||
|
* bytes without the blockette header (type and next offsets). The
|
||
|
* 'chainpos' value controls which end of the chain the blockette is
|
||
|
* added to. If 'chainpos' is 0 the blockette will be added to the
|
||
|
* end of the chain (last blockette), other wise it will be added to
|
||
|
* the beginning of the chain (first blockette).
|
||
|
*
|
||
|
* Returns a pointer to the BlktLink added to the chain on success and
|
||
|
* NULL on error.
|
||
|
***************************************************************************/
|
||
|
BlktLink *
|
||
|
msr_addblockette (MSRecord *msr, char *blktdata, int length, int blkttype,
|
||
|
int chainpos)
|
||
|
{
|
||
|
BlktLink *blkt;
|
||
|
|
||
|
if ( ! msr )
|
||
|
return NULL;
|
||
|
|
||
|
blkt = msr->blkts;
|
||
|
|
||
|
if ( blkt )
|
||
|
{
|
||
|
if ( chainpos != 0 )
|
||
|
{
|
||
|
blkt = (BlktLink *) malloc (sizeof(BlktLink));
|
||
|
|
||
|
blkt->next = msr->blkts;
|
||
|
msr->blkts = blkt;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Find the last blockette */
|
||
|
while ( blkt && blkt->next )
|
||
|
{
|
||
|
blkt = blkt->next;
|
||
|
}
|
||
|
|
||
|
blkt->next = (BlktLink *) malloc (sizeof(BlktLink));
|
||
|
|
||
|
blkt = blkt->next;
|
||
|
blkt->next = 0;
|
||
|
}
|
||
|
|
||
|
if ( blkt == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_addblockette(): Cannot allocate memory\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
msr->blkts = (BlktLink *) malloc (sizeof(BlktLink));
|
||
|
|
||
|
if ( msr->blkts == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_addblockette(): Cannot allocate memory\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
blkt = msr->blkts;
|
||
|
blkt->next = 0;
|
||
|
}
|
||
|
|
||
|
blkt->blktoffset = 0;
|
||
|
blkt->blkt_type = blkttype;
|
||
|
blkt->next_blkt = 0;
|
||
|
|
||
|
blkt->blktdata = (char *) malloc (length);
|
||
|
|
||
|
if ( blkt->blktdata == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_addblockette(): Cannot allocate memory\n");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
memcpy (blkt->blktdata, blktdata, length);
|
||
|
blkt->blktdatalen = length;
|
||
|
|
||
|
/* Setup the shortcut pointer for common blockettes */
|
||
|
switch ( blkttype )
|
||
|
{
|
||
|
case 100:
|
||
|
msr->Blkt100 = blkt->blktdata;
|
||
|
break;
|
||
|
case 1000:
|
||
|
msr->Blkt1000 = blkt->blktdata;
|
||
|
break;
|
||
|
case 1001:
|
||
|
msr->Blkt1001 = blkt->blktdata;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return blkt;
|
||
|
} /* End of msr_addblockette() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_normalize_header:
|
||
|
*
|
||
|
* Normalize header values between the MSRecord struct and the
|
||
|
* associated fixed-section of the header and blockettes. Essentially
|
||
|
* this updates the SEED structured data in the MSRecord.fsdh struct
|
||
|
* and MSRecord.blkts chain with values stored at the MSRecord level.
|
||
|
*
|
||
|
* Returns the header length in bytes on success or -1 on error.
|
||
|
***************************************************************************/
|
||
|
int
|
||
|
msr_normalize_header ( MSRecord *msr, flag verbose )
|
||
|
{
|
||
|
struct blkt_link_s *cur_blkt;
|
||
|
char seqnum[7];
|
||
|
int offset = 0;
|
||
|
int blktcnt = 0;
|
||
|
int reclenexp = 0;
|
||
|
int reclenfind;
|
||
|
|
||
|
if ( ! msr )
|
||
|
return -1;
|
||
|
|
||
|
/* Update values in fixed section of data header */
|
||
|
if ( msr->fsdh )
|
||
|
{
|
||
|
if ( verbose > 2 )
|
||
|
ms_log (1, "Normalizing fixed section of data header\n");
|
||
|
|
||
|
/* Roll-over sequence number if necessary */
|
||
|
if ( msr->sequence_number > 999999 )
|
||
|
msr->sequence_number = 1;
|
||
|
|
||
|
/* Update values in the MSRecord.fsdh struct */
|
||
|
snprintf (seqnum, 7, "%06d", msr->sequence_number);
|
||
|
memcpy (msr->fsdh->sequence_number, seqnum, 6);
|
||
|
msr->fsdh->dataquality = msr->dataquality;
|
||
|
msr->fsdh->reserved = ' ';
|
||
|
ms_strncpopen (msr->fsdh->network, msr->network, 2);
|
||
|
ms_strncpopen (msr->fsdh->station, msr->station, 5);
|
||
|
ms_strncpopen (msr->fsdh->location, msr->location, 2);
|
||
|
ms_strncpopen (msr->fsdh->channel, msr->channel, 3);
|
||
|
ms_hptime2btime (msr->starttime, &(msr->fsdh->start_time));
|
||
|
|
||
|
/* When the sampling rate is <= 32767 Hertz determine the factor
|
||
|
* and multipler through rational approximation. For higher rates
|
||
|
* set the factor and multiplier to 0. */
|
||
|
if ( msr->samprate <= 32767.0 )
|
||
|
{
|
||
|
ms_genfactmult (msr->samprate, &(msr->fsdh->samprate_fact), &(msr->fsdh->samprate_mult));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( verbose > 1 )
|
||
|
ms_log (1, "Sampling rate too high to approximate factor & multiplier: %g\n",
|
||
|
msr->samprate);
|
||
|
msr->fsdh->samprate_fact = 0;
|
||
|
msr->fsdh->samprate_mult = 0;
|
||
|
}
|
||
|
|
||
|
offset += 48;
|
||
|
|
||
|
if ( msr->blkts )
|
||
|
msr->fsdh->blockette_offset = offset;
|
||
|
else
|
||
|
msr->fsdh->blockette_offset = 0;
|
||
|
}
|
||
|
|
||
|
/* Traverse blockette chain and performs necessary updates*/
|
||
|
cur_blkt = msr->blkts;
|
||
|
|
||
|
if ( cur_blkt && verbose > 2 )
|
||
|
ms_log (1, "Normalizing blockette chain\n");
|
||
|
|
||
|
while ( cur_blkt )
|
||
|
{
|
||
|
offset += 4;
|
||
|
|
||
|
if ( cur_blkt->blkt_type == 100 && msr->Blkt100 )
|
||
|
{
|
||
|
msr->Blkt100->samprate = (float)msr->samprate;
|
||
|
offset += sizeof (struct blkt_100_s);
|
||
|
}
|
||
|
else if ( cur_blkt->blkt_type == 1000 && msr->Blkt1000 )
|
||
|
{
|
||
|
msr->Blkt1000->byteorder = msr->byteorder;
|
||
|
msr->Blkt1000->encoding = msr->encoding;
|
||
|
|
||
|
/* Calculate the record length as an exponent of 2 */
|
||
|
for (reclenfind=1, reclenexp=1; reclenfind <= MAXRECLEN; reclenexp++)
|
||
|
{
|
||
|
reclenfind *= 2;
|
||
|
if ( reclenfind == msr->reclen ) break;
|
||
|
}
|
||
|
|
||
|
if ( reclenfind != msr->reclen )
|
||
|
{
|
||
|
ms_log (2, "msr_normalize_header(): Record length %d is not a power of 2\n",
|
||
|
msr->reclen);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
msr->Blkt1000->reclen = reclenexp;
|
||
|
|
||
|
offset += sizeof (struct blkt_1000_s);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 1001 )
|
||
|
{
|
||
|
hptime_t sec, usec;
|
||
|
|
||
|
/* Insert microseconds offset */
|
||
|
sec = msr->starttime / (HPTMODULUS / 10000);
|
||
|
usec = msr->starttime - (sec * (HPTMODULUS / 10000));
|
||
|
usec /= (HPTMODULUS / 1000000);
|
||
|
|
||
|
msr->Blkt1001->usec = (int8_t) usec;
|
||
|
offset += sizeof (struct blkt_1001_s);
|
||
|
}
|
||
|
|
||
|
blktcnt++;
|
||
|
cur_blkt = cur_blkt->next;
|
||
|
}
|
||
|
|
||
|
if ( msr->fsdh )
|
||
|
msr->fsdh->numblockettes = blktcnt;
|
||
|
|
||
|
return offset;
|
||
|
} /* End of msr_normalize_header() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_duplicate:
|
||
|
*
|
||
|
* Duplicate an MSRecord struct
|
||
|
* including the fixed-section data
|
||
|
* header and blockette chain. If
|
||
|
* the datadup flag is true and the
|
||
|
* source MSRecord has associated
|
||
|
* data samples copy them as well.
|
||
|
*
|
||
|
* Returns a pointer to a new MSRecord on success and NULL on error.
|
||
|
***************************************************************************/
|
||
|
MSRecord *
|
||
|
msr_duplicate (MSRecord *msr, flag datadup)
|
||
|
{
|
||
|
MSRecord *dupmsr = 0;
|
||
|
int samplesize = 0;
|
||
|
|
||
|
if ( ! msr )
|
||
|
return NULL;
|
||
|
|
||
|
/* Allocate target MSRecord structure */
|
||
|
if ( (dupmsr = msr_init (NULL)) == NULL )
|
||
|
return NULL;
|
||
|
|
||
|
/* Copy MSRecord structure */
|
||
|
memcpy (dupmsr, msr, sizeof(MSRecord));
|
||
|
|
||
|
/* Copy fixed-section data header structure */
|
||
|
if ( msr->fsdh )
|
||
|
{
|
||
|
/* Allocate memory for new FSDH structure */
|
||
|
if ( (dupmsr->fsdh = (struct fsdh_s *) malloc (sizeof(struct fsdh_s))) == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_duplicate(): Error allocating memory\n");
|
||
|
free (dupmsr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Copy the contents */
|
||
|
memcpy (dupmsr->fsdh, msr->fsdh, sizeof(struct fsdh_s));
|
||
|
}
|
||
|
|
||
|
/* Copy the blockette chain */
|
||
|
if ( msr->blkts )
|
||
|
{
|
||
|
BlktLink *blkt = msr->blkts;
|
||
|
BlktLink *next = NULL;
|
||
|
|
||
|
dupmsr->blkts = 0;
|
||
|
while ( blkt )
|
||
|
{
|
||
|
next = blkt->next;
|
||
|
|
||
|
/* Add blockette to chain of new MSRecord */
|
||
|
if ( msr_addblockette (dupmsr, blkt->blktdata, blkt->blktdatalen,
|
||
|
blkt->blkt_type, 0) == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_duplicate(): Error adding blockettes\n");
|
||
|
msr_free (&dupmsr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
blkt = next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Copy data samples if requested and available */
|
||
|
if ( datadup && msr->datasamples )
|
||
|
{
|
||
|
/* Determine size of samples in bytes */
|
||
|
samplesize = ms_samplesize (msr->sampletype);
|
||
|
|
||
|
if ( samplesize == 0 )
|
||
|
{
|
||
|
ms_log (2, "msr_duplicate(): unrecognized sample type: '%c'\n",
|
||
|
msr->sampletype);
|
||
|
free (dupmsr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Allocate memory for new data array */
|
||
|
if ( (dupmsr->datasamples = (void *) malloc ((size_t)(msr->numsamples * samplesize))) == NULL )
|
||
|
{
|
||
|
ms_log (2, "msr_duplicate(): Error allocating memory\n");
|
||
|
free (dupmsr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Copy the data array */
|
||
|
memcpy (dupmsr->datasamples, msr->datasamples, ((size_t)(msr->numsamples * samplesize)));
|
||
|
}
|
||
|
/* Otherwise make sure the sample array and count are zero */
|
||
|
else
|
||
|
{
|
||
|
dupmsr->datasamples = 0;
|
||
|
dupmsr->numsamples = 0;
|
||
|
}
|
||
|
|
||
|
return dupmsr;
|
||
|
} /* End of msr_duplicate() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_samprate:
|
||
|
*
|
||
|
* Calculate and return a double precision sample rate for the
|
||
|
* specified MSRecord. If a Blockette 100 was included and parsed,
|
||
|
* the "Actual sample rate" (field 3) will be returned, otherwise a
|
||
|
* nominal sample rate will be calculated from the sample rate factor
|
||
|
* and multiplier in the fixed section data header.
|
||
|
*
|
||
|
* Returns the positive sample rate on success and -1.0 on error.
|
||
|
***************************************************************************/
|
||
|
double
|
||
|
msr_samprate (MSRecord *msr)
|
||
|
{
|
||
|
if ( ! msr )
|
||
|
return -1.0;
|
||
|
|
||
|
if ( msr->Blkt100 )
|
||
|
return (double) msr->Blkt100->samprate;
|
||
|
else
|
||
|
return msr_nomsamprate (msr);
|
||
|
} /* End of msr_samprate() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_nomsamprate:
|
||
|
*
|
||
|
* Calculate a double precision nominal sample rate from the sample
|
||
|
* rate factor and multiplier in the FSDH struct of the specified
|
||
|
* MSRecord.
|
||
|
*
|
||
|
* Returns the positive sample rate on success and -1.0 on error.
|
||
|
***************************************************************************/
|
||
|
double
|
||
|
msr_nomsamprate (MSRecord *msr)
|
||
|
{
|
||
|
if ( ! msr )
|
||
|
return -1.0;
|
||
|
|
||
|
return ms_nomsamprate (msr->fsdh->samprate_fact, msr->fsdh->samprate_mult);
|
||
|
} /* End of msr_nomsamprate() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_starttime:
|
||
|
*
|
||
|
* Convert a btime struct of a FSDH struct of a MSRecord (the record
|
||
|
* start time) into a high precision epoch time and apply time
|
||
|
* corrections if any are specified in the header and bit 1 of the
|
||
|
* activity flags indicates that it has not already been applied. If
|
||
|
* a Blockette 1001 is included and has been parsed the microseconds
|
||
|
* of field 4 are also applied.
|
||
|
*
|
||
|
* Returns a high precision epoch time on success and HPTERROR on
|
||
|
* error.
|
||
|
***************************************************************************/
|
||
|
hptime_t
|
||
|
msr_starttime (MSRecord *msr)
|
||
|
{
|
||
|
hptime_t starttime = msr_starttime_uc (msr);
|
||
|
|
||
|
if ( ! msr || starttime == HPTERROR )
|
||
|
return HPTERROR;
|
||
|
|
||
|
/* Check if a correction is included and if it has been applied,
|
||
|
bit 1 of activity flags indicates if it has been appiled */
|
||
|
|
||
|
if ( msr->fsdh->time_correct != 0 &&
|
||
|
! (msr->fsdh->act_flags & 0x02) )
|
||
|
{
|
||
|
starttime += (hptime_t) msr->fsdh->time_correct * (HPTMODULUS / 10000);
|
||
|
}
|
||
|
|
||
|
/* Apply microsecond precision in a parsed Blockette 1001 */
|
||
|
if ( msr->Blkt1001 )
|
||
|
{
|
||
|
starttime += (hptime_t) msr->Blkt1001->usec * (HPTMODULUS / 1000000);
|
||
|
}
|
||
|
|
||
|
return starttime;
|
||
|
} /* End of msr_starttime() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_starttime_uc:
|
||
|
*
|
||
|
* Convert a btime struct of a FSDH struct of a MSRecord (the record
|
||
|
* start time) into a high precision epoch time. This time has no
|
||
|
* correction(s) applied to it.
|
||
|
*
|
||
|
* Returns a high precision epoch time on success and HPTERROR on
|
||
|
* error.
|
||
|
***************************************************************************/
|
||
|
hptime_t
|
||
|
msr_starttime_uc (MSRecord *msr)
|
||
|
{
|
||
|
if ( ! msr )
|
||
|
return HPTERROR;
|
||
|
|
||
|
if ( ! msr->fsdh )
|
||
|
return HPTERROR;
|
||
|
|
||
|
return ms_btime2hptime (&msr->fsdh->start_time);
|
||
|
} /* End of msr_starttime_uc() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_endtime:
|
||
|
*
|
||
|
* Calculate the time of the last sample in the record; this is the
|
||
|
* actual last sample time and *not* the time "covered" by the last
|
||
|
* sample.
|
||
|
*
|
||
|
* Returns the time of the last sample as a high precision epoch time
|
||
|
* on success and HPTERROR on error.
|
||
|
***************************************************************************/
|
||
|
hptime_t
|
||
|
msr_endtime (MSRecord *msr)
|
||
|
{
|
||
|
hptime_t span = 0;
|
||
|
|
||
|
if ( ! msr )
|
||
|
return HPTERROR;
|
||
|
|
||
|
if ( msr->samprate > 0.0 && msr->samplecnt > 0 )
|
||
|
span = (hptime_t)(((double) (msr->samplecnt - 1) / msr->samprate * HPTMODULUS) + 0.5);
|
||
|
|
||
|
/* If a positive leap second occurred during this record as denoted by
|
||
|
* bit 4 of the activity flags being set, reduce the end time to match
|
||
|
* the now shifted UTC time. */
|
||
|
if ( msr->fsdh )
|
||
|
if ( msr->fsdh->act_flags & 0x10 )
|
||
|
span -= HPTMODULUS;
|
||
|
|
||
|
return (msr->starttime + span);
|
||
|
} /* End of msr_endtime() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_srcname:
|
||
|
*
|
||
|
* Generate a source name string for a specified MSRecord in the
|
||
|
* format: 'NET_STA_LOC_CHAN' or, if the quality flag is true:
|
||
|
* 'NET_STA_LOC_CHAN_QUAL'. The passed srcname must have enough room
|
||
|
* for the resulting string.
|
||
|
*
|
||
|
* Returns a pointer to the resulting string or NULL on error.
|
||
|
***************************************************************************/
|
||
|
char *
|
||
|
msr_srcname (MSRecord *msr, char *srcname, flag quality)
|
||
|
{
|
||
|
char *src = srcname;
|
||
|
char *cp = srcname;
|
||
|
|
||
|
if ( ! msr || ! srcname )
|
||
|
return NULL;
|
||
|
|
||
|
/* Build the source name string */
|
||
|
cp = msr->network;
|
||
|
while ( *cp ) { *src++ = *cp++; }
|
||
|
*src++ = '_';
|
||
|
cp = msr->station;
|
||
|
while ( *cp ) { *src++ = *cp++; }
|
||
|
*src++ = '_';
|
||
|
cp = msr->location;
|
||
|
while ( *cp ) { *src++ = *cp++; }
|
||
|
*src++ = '_';
|
||
|
cp = msr->channel;
|
||
|
while ( *cp ) { *src++ = *cp++; }
|
||
|
|
||
|
if ( quality )
|
||
|
{
|
||
|
*src++ = '_';
|
||
|
*src++ = msr->dataquality;
|
||
|
}
|
||
|
|
||
|
*src = '\0';
|
||
|
|
||
|
return srcname;
|
||
|
} /* End of msr_srcname() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_print:
|
||
|
*
|
||
|
* Prints header values in an MSRecord struct, if 'details' is greater
|
||
|
* than 0 then detailed information about each blockette is printed.
|
||
|
* If 'details' is greater than 1 very detailed information is
|
||
|
* printed. If no FSDH (msr->fsdh) is present only a single line with
|
||
|
* basic information is printed.
|
||
|
***************************************************************************/
|
||
|
void
|
||
|
msr_print (MSRecord *msr, flag details)
|
||
|
{
|
||
|
double nomsamprate;
|
||
|
char srcname[50];
|
||
|
char time[25];
|
||
|
char b;
|
||
|
int idx;
|
||
|
|
||
|
if ( ! msr )
|
||
|
return;
|
||
|
|
||
|
/* Generate a source name string */
|
||
|
srcname[0] = '\0';
|
||
|
msr_srcname (msr, srcname, 0);
|
||
|
|
||
|
/* Generate a start time string */
|
||
|
ms_hptime2seedtimestr (msr->starttime, time, 1);
|
||
|
|
||
|
/* Report information in the fixed header */
|
||
|
if ( details > 0 && msr->fsdh )
|
||
|
{
|
||
|
nomsamprate = msr_nomsamprate (msr);
|
||
|
|
||
|
ms_log (0, "%s, %06d, %c\n", srcname, msr->sequence_number, msr->dataquality);
|
||
|
ms_log (0, " start time: %s\n", time);
|
||
|
ms_log (0, " number of samples: %d\n", msr->fsdh->numsamples);
|
||
|
ms_log (0, " sample rate factor: %d (%.10g samples per second)\n",
|
||
|
msr->fsdh->samprate_fact, nomsamprate);
|
||
|
ms_log (0, " sample rate multiplier: %d\n", msr->fsdh->samprate_mult);
|
||
|
|
||
|
if ( details > 1 )
|
||
|
{
|
||
|
/* Activity flags */
|
||
|
b = msr->fsdh->act_flags;
|
||
|
ms_log (0, " activity flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] Calibration signals present\n");
|
||
|
if ( b & 0x02 ) ms_log (0, " [Bit 1] Time correction applied\n");
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Beginning of an event, station trigger\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] End of an event, station detrigger\n");
|
||
|
if ( b & 0x10 ) ms_log (0, " [Bit 4] A positive leap second happened in this record\n");
|
||
|
if ( b & 0x20 ) ms_log (0, " [Bit 5] A negative leap second happened in this record\n");
|
||
|
if ( b & 0x40 ) ms_log (0, " [Bit 6] Event in progress\n");
|
||
|
if ( b & 0x80 ) ms_log (0, " [Bit 7] Undefined bit set\n");
|
||
|
|
||
|
/* I/O and clock flags */
|
||
|
b = msr->fsdh->io_flags;
|
||
|
ms_log (0, " I/O and clock flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] Station volume parity error possibly present\n");
|
||
|
if ( b & 0x02 ) ms_log (0, " [Bit 1] Long record read (possibly no problem)\n");
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Short record read (record padded)\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] Start of time series\n");
|
||
|
if ( b & 0x10 ) ms_log (0, " [Bit 4] End of time series\n");
|
||
|
if ( b & 0x20 ) ms_log (0, " [Bit 5] Clock locked\n");
|
||
|
if ( b & 0x40 ) ms_log (0, " [Bit 6] Undefined bit set\n");
|
||
|
if ( b & 0x80 ) ms_log (0, " [Bit 7] Undefined bit set\n");
|
||
|
|
||
|
/* Data quality flags */
|
||
|
b = msr->fsdh->dq_flags;
|
||
|
ms_log (0, " data quality flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] Amplifier saturation detected\n");
|
||
|
if ( b & 0x02 ) ms_log (0, " [Bit 1] Digitizer clipping detected\n");
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Spikes detected\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] Glitches detected\n");
|
||
|
if ( b & 0x10 ) ms_log (0, " [Bit 4] Missing/padded data present\n");
|
||
|
if ( b & 0x20 ) ms_log (0, " [Bit 5] Telemetry synchronization error\n");
|
||
|
if ( b & 0x40 ) ms_log (0, " [Bit 6] A digital filter may be charging\n");
|
||
|
if ( b & 0x80 ) ms_log (0, " [Bit 7] Time tag is questionable\n");
|
||
|
}
|
||
|
|
||
|
ms_log (0, " number of blockettes: %d\n", msr->fsdh->numblockettes);
|
||
|
ms_log (0, " time correction: %ld\n", (long int) msr->fsdh->time_correct);
|
||
|
ms_log (0, " data offset: %d\n", msr->fsdh->data_offset);
|
||
|
ms_log (0, " first blockette offset: %d\n", msr->fsdh->blockette_offset);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ms_log (0, "%s, %06d, %c, %d, %lld samples, %-.10g Hz, %s\n",
|
||
|
srcname, msr->sequence_number, msr->dataquality,
|
||
|
msr->reclen, (long long int) msr->samplecnt, msr->samprate, time);
|
||
|
}
|
||
|
|
||
|
/* Report information in the blockette chain */
|
||
|
if ( details > 0 && msr->blkts )
|
||
|
{
|
||
|
BlktLink *cur_blkt = msr->blkts;
|
||
|
|
||
|
while ( cur_blkt )
|
||
|
{
|
||
|
if ( cur_blkt->blkt_type == 100 )
|
||
|
{
|
||
|
struct blkt_100_s *blkt_100 = (struct blkt_100_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " actual sample rate: %.10g\n", blkt_100->samprate);
|
||
|
|
||
|
if ( details > 1 )
|
||
|
{
|
||
|
b = blkt_100->flags;
|
||
|
ms_log (0, " undefined flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
|
||
|
ms_log (0, " reserved bytes (3): %u,%u,%u\n",
|
||
|
blkt_100->reserved[0], blkt_100->reserved[1], blkt_100->reserved[2]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 200 )
|
||
|
{
|
||
|
struct blkt_200_s *blkt_200 = (struct blkt_200_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " signal amplitude: %g\n", blkt_200->amplitude);
|
||
|
ms_log (0, " signal period: %g\n", blkt_200->period);
|
||
|
ms_log (0, " background estimate: %g\n", blkt_200->background_estimate);
|
||
|
|
||
|
if ( details > 1 )
|
||
|
{
|
||
|
b = blkt_200->flags;
|
||
|
ms_log (0, " event detection flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] 1: Dilatation wave\n");
|
||
|
else ms_log (0, " [Bit 0] 0: Compression wave\n");
|
||
|
if ( b & 0x02 ) ms_log (0, " [Bit 1] 1: Units after deconvolution\n");
|
||
|
else ms_log (0, " [Bit 1] 0: Units are digital counts\n");
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Bit 0 is undetermined\n");
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_200->reserved);
|
||
|
}
|
||
|
|
||
|
ms_btime2seedtimestr (&blkt_200->time, time);
|
||
|
ms_log (0, " signal onset time: %s\n", time);
|
||
|
ms_log (0, " detector name: %.24s\n", blkt_200->detector);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 201 )
|
||
|
{
|
||
|
struct blkt_201_s *blkt_201 = (struct blkt_201_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " signal amplitude: %g\n", blkt_201->amplitude);
|
||
|
ms_log (0, " signal period: %g\n", blkt_201->period);
|
||
|
ms_log (0, " background estimate: %g\n", blkt_201->background_estimate);
|
||
|
|
||
|
b = blkt_201->flags;
|
||
|
ms_log (0, " event detection flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] 1: Dilation wave\n");
|
||
|
else ms_log (0, " [Bit 0] 0: Compression wave\n");
|
||
|
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_201->reserved);
|
||
|
ms_btime2seedtimestr (&blkt_201->time, time);
|
||
|
ms_log (0, " signal onset time: %s\n", time);
|
||
|
ms_log (0, " SNR values: ");
|
||
|
for (idx=0; idx < 6; idx++) ms_log (0, "%u ", blkt_201->snr_values[idx]);
|
||
|
ms_log (0, "\n");
|
||
|
ms_log (0, " loopback value: %u\n", blkt_201->loopback);
|
||
|
ms_log (0, " pick algorithm: %u\n", blkt_201->pick_algorithm);
|
||
|
ms_log (0, " detector name: %.24s\n", blkt_201->detector);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 300 )
|
||
|
{
|
||
|
struct blkt_300_s *blkt_300 = (struct blkt_300_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_btime2seedtimestr (&blkt_300->time, time);
|
||
|
ms_log (0, " calibration start time: %s\n", time);
|
||
|
ms_log (0, " number of calibrations: %u\n", blkt_300->numcalibrations);
|
||
|
|
||
|
b = blkt_300->flags;
|
||
|
ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] First pulse is positive\n");
|
||
|
if ( b & 0x02 ) ms_log (0, " [Bit 1] Calibration's alternate sign\n");
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
|
||
|
|
||
|
ms_log (0, " step duration: %u\n", blkt_300->step_duration);
|
||
|
ms_log (0, " interval duration: %u\n", blkt_300->interval_duration);
|
||
|
ms_log (0, " signal amplitude: %g\n", blkt_300->amplitude);
|
||
|
ms_log (0, " input signal channel: %.3s", blkt_300->input_channel);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_300->reserved);
|
||
|
ms_log (0, " reference amplitude: %u\n", blkt_300->reference_amplitude);
|
||
|
ms_log (0, " coupling: %.12s\n", blkt_300->coupling);
|
||
|
ms_log (0, " rolloff: %.12s\n", blkt_300->rolloff);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 310 )
|
||
|
{
|
||
|
struct blkt_310_s *blkt_310 = (struct blkt_310_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_btime2seedtimestr (&blkt_310->time, time);
|
||
|
ms_log (0, " calibration start time: %s\n", time);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_310->reserved1);
|
||
|
|
||
|
b = blkt_310->flags;
|
||
|
ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
|
||
|
if ( b & 0x10 ) ms_log (0, " [Bit 4] Peak-to-peak amplitude\n");
|
||
|
if ( b & 0x20 ) ms_log (0, " [Bit 5] Zero-to-peak amplitude\n");
|
||
|
if ( b & 0x40 ) ms_log (0, " [Bit 6] RMS amplitude\n");
|
||
|
|
||
|
ms_log (0, " calibration duration: %u\n", blkt_310->duration);
|
||
|
ms_log (0, " signal period: %g\n", blkt_310->period);
|
||
|
ms_log (0, " signal amplitude: %g\n", blkt_310->amplitude);
|
||
|
ms_log (0, " input signal channel: %.3s", blkt_310->input_channel);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_310->reserved2);
|
||
|
ms_log (0, " reference amplitude: %u\n", blkt_310->reference_amplitude);
|
||
|
ms_log (0, " coupling: %.12s\n", blkt_310->coupling);
|
||
|
ms_log (0, " rolloff: %.12s\n", blkt_310->rolloff);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 320 )
|
||
|
{
|
||
|
struct blkt_320_s *blkt_320 = (struct blkt_320_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_btime2seedtimestr (&blkt_320->time, time);
|
||
|
ms_log (0, " calibration start time: %s\n", time);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_320->reserved1);
|
||
|
|
||
|
b = blkt_320->flags;
|
||
|
ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
|
||
|
if ( b & 0x10 ) ms_log (0, " [Bit 4] Random amplitudes\n");
|
||
|
|
||
|
ms_log (0, " calibration duration: %u\n", blkt_320->duration);
|
||
|
ms_log (0, " peak-to-peak amplitude: %g\n", blkt_320->ptp_amplitude);
|
||
|
ms_log (0, " input signal channel: %.3s", blkt_320->input_channel);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_320->reserved2);
|
||
|
ms_log (0, " reference amplitude: %u\n", blkt_320->reference_amplitude);
|
||
|
ms_log (0, " coupling: %.12s\n", blkt_320->coupling);
|
||
|
ms_log (0, " rolloff: %.12s\n", blkt_320->rolloff);
|
||
|
ms_log (0, " noise type: %.8s\n", blkt_320->noise_type);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 390 )
|
||
|
{
|
||
|
struct blkt_390_s *blkt_390 = (struct blkt_390_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_btime2seedtimestr (&blkt_390->time, time);
|
||
|
ms_log (0, " calibration start time: %s\n", time);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_390->reserved1);
|
||
|
|
||
|
b = blkt_390->flags;
|
||
|
ms_log (0, " calibration flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
if ( b & 0x04 ) ms_log (0, " [Bit 2] Calibration was automatic\n");
|
||
|
if ( b & 0x08 ) ms_log (0, " [Bit 3] Calibration continued from previous record(s)\n");
|
||
|
|
||
|
ms_log (0, " calibration duration: %u\n", blkt_390->duration);
|
||
|
ms_log (0, " signal amplitude: %g\n", blkt_390->amplitude);
|
||
|
ms_log (0, " input signal channel: %.3s", blkt_390->input_channel);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_390->reserved2);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 395 )
|
||
|
{
|
||
|
struct blkt_395_s *blkt_395 = (struct blkt_395_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_btime2seedtimestr (&blkt_395->time, time);
|
||
|
ms_log (0, " calibration end time: %s\n", time);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved bytes (2): %u,%u\n",
|
||
|
blkt_395->reserved[0], blkt_395->reserved[1]);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 400 )
|
||
|
{
|
||
|
struct blkt_400_s *blkt_400 = (struct blkt_400_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " beam azimuth (degrees): %g\n", blkt_400->azimuth);
|
||
|
ms_log (0, " beam slowness (sec/degree): %g\n", blkt_400->slowness);
|
||
|
ms_log (0, " configuration: %u\n", blkt_400->configuration);
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved bytes (2): %u,%u\n",
|
||
|
blkt_400->reserved[0], blkt_400->reserved[1]);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 405 )
|
||
|
{
|
||
|
struct blkt_405_s *blkt_405 = (struct blkt_405_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s, incomplete)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " first delay value: %u\n", blkt_405->delay_values[0]);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 500 )
|
||
|
{
|
||
|
struct blkt_500_s *blkt_500 = (struct blkt_500_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " VCO correction: %g%%\n", blkt_500->vco_correction);
|
||
|
ms_btime2seedtimestr (&blkt_500->time, time);
|
||
|
ms_log (0, " time of exception: %s\n", time);
|
||
|
ms_log (0, " usec: %d\n", blkt_500->usec);
|
||
|
ms_log (0, " reception quality: %u%%\n", blkt_500->reception_qual);
|
||
|
ms_log (0, " exception count: %u\n", blkt_500->exception_count);
|
||
|
ms_log (0, " exception type: %.16s\n", blkt_500->exception_type);
|
||
|
ms_log (0, " clock model: %.32s\n", blkt_500->clock_model);
|
||
|
ms_log (0, " clock status: %.128s\n", blkt_500->clock_status);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 1000 )
|
||
|
{
|
||
|
struct blkt_1000_s *blkt_1000 = (struct blkt_1000_s *) cur_blkt->blktdata;
|
||
|
int recsize;
|
||
|
char order[40];
|
||
|
|
||
|
/* Calculate record size in bytes as 2^(blkt_1000->rec_len) */
|
||
|
recsize = (unsigned int) 1 << blkt_1000->reclen;
|
||
|
|
||
|
/* Big or little endian? */
|
||
|
if (blkt_1000->byteorder == 0)
|
||
|
strncpy (order, "Little endian", sizeof(order)-1);
|
||
|
else if (blkt_1000->byteorder == 1)
|
||
|
strncpy (order, "Big endian", sizeof(order)-1);
|
||
|
else
|
||
|
strncpy (order, "Unknown value", sizeof(order)-1);
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " encoding: %s (val:%u)\n",
|
||
|
(char *) ms_encodingstr (blkt_1000->encoding), blkt_1000->encoding);
|
||
|
ms_log (0, " byte order: %s (val:%u)\n",
|
||
|
order, blkt_1000->byteorder);
|
||
|
ms_log (0, " record length: %d (val:%u)\n",
|
||
|
recsize, blkt_1000->reclen);
|
||
|
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_1000->reserved);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 1001 )
|
||
|
{
|
||
|
struct blkt_1001_s *blkt_1001 = (struct blkt_1001_s *) cur_blkt->blktdata;
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " timing quality: %u%%\n", blkt_1001->timing_qual);
|
||
|
ms_log (0, " micro second: %d\n", blkt_1001->usec);
|
||
|
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " reserved byte: %u\n", blkt_1001->reserved);
|
||
|
|
||
|
ms_log (0, " frame count: %u\n", blkt_1001->framecnt);
|
||
|
}
|
||
|
|
||
|
else if ( cur_blkt->blkt_type == 2000 )
|
||
|
{
|
||
|
struct blkt_2000_s *blkt_2000 = (struct blkt_2000_s *) cur_blkt->blktdata;
|
||
|
char order[40];
|
||
|
|
||
|
/* Big or little endian? */
|
||
|
if (blkt_2000->byteorder == 0)
|
||
|
strncpy (order, "Little endian", sizeof(order)-1);
|
||
|
else if (blkt_2000->byteorder == 1)
|
||
|
strncpy (order, "Big endian", sizeof(order)-1);
|
||
|
else
|
||
|
strncpy (order, "Unknown value", sizeof(order)-1);
|
||
|
|
||
|
ms_log (0, " BLOCKETTE %u: (%s)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
ms_log (0, " blockette length: %u\n", blkt_2000->length);
|
||
|
ms_log (0, " data offset: %u\n", blkt_2000->data_offset);
|
||
|
ms_log (0, " record number: %u\n", blkt_2000->recnum);
|
||
|
ms_log (0, " byte order: %s (val:%u)\n",
|
||
|
order, blkt_2000->byteorder);
|
||
|
b = blkt_2000->flags;
|
||
|
ms_log (0, " data flags: [%u%u%u%u%u%u%u%u] 8 bits\n",
|
||
|
bit(b,0x01), bit(b,0x02), bit(b,0x04), bit(b,0x08),
|
||
|
bit(b,0x10), bit(b,0x20), bit(b,0x40), bit(b,0x80));
|
||
|
|
||
|
if ( details > 1 )
|
||
|
{
|
||
|
if ( b & 0x01 ) ms_log (0, " [Bit 0] 1: Stream oriented\n");
|
||
|
else ms_log (0, " [Bit 0] 0: Record oriented\n");
|
||
|
if ( b & 0x02 ) ms_log (0, " [Bit 1] 1: Blockette 2000s may NOT be packaged\n");
|
||
|
else ms_log (0, " [Bit 1] 0: Blockette 2000s may be packaged\n");
|
||
|
if ( ! (b & 0x04) && ! (b & 0x08) )
|
||
|
ms_log (0, " [Bits 2-3] 00: Complete blockette\n");
|
||
|
else if ( ! (b & 0x04) && (b & 0x08) )
|
||
|
ms_log (0, " [Bits 2-3] 01: First blockette in span\n");
|
||
|
else if ( (b & 0x04) && (b & 0x08) )
|
||
|
ms_log (0, " [Bits 2-3] 11: Continuation blockette in span\n");
|
||
|
else if ( (b & 0x04) && ! (b & 0x08) )
|
||
|
ms_log (0, " [Bits 2-3] 10: Final blockette in span\n");
|
||
|
if ( ! (b & 0x10) && ! (b & 0x20) )
|
||
|
ms_log (0, " [Bits 4-5] 00: Not file oriented\n");
|
||
|
else if ( ! (b & 0x10) && (b & 0x20) )
|
||
|
ms_log (0, " [Bits 4-5] 01: First blockette of file\n");
|
||
|
else if ( (b & 0x10) && ! (b & 0x20) )
|
||
|
ms_log (0, " [Bits 4-5] 10: Continuation of file\n");
|
||
|
else if ( (b & 0x10) && (b & 0x20) )
|
||
|
ms_log (0, " [Bits 4-5] 11: Last blockette of file\n");
|
||
|
}
|
||
|
|
||
|
ms_log (0, " number of headers: %u\n", blkt_2000->numheaders);
|
||
|
|
||
|
/* Crude display of the opaque data headers */
|
||
|
if ( details > 1 )
|
||
|
ms_log (0, " headers: %.*s\n",
|
||
|
(blkt_2000->data_offset - 15), blkt_2000->payload);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
ms_log (0, " BLOCKETTE %u: (%s, not parsed)\n", cur_blkt->blkt_type,
|
||
|
ms_blktdesc(cur_blkt->blkt_type));
|
||
|
ms_log (0, " next blockette: %u\n", cur_blkt->next_blkt);
|
||
|
}
|
||
|
|
||
|
cur_blkt = cur_blkt->next;
|
||
|
}
|
||
|
}
|
||
|
} /* End of msr_print() */
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
* msr_host_latency:
|
||
|
*
|
||
|
* Calculate the latency based on the host time in UTC accounting for
|
||
|
* the time covered using the number of samples and sample rate; in
|
||
|
* other words, the difference between the host time and the time of
|
||
|
* the last sample in the specified Mini-SEED record.
|
||
|
*
|
||
|
* Double precision is returned, but the true precision is dependent
|
||
|
* on the accuracy of the host system clock among other things.
|
||
|
*
|
||
|
* Returns seconds of latency or 0.0 on error (indistinguishable from
|
||
|
* 0.0 latency).
|
||
|
***************************************************************************/
|
||
|
double
|
||
|
msr_host_latency (MSRecord *msr)
|
||
|
{
|
||
|
double span = 0.0; /* Time covered by the samples */
|
||
|
double epoch; /* Current epoch time */
|
||
|
double latency = 0.0;
|
||
|
time_t tv;
|
||
|
|
||
|
if ( msr == NULL )
|
||
|
return 0.0;
|
||
|
|
||
|
/* Calculate the time covered by the samples */
|
||
|
if ( msr->samprate > 0.0 && msr->samplecnt > 0 )
|
||
|
span = (1.0 / msr->samprate) * (msr->samplecnt - 1);
|
||
|
|
||
|
/* Grab UTC time according to the system clock */
|
||
|
epoch = (double) time(&tv);
|
||
|
|
||
|
/* Now calculate the latency */
|
||
|
latency = epoch - ((double) msr->starttime / HPTMODULUS) - span;
|
||
|
|
||
|
return latency;
|
||
|
} /* End of msr_host_latency() */
|