/*************************************************************************** * ms_parse_raw: * * Parse and verify a SEED data record header (fixed section and * blockettes) at the lowest level, printing error messages for * invalid header values and optionally print raw header values. The * memory at 'record' is assumed to be a Mini-SEED record. Not every * possible test is performed, common errors and those causing * libmseed parsing to fail should be detected. * * The 'details' argument is interpreted as follows: * * details: * 0 = only print error messages for invalid header fields * 1 = print basic fields in addition to invalid field errors * 2 = print all fields in addition to invalid field errors * * The 'swapflag' argument is interpreted as follows: * * swapflag: * 1 = swap multibyte quantities * 0 = do no swapping * -1 = autodetect byte order using year test, swap if needed * * Any byte swapping performed by this routine is applied directly to * the memory reference by the record pointer. * * This routine is primarily intended to diagnose invalid Mini-SEED headers. * * Returns 0 when no errors were detected or a positive count of * errors detected. ***************************************************************************/ int ms_parse_raw ( char *record, int maxreclen, flag details, flag swapflag ) { struct fsdh_s *fsdh; double nomsamprate; char srcname[50]; char *X; char b; int retval = 0; int b1000encoding = -1; int b1000reclen = -1; int endofblockettes = -1; int idx; if ( ! record ) return 1; /* Generate a source name string */ srcname[0] = '\0'; ms_recsrcname (record, srcname, 1); fsdh = (struct fsdh_s *) record; /* Check to see if byte swapping is needed by testing the year */ if ( swapflag == -1 && ((fsdh->start_time.year < 1900) || (fsdh->start_time.year > 2050)) ) swapflag = 1; else swapflag = 0; if ( details > 1 ) { if ( swapflag == 1 ) ms_log (0, "Swapping multi-byte quantities in header\n"); else ms_log (0, "Not swapping multi-byte quantities in header\n"); } /* Swap byte order */ if ( swapflag ) { MS_SWAPBTIME (&fsdh->start_time); ms_gswap2a (&fsdh->numsamples); ms_gswap2a (&fsdh->samprate_fact); ms_gswap2a (&fsdh->samprate_mult); ms_gswap4a (&fsdh->time_correct); ms_gswap2a (&fsdh->data_offset); ms_gswap2a (&fsdh->blockette_offset); } /* Validate fixed section header fields */ X = record; /* Pointer of convenience */ /* Check record sequence number, 6 ASCII digits */ if ( ! isdigit((unsigned char) *(X)) || ! isdigit ((unsigned char) *(X+1)) || ! isdigit((unsigned char) *(X+2)) || ! isdigit ((unsigned char) *(X+3)) || ! isdigit((unsigned char) *(X+4)) || ! isdigit ((unsigned char) *(X+5)) ) { ms_log (2, "%s: Invalid sequence number: '%c%c%c%c%c%c'\n", srcname, X, X+1, X+2, X+3, X+4, X+5); retval++; } /* Check header/quality indicator */ if ( ! MS_ISDATAINDICATOR(*(X+6)) ) { ms_log (2, "%s: Invalid header indicator (DRQM): '%c'\n", srcname, X+6); retval++; } /* Check reserved byte, space or NULL */ if ( ! (*(X+7) == ' ' || *(X+7) == '\0') ) { ms_log (2, "%s: Invalid fixed section reserved byte (Space): '%c'\n", srcname, X+7); retval++; } /* Check station code, 5 alphanumerics or spaces */ if ( ! (isalnum((unsigned char) *(X+8)) || *(X+8) == ' ') || ! (isalnum((unsigned char) *(X+9)) || *(X+9) == ' ') || ! (isalnum((unsigned char) *(X+10)) || *(X+10) == ' ') || ! (isalnum((unsigned char) *(X+11)) || *(X+11) == ' ') || ! (isalnum((unsigned char) *(X+12)) || *(X+12) == ' ') ) { ms_log (2, "%s: Invalid station code: '%c%c%c%c%c'\n", srcname, X+8, X+9, X+10, X+11, X+12); retval++; } /* Check location ID, 2 alphanumerics or spaces */ if ( ! (isalnum((unsigned char) *(X+13)) || *(X+13) == ' ') || ! (isalnum((unsigned char) *(X+14)) || *(X+14) == ' ') ) { ms_log (2, "%s: Invalid location ID: '%c%c'\n", srcname, X+13, X+14); retval++; } /* Check channel codes, 3 alphanumerics or spaces */ if ( ! (isalnum((unsigned char) *(X+15)) || *(X+15) == ' ') || ! (isalnum((unsigned char) *(X+16)) || *(X+16) == ' ') || ! (isalnum((unsigned char) *(X+17)) || *(X+17) == ' ') ) { ms_log (2, "%s: Invalid channel codes: '%c%c%c'\n", srcname, X+15, X+16, X+17); retval++; } /* Check network code, 2 alphanumerics or spaces */ if ( ! (isalnum((unsigned char) *(X+18)) || *(X+18) == ' ') || ! (isalnum((unsigned char) *(X+19)) || *(X+19) == ' ') ) { ms_log (2, "%s: Invalid network code: '%c%c'\n", srcname, X+18, X+19); retval++; } /* Check start time fields */ if ( fsdh->start_time.year < 1920 || fsdh->start_time.year > 2050 ) { ms_log (2, "%s: Unlikely start year (1920-2050): '%d'\n", srcname, fsdh->start_time.year); retval++; } if ( fsdh->start_time.day < 1 || fsdh->start_time.day > 366 ) { ms_log (2, "%s: Invalid start day (1-366): '%d'\n", srcname, fsdh->start_time.day); retval++; } if ( fsdh->start_time.hour > 23 ) { ms_log (2, "%s: Invalid start hour (0-23): '%d'\n", srcname, fsdh->start_time.hour); retval++; } if ( fsdh->start_time.min > 59 ) { ms_log (2, "%s: Invalid start minute (0-59): '%d'\n", srcname, fsdh->start_time.min); retval++; } if ( fsdh->start_time.sec > 60 ) { ms_log (2, "%s: Invalid start second (0-60): '%d'\n", srcname, fsdh->start_time.sec); retval++; } if ( fsdh->start_time.fract > 9999 ) { ms_log (2, "%s: Invalid start fractional seconds (0-9999): '%d'\n", srcname, fsdh->start_time.fract); retval++; } /* Check number of samples, max samples in 4096-byte Steim-2 encoded record: 6601 */ if ( fsdh->numsamples > 20000 ) { ms_log (2, "%s: Unlikely number of samples (>20000): '%d'\n", srcname, fsdh->numsamples); retval++; } /* Sanity check that there is space for blockettes when both data and blockettes are present */ if ( fsdh->numsamples > 0 && fsdh->numblockettes > 0 && fsdh->data_offset <= fsdh->blockette_offset ) { ms_log (2, "%s: No space for %d blockettes, data offset: %d, blockette offset: %d\n", srcname, fsdh->numblockettes, fsdh->data_offset, fsdh->blockette_offset); retval++; } /* Print raw header details */ if ( details >= 1 ) { /* Determine nominal sample rate */ nomsamprate = ms_nomsamprate (fsdh->samprate_fact, fsdh->samprate_mult); /* Print header values */ ms_log (0, "RECORD -- %s\n", srcname); ms_log (0, " sequence number: '%c%c%c%c%c%c'\n", fsdh->sequence_number[0], fsdh->sequence_number[1], fsdh->sequence_number[2], fsdh->sequence_number[3], fsdh->sequence_number[4], fsdh->sequence_number[5]); ms_log (0, " data quality indicator: '%c'\n", fsdh->dataquality); if ( details > 0 ) ms_log (0, " reserved: '%c'\n", fsdh->reserved); ms_log (0, " station code: '%c%c%c%c%c'\n", fsdh->station[0], fsdh->station[1], fsdh->station[2], fsdh->station[3], fsdh->station[4]); ms_log (0, " location ID: '%c%c'\n", fsdh->location[0], fsdh->location[1]); ms_log (0, " channel codes: '%c%c%c'\n", fsdh->channel[0], fsdh->channel[1], fsdh->channel[2]); ms_log (0, " network code: '%c%c'\n", fsdh->network[0], fsdh->network[1]); ms_log (0, " start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", fsdh->start_time.year, fsdh->start_time.day, fsdh->start_time.hour, fsdh->start_time.min, fsdh->start_time.sec, fsdh->start_time.fract, fsdh->start_time.unused); ms_log (0, " number of samples: %d\n", fsdh->numsamples); ms_log (0, " sample rate factor: %d (%.10g samples per second)\n", fsdh->samprate_fact, nomsamprate); ms_log (0, " sample rate multiplier: %d\n", fsdh->samprate_mult); /* Print flag details if requested */ if ( details > 1 ) { /* Activity flags */ b = 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 = 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 = 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", fsdh->numblockettes); ms_log (0, " time correction: %ld\n", (long int) fsdh->time_correct); ms_log (0, " data offset: %d\n", fsdh->data_offset); ms_log (0, " first blockette offset: %d\n", fsdh->blockette_offset); } /* Done printing raw header details */ /* Validate and report information in the blockette chain */ if ( fsdh->blockette_offset > 46 && fsdh->blockette_offset < maxreclen ) { int blkt_offset = fsdh->blockette_offset; int blkt_count = 0; int blkt_length; uint16_t blkt_type; uint16_t next_blkt; char *blkt_desc; /* Traverse blockette chain */ while ( blkt_offset != 0 && blkt_offset < maxreclen ) { /* Every blockette has a similar 4 byte header: type and next */ memcpy (&blkt_type, record + blkt_offset, 2); memcpy (&next_blkt, record + blkt_offset+2, 2); if ( swapflag ) { ms_gswap2 (&blkt_type); ms_gswap2 (&next_blkt); } /* Print common header fields */ if ( details >= 1 ) { blkt_desc = ms_blktdesc(blkt_type); ms_log (0, " BLOCKETTE %u: (%s)\n", blkt_type, (blkt_desc) ? blkt_desc : "Unknown"); ms_log (0, " next blockette: %u\n", next_blkt); } blkt_length = ms_blktlen (blkt_type, record + blkt_offset, swapflag); if ( blkt_length == 0 ) { ms_log (2, "%s: Unknown blockette length for type %d\n", srcname, blkt_type); retval++; } /* Track end of blockette chain */ endofblockettes = blkt_offset + blkt_length - 1; /* Sanity check that the blockette is contained in the record */ if ( endofblockettes > maxreclen ) { ms_log (2, "%s: Blockette type %d at offset %d with length %d does not fix in record (%d)\n", srcname, blkt_type, blkt_offset, blkt_length, maxreclen); retval++; break; } if ( blkt_type == 100 ) { struct blkt_100_s *blkt_100 = (struct blkt_100_s *) (record + blkt_offset + 4); if ( swapflag ) ms_gswap4 (&blkt_100->samprate); if ( details >= 1 ) { 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 ( blkt_type == 200 ) { struct blkt_200_s *blkt_200 = (struct blkt_200_s *) (record + blkt_offset + 4); if ( swapflag ) { ms_gswap4 (&blkt_200->amplitude); ms_gswap4 (&blkt_200->period); ms_gswap4 (&blkt_200->background_estimate); MS_SWAPBTIME (&blkt_200->time); } if ( details >= 1 ) { 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_log (0, " signal onset time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_200->time.year, blkt_200->time.day, blkt_200->time.hour, blkt_200->time.min, blkt_200->time.sec, blkt_200->time.fract, blkt_200->time.unused); ms_log (0, " detector name: %.24s\n", blkt_200->detector); } } else if ( blkt_type == 201 ) { struct blkt_201_s *blkt_201 = (struct blkt_201_s *) (record + blkt_offset + 4); if ( swapflag ) { ms_gswap4 (&blkt_201->amplitude); ms_gswap4 (&blkt_201->period); ms_gswap4 (&blkt_201->background_estimate); MS_SWAPBTIME (&blkt_201->time); } if ( details >= 1 ) { 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_log (0, " signal onset time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_201->time.year, blkt_201->time.day, blkt_201->time.hour, blkt_201->time.min, blkt_201->time.sec, blkt_201->time.fract, blkt_201->time.unused); 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 ( blkt_type == 300 ) { struct blkt_300_s *blkt_300 = (struct blkt_300_s *) (record + blkt_offset + 4); if ( swapflag ) { MS_SWAPBTIME (&blkt_300->time); ms_gswap4 (&blkt_300->step_duration); ms_gswap4 (&blkt_300->interval_duration); ms_gswap4 (&blkt_300->amplitude); ms_gswap4 (&blkt_300->reference_amplitude); } if ( details >= 1 ) { ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_300->time.year, blkt_300->time.day, blkt_300->time.hour, blkt_300->time.min, blkt_300->time.sec, blkt_300->time.fract, blkt_300->time.unused); 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 ( blkt_type == 310 ) { struct blkt_310_s *blkt_310 = (struct blkt_310_s *) (record + blkt_offset + 4); if ( swapflag ) { MS_SWAPBTIME (&blkt_310->time); ms_gswap4 (&blkt_310->duration); ms_gswap4 (&blkt_310->period); ms_gswap4 (&blkt_310->amplitude); ms_gswap4 (&blkt_310->reference_amplitude); } if ( details >= 1 ) { ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_310->time.year, blkt_310->time.day, blkt_310->time.hour, blkt_310->time.min, blkt_310->time.sec, blkt_310->time.fract, blkt_310->time.unused); 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 ( blkt_type == 320 ) { struct blkt_320_s *blkt_320 = (struct blkt_320_s *) (record + blkt_offset + 4); if ( swapflag ) { MS_SWAPBTIME (&blkt_320->time); ms_gswap4 (&blkt_320->duration); ms_gswap4 (&blkt_320->ptp_amplitude); ms_gswap4 (&blkt_320->reference_amplitude); } if ( details >= 1 ) { ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_320->time.year, blkt_320->time.day, blkt_320->time.hour, blkt_320->time.min, blkt_320->time.sec, blkt_320->time.fract, blkt_320->time.unused); 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 ( blkt_type == 390 ) { struct blkt_390_s *blkt_390 = (struct blkt_390_s *) (record + blkt_offset + 4); if ( swapflag ) { MS_SWAPBTIME (&blkt_390->time); ms_gswap4 (&blkt_390->duration); ms_gswap4 (&blkt_390->amplitude); } if ( details >= 1 ) { ms_log (0, " calibration start time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_390->time.year, blkt_390->time.day, blkt_390->time.hour, blkt_390->time.min, blkt_390->time.sec, blkt_390->time.fract, blkt_390->time.unused); 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 ( blkt_type == 395 ) { struct blkt_395_s *blkt_395 = (struct blkt_395_s *) (record + blkt_offset + 4); if ( swapflag ) MS_SWAPBTIME (&blkt_395->time); if ( details >= 1 ) { ms_log (0, " calibration end time: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_395->time.year, blkt_395->time.day, blkt_395->time.hour, blkt_395->time.min, blkt_395->time.sec, blkt_395->time.fract, blkt_395->time.unused); if ( details > 1 ) ms_log (0, " reserved bytes (2): %u,%u\n", blkt_395->reserved[0], blkt_395->reserved[1]); } } else if ( blkt_type == 400 ) { struct blkt_400_s *blkt_400 = (struct blkt_400_s *) (record + blkt_offset + 4); if ( swapflag ) { ms_gswap4 (&blkt_400->azimuth); ms_gswap4 (&blkt_400->slowness); ms_gswap4 (&blkt_400->configuration); } if ( details >= 1 ) { 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 ( blkt_type == 405 ) { struct blkt_405_s *blkt_405 = (struct blkt_405_s *) (record + blkt_offset + 4); uint16_t firstvalue = blkt_405->delay_values[0]; /* Work on a private copy */ if ( swapflag ) ms_gswap2 (&firstvalue); if ( details >= 1 ) ms_log (0, " first delay value: %u\n", firstvalue); } else if ( blkt_type == 500 ) { struct blkt_500_s *blkt_500 = (struct blkt_500_s *) (record + blkt_offset + 4); if ( swapflag ) { ms_gswap4 (&blkt_500->vco_correction); MS_SWAPBTIME (&blkt_500->time); ms_gswap4 (&blkt_500->exception_count); } if ( details >= 1 ) { ms_log (0, " VCO correction: %g%%\n", blkt_500->vco_correction); ms_log (0, " time of exception: %d,%d,%d:%d:%d.%04d (unused: %d)\n", blkt_500->time.year, blkt_500->time.day, blkt_500->time.hour, blkt_500->time.min, blkt_500->time.sec, blkt_500->time.fract, blkt_500->time.unused); 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 ( blkt_type == 1000 ) { struct blkt_1000_s *blkt_1000 = (struct blkt_1000_s *) (record + blkt_offset + 4); char order[40]; /* Calculate record size in bytes as 2^(blkt_1000->rec_len) */ b1000reclen = (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); if ( details >= 1 ) { 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", b1000reclen, blkt_1000->reclen); if ( details > 1 ) ms_log (0, " reserved byte: %u\n", blkt_1000->reserved); } /* Save encoding format */ b1000encoding = blkt_1000->encoding; /* Sanity check encoding format */ if ( ! (b1000encoding >= 0 && b1000encoding <= 5) && ! (b1000encoding >= 10 && b1000encoding <= 19) && ! (b1000encoding >= 30 && b1000encoding <= 33) ) { ms_log (2, "%s: Blockette 1000 encoding format invalid (0-5,10-19,30-33): %d\n", srcname, b1000encoding); retval++; } /* Sanity check byte order flag */ if ( blkt_1000->byteorder != 0 && blkt_1000->byteorder != 1 ) { ms_log (2, "%s: Blockette 1000 byte order flag invalid (0 or 1): %d\n", srcname, blkt_1000->byteorder); retval++; } } else if ( blkt_type == 1001 ) { struct blkt_1001_s *blkt_1001 = (struct blkt_1001_s *) (record + blkt_offset + 4); if ( details >= 1 ) { 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 ( blkt_type == 2000 ) { struct blkt_2000_s *blkt_2000 = (struct blkt_2000_s *) (record + blkt_offset + 4); char order[40]; if ( swapflag ) { ms_gswap2 (&blkt_2000->length); ms_gswap2 (&blkt_2000->data_offset); ms_gswap4 (&blkt_2000->recnum); } /* 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); if ( details >= 1 ) { 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 (2, "%s: Unrecognized blockette type: %d\n", srcname, blkt_type); retval++; } /* Sanity check the next blockette offset */ if ( next_blkt && next_blkt <= endofblockettes ) { ms_log (2, "%s: Next blockette offset (%d) is within current blockette ending at byte %d\n", srcname, next_blkt, endofblockettes); blkt_offset = 0; } else { blkt_offset = next_blkt; } blkt_count++; } /* End of looping through blockettes */ /* Check that the blockette offset is within the maximum record size */ if ( blkt_offset > maxreclen ) { ms_log (2, "%s: Blockette offset (%d) beyond maximum record length (%d)\n", srcname, blkt_offset, maxreclen); retval++; } /* Check that the data and blockette offsets are within the record */ if ( b1000reclen && fsdh->data_offset > b1000reclen ) { ms_log (2, "%s: Data offset (%d) beyond record length (%d)\n", srcname, fsdh->data_offset, b1000reclen); retval++; } if ( b1000reclen && fsdh->blockette_offset > b1000reclen ) { ms_log (2, "%s: Blockette offset (%d) beyond record length (%d)\n", srcname, fsdh->blockette_offset, b1000reclen); retval++; } /* Check that the data offset is beyond the end of the blockettes */ if ( fsdh->numsamples && fsdh->data_offset <= endofblockettes ) { ms_log (2, "%s: Data offset (%d) is within blockette chain (end of blockettes: %d)\n", srcname, fsdh->data_offset, endofblockettes); retval++; } /* Check that the correct number of blockettes were parsed */ if ( fsdh->numblockettes != blkt_count ) { ms_log (2, "%s: Specified number of blockettes (%d) not equal to those parsed (%d)\n", srcname, fsdh->numblockettes, blkt_count); retval++; } } return retval; } /* End of ms_parse_raw() */
/************************************************************************ * msr_decode_steim2: * * Decode Steim2 encoded miniSEED data and place in supplied buffer * as 32-bit integers. * * Return number of samples in output buffer on success, -1 on error. ************************************************************************/ int msr_decode_steim2 (int32_t *input, int inputlength, int samplecount, int32_t *output, int outputlength, char *srcname, int swapflag) { int32_t *outputptr = output; /* Pointer to next output sample location */ uint32_t frame[16]; /* Frame, 16 x 32-bit quantities = 64 bytes */ int32_t X0 = 0; /* Forward integration constant, aka first sample */ int32_t Xn = 0; /* Reverse integration constant, aka last sample */ int32_t diff[7]; int32_t semask; int maxframes = inputlength / 64; int frameidx; int startnibble; int nibble; int widx; int diffcount; int dnib; int idx; union dword { int8_t d8[4]; int32_t d32; } * word; if (inputlength <= 0) return 0; if (!input || !output || outputlength <= 0 || maxframes <= 0) return -1; if (decodedebug) ms_log (1, "Decoding %d Steim2 frames, swapflag: %d, srcname: %s\n", maxframes, swapflag, (srcname) ? srcname : ""); for (frameidx = 0; frameidx < maxframes && samplecount > 0; frameidx++) { /* Copy frame, each is 16x32-bit quantities = 64 bytes */ memcpy (frame, input + (16 * frameidx), 64); /* Save forward integration constant (X0) and reverse integration constant (Xn) and set the starting nibble index depending on frame. */ if (frameidx == 0) { if (swapflag) { ms_gswap4a (&frame[1]); ms_gswap4a (&frame[2]); } X0 = frame[1]; Xn = frame[2]; startnibble = 3; /* First frame: skip nibbles, X0, and Xn */ if (decodedebug) ms_log (1, "Frame %d: X0=%d Xn=%d\n", frameidx, X0, Xn); } else { startnibble = 1; /* Subsequent frames: skip nibbles */ if (decodedebug) ms_log (1, "Frame %d\n", frameidx); } /* Swap 32-bit word containing the nibbles */ if (swapflag) ms_gswap4a (&frame[0]); /* Decode each 32-bit word according to nibble */ for (widx = startnibble; widx < 16 && samplecount > 0; widx++) { /* W0: the first 32-bit quantity contains 16 x 2-bit nibbles */ nibble = EXTRACTBITRANGE (frame[0], (30 - (2 * widx)), 2); diffcount = 0; switch (nibble) { case 0: /* nibble=00: Special flag, no differences */ if (decodedebug) ms_log (1, " W%02d: 00=special\n", widx); break; case 1: /* nibble=01: Four 1-byte differences */ diffcount = 4; word = (union dword *)&frame[widx]; for (idx = 0; idx < diffcount; idx++) { diff[idx] = word->d8[idx]; } if (decodedebug) ms_log (1, " W%02d: 01=4x8b %d %d %d %d\n", widx, diff[0], diff[1], diff[2], diff[3]); break; case 2: /* nibble=10: Must consult dnib, the high order two bits */ if (swapflag) ms_gswap4a (&frame[widx]); dnib = EXTRACTBITRANGE (frame[widx], 30, 2); switch (dnib) { case 0: /* nibble=10, dnib=00: Error, undefined value */ ms_log (2, "%s: Impossible Steim2 dnib=00 for nibble=10\n", srcname); return -1; break; case 1: /* nibble=10, dnib=01: One 30-bit difference */ diffcount = 1; semask = 1U << (30 - 1); /* Sign extension from bit 30 */ diff[0] = EXTRACTBITRANGE (frame[widx], 0, 30); diff[0] = (diff[0] ^ semask) - semask; if (decodedebug) ms_log (1, " W%02d: 10,01=1x30b %d\n", widx, diff[0]); break; case 2: /* nibble=10, dnib=10: Two 15-bit differences */ diffcount = 2; semask = 1U << (15 - 1); /* Sign extension from bit 15 */ for (idx = 0; idx < diffcount; idx++) { diff[idx] = EXTRACTBITRANGE (frame[widx], (15 - idx * 15), 15); diff[idx] = (diff[idx] ^ semask) - semask; } if (decodedebug) ms_log (1, " W%02d: 10,10=2x15b %d %d\n", widx, diff[0], diff[1]); break; case 3: /* nibble=10, dnib=11: Three 10-bit differences */ diffcount = 3; semask = 1U << (10 - 1); /* Sign extension from bit 10 */ for (idx = 0; idx < diffcount; idx++) { diff[idx] = EXTRACTBITRANGE (frame[widx], (20 - idx * 10), 10); diff[idx] = (diff[idx] ^ semask) - semask; } if (decodedebug) ms_log (1, " W%02d: 10,11=3x10b %d %d %d\n", widx, diff[0], diff[1], diff[2]); break; } break; case 3: /* nibble=11: Must consult dnib, the high order two bits */ if (swapflag) ms_gswap4a (&frame[widx]); dnib = EXTRACTBITRANGE (frame[widx], 30, 2); switch (dnib) { case 0: /* nibble=11, dnib=00: Five 6-bit differences */ diffcount = 5; semask = 1U << (6 - 1); /* Sign extension from bit 6 */ for (idx = 0; idx < diffcount; idx++) { diff[idx] = EXTRACTBITRANGE (frame[widx], (24 - idx * 6), 6); diff[idx] = (diff[idx] ^ semask) - semask; } if (decodedebug) ms_log (1, " W%02d: 11,00=5x6b %d %d %d %d %d\n", widx, diff[0], diff[1], diff[2], diff[3], diff[4]); break; case 1: /* nibble=11, dnib=01: Six 5-bit differences */ diffcount = 6; semask = 1U << (5 - 1); /* Sign extension from bit 5 */ for (idx = 0; idx < diffcount; idx++) { diff[idx] = EXTRACTBITRANGE (frame[widx], (25 - idx * 5), 5); diff[idx] = (diff[idx] ^ semask) - semask; } if (decodedebug) ms_log (1, " W%02d: 11,01=6x5b %d %d %d %d %d %d\n", widx, diff[0], diff[1], diff[2], diff[3], diff[4], diff[5]); break; case 2: /* nibble=11, dnib=10: Seven 4-bit differences */ diffcount = 7; semask = 1U << (4 - 1); /* Sign extension from bit 4 */ for (idx = 0; idx < diffcount; idx++) { diff[idx] = EXTRACTBITRANGE (frame[widx], (24 - idx * 4), 4); diff[idx] = (diff[idx] ^ semask) - semask; } if (decodedebug) ms_log (1, " W%02d: 11,10=7x4b %d %d %d %d %d %d %d\n", widx, diff[0], diff[1], diff[2], diff[3], diff[4], diff[5], diff[6]); break; case 3: /* nibble=11, dnib=11: Error, undefined value */ ms_log (2, "%s: Impossible Steim2 dnib=11 for nibble=11\n", srcname); return -1; break; } break; } /* Done with decoding 32-bit word based on nibble */ /* Apply differences to calculate output samples */ if (diffcount > 0) { for (idx = 0; idx < diffcount && samplecount > 0; idx++, outputptr++) { if (outputptr == output) /* Ignore first difference, instead store X0 */ *outputptr = X0; else /* Otherwise store difference from previous sample */ *outputptr = *(outputptr - 1) + diff[idx]; samplecount--; } } } /* Done looping over nibbles and 32-bit words */ } /* Done looping over frames */ /* Check data integrity by comparing last sample to Xn (reverse integration constant) */ if (outputptr != output && *(outputptr - 1) != Xn) { ms_log (1, "%s: Warning: Data integrity check for Steim2 failed, Last sample=%d, Xn=%d\n", srcname, *(outputptr - 1), Xn); } return (outputptr - output); } /* End of msr_decode_steim2() */
/*************************************************************************** * msr_pack_header_raw: * * Pack data header/blockettes into the specified SEED data record. * * Returns the header length in bytes on success or -1 on error. ***************************************************************************/ static int msr_pack_header_raw ( MSRecord *msr, char *rawrec, int maxheaderlen, flag swapflag, flag normalize, struct blkt_1001_s **blkt1001, flag verbose ) { struct blkt_link_s *cur_blkt; struct fsdh_s *fsdh; int16_t offset; int blktcnt = 0; int nextoffset; if ( ! msr || ! rawrec ) return -1; /* Make sure a fixed section of data header is available */ if ( ! msr->fsdh ) { msr->fsdh = (struct fsdh_s *) calloc (1, sizeof (struct fsdh_s)); if ( msr->fsdh == NULL ) { ms_log (2, "msr_pack_header_raw(%s): Cannot allocate memory\n", PACK_SRCNAME); return -1; } } /* Update the SEED structures associated with the MSRecord */ if ( normalize ) if ( msr_normalize_header (msr, verbose) < 0 ) { ms_log (2, "msr_pack_header_raw(%s): error normalizing header values\n", PACK_SRCNAME); return -1; } if ( verbose > 2 ) ms_log (1, "%s: Packing fixed section of data header\n", PACK_SRCNAME); if ( maxheaderlen > msr->reclen ) { ms_log (2, "msr_pack_header_raw(%s): maxheaderlen of %d is beyond record length of %d\n", PACK_SRCNAME, maxheaderlen, msr->reclen); return -1; } if ( maxheaderlen < sizeof(struct fsdh_s) ) { ms_log (2, "msr_pack_header_raw(%s): maxheaderlen of %d is too small, must be >= %d\n", PACK_SRCNAME, maxheaderlen, sizeof(struct fsdh_s)); return -1; } fsdh = (struct fsdh_s *) rawrec; offset = 48; /* Roll-over sequence number if necessary */ if ( msr->sequence_number > 999999 ) msr->sequence_number = 1; /* Copy FSDH associated with the MSRecord into the record */ memcpy (fsdh, msr->fsdh, sizeof(struct fsdh_s)); /* Swap byte order? */ if ( swapflag ) { MS_SWAPBTIME (&fsdh->start_time); ms_gswap2 (&fsdh->numsamples); ms_gswap2 (&fsdh->samprate_fact); ms_gswap2 (&fsdh->samprate_mult); ms_gswap4 (&fsdh->time_correct); ms_gswap2 (&fsdh->data_offset); ms_gswap2 (&fsdh->blockette_offset); } /* Traverse blockette chain and pack blockettes at 'offset' */ cur_blkt = msr->blkts; while ( cur_blkt && offset < maxheaderlen ) { /* Check that the blockette fits */ if ( (offset + 4 + cur_blkt->blktdatalen) > maxheaderlen ) { ms_log (2, "msr_pack_header_raw(%s): header exceeds maxheaderlen of %d\n", PACK_SRCNAME, maxheaderlen); break; } /* Pack blockette type and leave space for next offset */ memcpy (rawrec + offset, &cur_blkt->blkt_type, 2); if ( swapflag ) ms_gswap2 (rawrec + offset); nextoffset = offset + 2; offset += 4; if ( cur_blkt->blkt_type == 100 ) { struct blkt_100_s *blkt_100 = (struct blkt_100_s *) (rawrec + offset); memcpy (blkt_100, cur_blkt->blktdata, sizeof (struct blkt_100_s)); offset += sizeof (struct blkt_100_s); if ( swapflag ) { ms_gswap4 (&blkt_100->samprate); } } else if ( cur_blkt->blkt_type == 200 ) { struct blkt_200_s *blkt_200 = (struct blkt_200_s *) (rawrec + offset); memcpy (blkt_200, cur_blkt->blktdata, sizeof (struct blkt_200_s)); offset += sizeof (struct blkt_200_s); if ( swapflag ) { ms_gswap4 (&blkt_200->amplitude); ms_gswap4 (&blkt_200->period); ms_gswap4 (&blkt_200->background_estimate); MS_SWAPBTIME (&blkt_200->time); } } else if ( cur_blkt->blkt_type == 201 ) { struct blkt_201_s *blkt_201 = (struct blkt_201_s *) (rawrec + offset); memcpy (blkt_201, cur_blkt->blktdata, sizeof (struct blkt_201_s)); offset += sizeof (struct blkt_201_s); if ( swapflag ) { ms_gswap4 (&blkt_201->amplitude); ms_gswap4 (&blkt_201->period); ms_gswap4 (&blkt_201->background_estimate); MS_SWAPBTIME (&blkt_201->time); } } else if ( cur_blkt->blkt_type == 300 ) { struct blkt_300_s *blkt_300 = (struct blkt_300_s *) (rawrec + offset); memcpy (blkt_300, cur_blkt->blktdata, sizeof (struct blkt_300_s)); offset += sizeof (struct blkt_300_s); if ( swapflag ) { MS_SWAPBTIME (&blkt_300->time); ms_gswap4 (&blkt_300->step_duration); ms_gswap4 (&blkt_300->interval_duration); ms_gswap4 (&blkt_300->amplitude); ms_gswap4 (&blkt_300->reference_amplitude); } } else if ( cur_blkt->blkt_type == 310 ) { struct blkt_310_s *blkt_310 = (struct blkt_310_s *) (rawrec + offset); memcpy (blkt_310, cur_blkt->blktdata, sizeof (struct blkt_310_s)); offset += sizeof (struct blkt_310_s); if ( swapflag ) { MS_SWAPBTIME (&blkt_310->time); ms_gswap4 (&blkt_310->duration); ms_gswap4 (&blkt_310->period); ms_gswap4 (&blkt_310->amplitude); ms_gswap4 (&blkt_310->reference_amplitude); } } else if ( cur_blkt->blkt_type == 320 ) { struct blkt_320_s *blkt_320 = (struct blkt_320_s *) (rawrec + offset); memcpy (blkt_320, cur_blkt->blktdata, sizeof (struct blkt_320_s)); offset += sizeof (struct blkt_320_s); if ( swapflag ) { MS_SWAPBTIME (&blkt_320->time); ms_gswap4 (&blkt_320->duration); ms_gswap4 (&blkt_320->ptp_amplitude); ms_gswap4 (&blkt_320->reference_amplitude); } } else if ( cur_blkt->blkt_type == 390 ) { struct blkt_390_s *blkt_390 = (struct blkt_390_s *) (rawrec + offset); memcpy (blkt_390, cur_blkt->blktdata, sizeof (struct blkt_390_s)); offset += sizeof (struct blkt_390_s); if ( swapflag ) { MS_SWAPBTIME (&blkt_390->time); ms_gswap4 (&blkt_390->duration); ms_gswap4 (&blkt_390->amplitude); } } else if ( cur_blkt->blkt_type == 395 ) { struct blkt_395_s *blkt_395 = (struct blkt_395_s *) (rawrec + offset); memcpy (blkt_395, cur_blkt->blktdata, sizeof (struct blkt_395_s)); offset += sizeof (struct blkt_395_s); if ( swapflag ) { MS_SWAPBTIME (&blkt_395->time); } } else if ( cur_blkt->blkt_type == 400 ) { struct blkt_400_s *blkt_400 = (struct blkt_400_s *) (rawrec + offset); memcpy (blkt_400, cur_blkt->blktdata, sizeof (struct blkt_400_s)); offset += sizeof (struct blkt_400_s); if ( swapflag ) { ms_gswap4 (&blkt_400->azimuth); ms_gswap4 (&blkt_400->slowness); ms_gswap2 (&blkt_400->configuration); } } else if ( cur_blkt->blkt_type == 405 ) { struct blkt_405_s *blkt_405 = (struct blkt_405_s *) (rawrec + offset); memcpy (blkt_405, cur_blkt->blktdata, sizeof (struct blkt_405_s)); offset += sizeof (struct blkt_405_s); if ( swapflag ) { ms_gswap2 (&blkt_405->delay_values); } if ( verbose > 0 ) { ms_log (1, "msr_pack_header_raw(%s): WARNING Blockette 405 cannot be fully supported\n", PACK_SRCNAME); } } else if ( cur_blkt->blkt_type == 500 ) { struct blkt_500_s *blkt_500 = (struct blkt_500_s *) (rawrec + offset); memcpy (blkt_500, cur_blkt->blktdata, sizeof (struct blkt_500_s)); offset += sizeof (struct blkt_500_s); if ( swapflag ) { ms_gswap4 (&blkt_500->vco_correction); MS_SWAPBTIME (&blkt_500->time); ms_gswap4 (&blkt_500->exception_count); } } else if ( cur_blkt->blkt_type == 1000 ) { struct blkt_1000_s *blkt_1000 = (struct blkt_1000_s *) (rawrec + offset); memcpy (blkt_1000, cur_blkt->blktdata, sizeof (struct blkt_1000_s)); offset += sizeof (struct blkt_1000_s); /* This guarantees that the byte order is in sync with msr_pack() */ if ( packdatabyteorder >= 0 ) blkt_1000->byteorder = packdatabyteorder; } else if ( cur_blkt->blkt_type == 1001 ) { struct blkt_1001_s *blkt_1001 = (struct blkt_1001_s *) (rawrec + offset); memcpy (blkt_1001, cur_blkt->blktdata, sizeof (struct blkt_1001_s)); offset += sizeof (struct blkt_1001_s); /* Track location of Blockette 1001 if requested */ if ( blkt1001 ) *blkt1001 = blkt_1001; } else if ( cur_blkt->blkt_type == 2000 ) { struct blkt_2000_s *blkt_2000 = (struct blkt_2000_s *) (rawrec + offset); memcpy (blkt_2000, cur_blkt->blktdata, cur_blkt->blktdatalen); offset += cur_blkt->blktdatalen; if ( swapflag ) { ms_gswap2 (&blkt_2000->length); ms_gswap2 (&blkt_2000->data_offset); ms_gswap4 (&blkt_2000->recnum); } /* Nothing done to pack the opaque headers and data, they should already be packed into the blockette payload */ } else { memcpy (rawrec + offset, cur_blkt->blktdata, cur_blkt->blktdatalen); offset += cur_blkt->blktdatalen; } /* Pack the offset to the next blockette */ if ( cur_blkt->next ) { memcpy (rawrec + nextoffset, &offset, 2); if ( swapflag ) ms_gswap2 (rawrec + nextoffset); } else { memset (rawrec + nextoffset, 0, 2); } blktcnt++; cur_blkt = cur_blkt->next; } fsdh->numblockettes = blktcnt; if ( verbose > 2 ) ms_log (1, "%s: Packed %d blockettes\n", PACK_SRCNAME, blktcnt); return offset; } /* End of msr_pack_header_raw() */
/************************************************************************ * msr_pack_data: * * Pack Mini-SEED data samples. The input data samples specified as * 'src' will be packed with 'encoding' format and placed in 'dest'. * * If a pointer to a 32-bit integer sample is provided in the * argument 'lastintsample' and 'comphistory' is true the sample * value will be used to seed the difference buffer for Steim1/2 * encoding and provide a compression history. It will also be * updated with the last sample packed in order to be used with a * subsequent call to this routine. * * The number of samples packed will be placed in 'packsamples' and * the number of bytes packed will be placed in 'packbytes'. * * Return 0 on success and a negative number on error. ************************************************************************/ static int msr_pack_data (void *dest, void *src, int maxsamples, int maxdatabytes, int *packsamples, int32_t *lastintsample, flag comphistory, char sampletype, flag encoding, flag swapflag, flag verbose) { int retval; int nframes; int npacked; int32_t *intbuff; int32_t d0; /* Decide if this is a format that we can decode */ switch (encoding) { case DE_ASCII: if ( sampletype != 'a' ) { ms_log (2, "%s: Sample type must be ascii (a) for ASCII encoding not '%c'\n", PACK_SRCNAME, sampletype); return -1; } if ( verbose > 1 ) ms_log (1, "%s: Packing ASCII data\n", PACK_SRCNAME); retval = msr_pack_text (dest, src, maxsamples, maxdatabytes, 1, &npacked, packsamples); break; case DE_INT16: if ( sampletype != 'i' ) { ms_log (2, "%s: Sample type must be integer (i) for integer-16 encoding not '%c'\n", PACK_SRCNAME, sampletype); return -1; } if ( verbose > 1 ) ms_log (1, "%s: Packing INT-16 data samples\n", PACK_SRCNAME); retval = msr_pack_int_16 (dest, src, maxsamples, maxdatabytes, 1, &npacked, packsamples, swapflag); break; case DE_INT32: if ( sampletype != 'i' ) { ms_log (2, "%s: Sample type must be integer (i) for integer-32 encoding not '%c'\n", PACK_SRCNAME, sampletype); return -1; } if ( verbose > 1 ) ms_log (1, "%s: Packing INT-32 data samples\n", PACK_SRCNAME); retval = msr_pack_int_32 (dest, src, maxsamples, maxdatabytes, 1, &npacked, packsamples, swapflag); break; case DE_FLOAT32: if ( sampletype != 'f' ) { ms_log (2, "%s: Sample type must be float (f) for float-32 encoding not '%c'\n", PACK_SRCNAME, sampletype); return -1; } if ( verbose > 1 ) ms_log (1, "%s: Packing FLOAT-32 data samples\n", PACK_SRCNAME); retval = msr_pack_float_32 (dest, src, maxsamples, maxdatabytes, 1, &npacked, packsamples, swapflag); break; case DE_FLOAT64: if ( sampletype != 'd' ) { ms_log (2, "%s: Sample type must be double (d) for float-64 encoding not '%c'\n", PACK_SRCNAME, sampletype); return -1; } if ( verbose > 1 ) ms_log (1, "%s: Packing FLOAT-64 data samples\n", PACK_SRCNAME); retval = msr_pack_float_64 (dest, src, maxsamples, maxdatabytes, 1, &npacked, packsamples, swapflag); break; case DE_STEIM1: if ( sampletype != 'i' ) { ms_log (2, "%s: Sample type must be integer (i) for Steim-1 compression not '%c'\n", PACK_SRCNAME, sampletype); return -1; } intbuff = (int32_t *) src; /* If a previous sample is supplied use it for compression history otherwise cold-start */ d0 = ( lastintsample && comphistory ) ? (intbuff[0] - *lastintsample) : 0; if ( verbose > 1 ) ms_log (1, "%s: Packing Steim-1 data frames\n", PACK_SRCNAME); nframes = maxdatabytes / 64; retval = msr_pack_steim1 (dest, src, d0, maxsamples, nframes, 1, &npacked, packsamples, swapflag); /* If a previous sample is supplied update it with the last sample value */ if ( lastintsample && retval == 0 ) *lastintsample = intbuff[*packsamples-1]; break; case DE_STEIM2: if ( sampletype != 'i' ) { ms_log (2, "%s: Sample type must be integer (i) for Steim-2 compression not '%c'\n", PACK_SRCNAME, sampletype); return -1; } intbuff = (int32_t *) src; /* If a previous sample is supplied use it for compression history otherwise cold-start */ d0 = ( lastintsample && comphistory ) ? (intbuff[0] - *lastintsample) : 0; if ( verbose > 1 ) ms_log (1, "%s: Packing Steim-2 data frames\n", PACK_SRCNAME); nframes = maxdatabytes / 64; retval = msr_pack_steim2 (dest, src, d0, maxsamples, nframes, 1, &npacked, packsamples, swapflag); /* If a previous sample is supplied update it with the last sample value */ if ( lastintsample && retval == 0 ) *lastintsample = intbuff[*packsamples-1]; break; default: ms_log (2, "%s: Unable to pack format %d\n", PACK_SRCNAME, encoding); return -1; } return retval; } /* End of msr_pack_data() */
int main (int argc, char **argv) { struct filelink *flp; MSRecord *msr = 0; MSTraceList *mstl = 0; FILE *bfp = 0; FILE *ofp = 0; int retcode = MS_NOERROR; char envvariable[100]; int dataflag = 0; long long int totalrecs = 0; long long int totalsamps = 0; long long int totalfiles = 0; off_t filepos = 0; char srcname[50]; char stime[30]; /* Set default error message prefix */ ms_loginit (NULL, NULL, NULL, "ERROR: "); /* Process given parameters (command line and parameter file) */ if ( processparam (argc, argv) < 0 ) return 1; /* Setup encoding environment variable if specified, ugly kludge */ if ( encodingstr ) { snprintf (envvariable, sizeof(envvariable), "UNPACK_DATA_FORMAT=%s", encodingstr); if ( putenv (envvariable) ) { ms_log (2, "Cannot set environment variable UNPACK_DATA_FORMAT\n"); return 1; } } /* Open the integer output file if specified */ if ( binfile ) { if ( strcmp (binfile, "-") == 0 ) { bfp = stdout; } else if ( (bfp = fopen (binfile, "wb")) == NULL ) { ms_log (2, "Cannot open binary data output file: %s (%s)\n", binfile, strerror(errno)); return 1; } } /* Open the output file if specified */ if ( outfile ) { if ( strcmp (outfile, "-") == 0 ) { ofp = stdout; } else if ( (ofp = fopen (outfile, "wb")) == NULL ) { ms_log (2, "Cannot open output file: %s (%s)\n", outfile, strerror(errno)); return 1; } } if ( printdata || binfile ) dataflag = 1; if ( tracegapsum || tracegaponly ) mstl = mstl_init (NULL); flp = filelist; while ( flp != 0 ) { if ( verbose >= 2 ) { if ( flp->offset ) ms_log (1, "Processing: %s (starting at byte %lld)\n", flp->filename, flp->offset); else ms_log (1, "Processing: %s\n", flp->filename); } /* Set starting byte offset if supplied as negative file position */ filepos = - flp->offset; /* Loop over the input file */ while ( reccntdown != 0 ) { if ( (retcode = ms_readmsr (&msr, flp->filename, reclen, &filepos, NULL, skipnotdata, 0, verbose)) != MS_NOERROR ) break; /* Check if record matches start/end time criteria */ if ( starttime != HPTERROR || endtime != HPTERROR ) { hptime_t recendtime = msr_endtime (msr); if ( starttime != HPTERROR && (msr->starttime < starttime && ! (msr->starttime <= starttime && recendtime >= starttime)) ) { if ( verbose >= 3 ) { msr_srcname (msr, srcname, 1); ms_hptime2seedtimestr (msr->starttime, stime, 1); ms_log (1, "Skipping (starttime) %s, %s\n", srcname, stime); } continue; } if ( endtime != HPTERROR && (recendtime > endtime && ! (msr->starttime <= endtime && recendtime >= endtime)) ) { if ( verbose >= 3 ) { msr_srcname (msr, srcname, 1); ms_hptime2seedtimestr (msr->starttime, stime, 1); ms_log (1, "Skipping (starttime) %s, %s\n", srcname, stime); } continue; } } if ( match || reject ) { /* Generate the srcname with the quality code */ msr_srcname (msr, srcname, 1); /* Check if record is matched by the match regex */ if ( match ) { if ( regexec ( match, srcname, 0, 0, 0) != 0 ) { if ( verbose >= 3 ) { ms_hptime2seedtimestr (msr->starttime, stime, 1); ms_log (1, "Skipping (match) %s, %s\n", srcname, stime); } continue; } } /* Check if record is rejected by the reject regex */ if ( reject ) { if ( regexec ( reject, srcname, 0, 0, 0) == 0 ) { if ( verbose >= 3 ) { ms_hptime2seedtimestr (msr->starttime, stime, 1); ms_log (1, "Skipping (reject) %s, %s\n", srcname, stime); } continue; } } } if ( reccntdown > 0 ) reccntdown--; totalrecs++; totalsamps += msr->samplecnt; if ( ! tracegaponly ) { if ( printoffset ) ms_log (0, "%-10lld", (long long) filepos); if ( printlatency ) ms_log (0, "%-10.6g secs ", msr_host_latency(msr)); if ( printraw ) ms_parse_raw (msr->record, msr->reclen, ppackets, -1); else msr_print (msr, ppackets); } if ( tracegapsum || tracegaponly ) mstl_addmsr (mstl, msr, dataquality, 1, timetol, sampratetol); if ( dataflag ) { /* Parse the record (again) and unpack the data */ int rv = msr_unpack (msr->record, msr->reclen, &msr, 1, verbose); if ( rv == MS_NOERROR && printdata && ! tracegaponly ) { int line, col, cnt, samplesize; int lines = (msr->numsamples / 6) + 1; void *sptr; if ( (samplesize = ms_samplesize(msr->sampletype)) == 0 ) { ms_log (2, "Unrecognized sample type: %c\n", msr->sampletype); } if ( msr->sampletype == 'a' ) { char *ascii = (char *)msr->datasamples; int length = msr->numsamples; ms_log (0, "ASCII Data:\n"); /* Print maximum log message segments */ while ( length > (MAX_LOG_MSG_LENGTH-1) ) { ms_log (0, "%.*s", (MAX_LOG_MSG_LENGTH-1), ascii); ascii += MAX_LOG_MSG_LENGTH-1; length -= MAX_LOG_MSG_LENGTH-1; } /* Print any remaining ASCII and add a newline */ if ( length > 0 ) { ms_log (0, "%.*s\n", length, ascii); } else { ms_log (0, "\n"); } } else for ( cnt = 0, line = 0; line < lines; line++ ) { for ( col = 0; col < 6 ; col ++ ) { if ( cnt < msr->numsamples ) { sptr = (char*)msr->datasamples + (cnt * samplesize); if ( msr->sampletype == 'i' ) ms_log (0, "%10d ", *(int32_t *)sptr); else if ( msr->sampletype == 'f' ) ms_log (0, "%10.8g ", *(float *)sptr); else if ( msr->sampletype == 'd' ) ms_log (0, "%10.10g ", *(double *)sptr); cnt++; } } ms_log (0, "\n"); /* If only printing the first 6 samples break out here */ if ( printdata == 1 ) break; } } if ( binfile ) { uint8_t samplesize = ms_samplesize (msr->sampletype); if ( samplesize ) { fwrite (msr->datasamples, samplesize, msr->numsamples, bfp); } else { ms_log (1, "Cannot write to binary file, unknown sample type: %c\n", msr->sampletype); } } } if ( outfile ) { fwrite (msr->record, 1, msr->reclen, ofp); } } /* Print error if not EOF and not counting down records */ if ( retcode != MS_ENDOFFILE && reccntdown != 0 ) { ms_log (2, "Cannot read %s: %s\n", flp->filename, ms_errorstr(retcode)); ms_readmsr (&msr, NULL, 0, NULL, NULL, 0, 0, 0); exit (1); } /* Make sure everything is cleaned up */ ms_readmsr (&msr, NULL, 0, NULL, NULL, 0, 0, 0); totalfiles++; flp = flp->next; } /* End of looping over file list */ if ( binfile ) fclose (bfp); if ( outfile ) fclose (ofp); if ( basicsum ) ms_log (0, "Files: %lld, Records: %lld, Samples: %lld\n", totalfiles, totalrecs, totalsamps); if ( tracegapsum || tracegaponly ) { if ( tracegapsum == 1 || tracegaponly == 1 ) { mstl_printtracelist (mstl, timeformat, 1, tracegaps); } if ( tracegapsum == 2 || tracegaponly == 2 ) { mstl_printgaplist (mstl, timeformat, mingapptr, maxgapptr); } if ( tracegaponly == 3 ) { mstl_printsynclist (mstl, NULL, 1); } } if ( mstl ) mstl_free (&mstl, 0); return 0; } /* End of main() */
/************************************************************************ * msr_pack_data: * * Pack Mini-SEED data samples. The input data samples specified as * 'src' will be packed with 'encoding' format and placed in 'dest'. * * If a pointer to a 32-bit integer sample is provided in the * argument 'lastintsample' and 'comphistory' is true the sample * value will be used to seed the difference buffer for Steim1/2 * encoding and provide a compression history. It will also be * updated with the last sample packed in order to be used with a * subsequent call to this routine. * * Return number of samples packed on success and a negative on error. ************************************************************************/ static int msr_pack_data (void *dest, void *src, int maxsamples, int maxdatabytes, int32_t *lastintsample, flag comphistory, char sampletype, flag encoding, flag swapflag, char *srcname, flag verbose) { int nsamples; int32_t *intbuff; int32_t d0; /* Check for encode debugging environment variable */ if (getenv ("ENCODE_DEBUG")) encodedebug = 1; /* Decide if this is a format that we can encode */ switch (encoding) { case DE_ASCII: if (sampletype != 'a') { ms_log (2, "%s: Sample type must be ascii (a) for ASCII text encoding not '%c'\n", srcname, sampletype); return -1; } if (verbose > 1) ms_log (1, "%s: Packing ASCII data\n", srcname); nsamples = msr_encode_text (src, maxsamples, dest, maxdatabytes); break; case DE_INT16: if (sampletype != 'i') { ms_log (2, "%s: Sample type must be integer (i) for INT16 encoding not '%c'\n", srcname, sampletype); return -1; } if (verbose > 1) ms_log (1, "%s: Packing INT16 data samples\n", srcname); nsamples = msr_encode_int16 (src, maxsamples, dest, maxdatabytes, swapflag); break; case DE_INT32: if (sampletype != 'i') { ms_log (2, "%s: Sample type must be integer (i) for INT32 encoding not '%c'\n", srcname, sampletype); return -1; } if (verbose > 1) ms_log (1, "%s: Packing INT32 data samples\n", srcname); nsamples = msr_encode_int32 (src, maxsamples, dest, maxdatabytes, swapflag); break; case DE_FLOAT32: if (sampletype != 'f') { ms_log (2, "%s: Sample type must be float (f) for FLOAT32 encoding not '%c'\n", srcname, sampletype); return -1; } if (verbose > 1) ms_log (1, "%s: Packing FLOAT32 data samples\n", srcname); nsamples = msr_encode_float32 (src, maxsamples, dest, maxdatabytes, swapflag); break; case DE_FLOAT64: if (sampletype != 'd') { ms_log (2, "%s: Sample type must be double (d) for FLOAT64 encoding not '%c'\n", srcname, sampletype); return -1; } if (verbose > 1) ms_log (1, "%s: Packing FLOAT64 data samples\n", srcname); nsamples = msr_encode_float64 (src, maxsamples, dest, maxdatabytes, swapflag); break; case DE_STEIM1: if (sampletype != 'i') { ms_log (2, "%s: Sample type must be integer (i) for Steim1 compression not '%c'\n", srcname, sampletype); return -1; } intbuff = (int32_t *)src; /* If a previous sample is supplied use it for compression history otherwise cold-start */ d0 = (lastintsample && comphistory) ? (intbuff[0] - *lastintsample) : 0; if (verbose > 1) ms_log (1, "%s: Packing Steim1 data frames\n", srcname); nsamples = msr_encode_steim1 (src, maxsamples, dest, maxdatabytes, d0, swapflag); /* If a previous sample is supplied update it with the last sample value */ if (lastintsample && nsamples > 0) *lastintsample = intbuff[nsamples - 1]; break; case DE_STEIM2: if (sampletype != 'i') { ms_log (2, "%s: Sample type must be integer (i) for Steim2 compression not '%c'\n", srcname, sampletype); return -1; } intbuff = (int32_t *)src; /* If a previous sample is supplied use it for compression history otherwise cold-start */ d0 = (lastintsample && comphistory) ? (intbuff[0] - *lastintsample) : 0; if (verbose > 1) ms_log (1, "%s: Packing Steim2 data frames\n", srcname); nsamples = msr_encode_steim2 (src, maxsamples, dest, maxdatabytes, d0, srcname, swapflag); /* If a previous sample is supplied update it with the last sample value */ if (lastintsample && nsamples > 0) *lastintsample = intbuff[nsamples - 1]; break; default: ms_log (2, "%s: Unable to pack format %d\n", srcname, encoding); return -1; } return nsamples; } /* End of msr_pack_data() */
/*************************************************************************** * parameter_proc(): * Process the command line parameters. * * Returns 0 on success, and -1 on failure ***************************************************************************/ static int parameter_proc (int argcount, char **argvec) { int optind; /* Process all command line arguments */ for (optind = 1; optind < argcount; optind++) { if (strcmp (argvec[optind], "-V") == 0) { ms_log (1, "%s version: %s\n", PACKAGE, VERSION); exit (0); } else if (strcmp (argvec[optind], "-h") == 0) { usage (); exit (0); } else if (strncmp (argvec[optind], "-v", 2) == 0) { verbose += strspn (&argvec[optind][1], "v"); } else if (strncmp (argvec[optind], "-p", 2) == 0) { ppackets += strspn (&argvec[optind][1], "p"); } else if (strncmp (argvec[optind], "-d", 2) == 0) { printdata = 1; } else if (strncmp (argvec[optind], "-D", 2) == 0) { printdata = 2; } else if (strcmp (argvec[optind], "-s") == 0) { basicsum = 1; } else if (strcmp (argvec[optind], "-r") == 0) { reclen = atoi (argvec[++optind]); } else if (strncmp (argvec[optind], "-", 1) == 0 && strlen (argvec[optind]) > 1) { ms_log (2, "Unknown option: %s\n", argvec[optind]); exit (1); } else if (inputfile == 0) { inputfile = argvec[optind]; } else { ms_log (2, "Unknown option: %s\n", argvec[optind]); exit (1); } } /* Make sure an inputfile was specified */ if (!inputfile) { ms_log (2, "No input file was specified\n\n"); ms_log (1, "%s version %s\n\n", PACKAGE, VERSION); ms_log (1, "Try %s -h for usage\n", PACKAGE); exit (1); } /* Report the program version */ if (verbose) ms_log (1, "%s version: %s\n", PACKAGE, VERSION); return 0; } /* End of parameter_proc() */
/*************************************************************************** * parameter_proc(): * Process the command line parameters. * * Returns 0 on success, and -1 on failure ***************************************************************************/ static int processparam (int argcount, char **argvec) { int optind; char *matchpattern = 0; char *rejectpattern = 0; char *tptr; /* Process all command line arguments */ for (optind = 1; optind < argcount; optind++) { if (strcmp (argvec[optind], "-V") == 0) { ms_log (1, "%s version: %s\n", PACKAGE, VERSION); exit (0); } else if (strcmp (argvec[optind], "-h") == 0) { usage(); exit (0); } else if (strncmp (argvec[optind], "-v", 2) == 0) { verbose += strspn (&argvec[optind][1], "v"); } else if (strcmp (argvec[optind], "-r") == 0) { reclen = strtol (getoptval(argcount, argvec, optind++), NULL, 10); } else if (strcmp (argvec[optind], "-e") == 0) { encodingstr = getoptval(argcount, argvec, optind++); } else if (strcmp (argvec[optind], "-ts") == 0) { starttime = ms_seedtimestr2hptime (getoptval(argcount, argvec, optind++)); if ( starttime == HPTERROR ) return -1; } else if (strcmp (argvec[optind], "-te") == 0) { endtime = ms_seedtimestr2hptime (getoptval(argcount, argvec, optind++)); if ( endtime == HPTERROR ) return -1; } else if (strcmp (argvec[optind], "-M") == 0) { matchpattern = strdup (getoptval(argcount, argvec, optind++)); } else if (strcmp (argvec[optind], "-R") == 0) { rejectpattern = strdup (getoptval(argcount, argvec, optind++)); } else if (strcmp (argvec[optind], "-n") == 0) { reccntdown = strtol (getoptval(argcount, argvec, optind++), NULL, 10); } else if (strcmp (argvec[optind], "-y") == 0) { skipnotdata = 0; } else if (strncmp (argvec[optind], "-p", 2) == 0) { ppackets += strspn (&argvec[optind][1], "p"); } else if (strcmp (argvec[optind], "-O") == 0) { printoffset = 1; } else if (strcmp (argvec[optind], "-L") == 0) { printlatency = 1; } else if (strcmp (argvec[optind], "-s") == 0) { basicsum = 1; } else if (strcmp (argvec[optind], "-d") == 0) { printdata = 1; } else if (strcmp (argvec[optind], "-D") == 0) { printdata = 2; } else if (strcmp (argvec[optind], "-z") == 0) { printraw = 1; } else if (strcmp (argvec[optind], "-t") == 0) { tracegapsum = 1; } else if (strcmp (argvec[optind], "-T") == 0) { tracegaponly = 1; } else if (strcmp (argvec[optind], "-tg") == 0) { tracegaps = 1; /* -T is assumed if -t/-g is not already set */ if ( ! tracegapsum ) tracegaponly = 1; } else if (strcmp (argvec[optind], "-tt") == 0) { timetol = strtod (getoptval(argcount, argvec, optind++), NULL); } else if (strcmp (argvec[optind], "-rt") == 0) { sampratetol = strtod (getoptval(argcount, argvec, optind++), NULL); } else if (strcmp (argvec[optind], "-g") == 0) { tracegapsum = 2; } else if (strcmp (argvec[optind], "-G") == 0) { tracegaponly = 2; } else if (strcmp (argvec[optind], "-S") == 0) { tracegaponly = 3; } else if (strcmp (argvec[optind], "-gmin") == 0) { mingap = strtod (getoptval(argcount, argvec, optind++), NULL); mingapptr = &mingap; } else if (strcmp (argvec[optind], "-gmax") == 0) { maxgap = strtod (getoptval(argcount, argvec, optind++), NULL); maxgapptr = &maxgap; } else if (strcmp (argvec[optind], "-Q") == 0) { dataquality = 1; } else if (strcmp (argvec[optind], "-tf") == 0) { timeformat = strtol (getoptval(argcount, argvec, optind++), NULL, 10); } else if (strcmp (argvec[optind], "-b") == 0) { binfile = getoptval(argcount, argvec, optind++); } else if (strcmp (argvec[optind], "-o") == 0) { outfile = getoptval(argcount, argvec, optind++); } else if (strncmp (argvec[optind], "-", 1) == 0 && strlen (argvec[optind]) > 1 ) { ms_log (2, "Unknown option: %s\n", argvec[optind]); exit (1); } else { tptr = argvec[optind]; /* Check for an input file list */ if ( tptr[0] == '@' ) { if ( addlistfile (tptr+1) < 0 ) { ms_log (2, "Error adding list file %s", tptr+1); exit (1); } } /* Otherwise this is an input file */ else { /* Add file to global file list */ if ( addfile (tptr) ) { ms_log (2, "Error adding file to input list %s", tptr); exit (1); } } } } /* Make sure input file were specified */ if ( filelist == 0 ) { ms_log (2, "No input files were specified\n\n"); ms_log (1, "%s version %s\n\n", PACKAGE, VERSION); ms_log (1, "Try %s -h for usage\n", PACKAGE); exit (1); } /* Expand match pattern from a file if prefixed by '@' */ if ( matchpattern ) { if ( *matchpattern == '@' ) { tptr = strdup(matchpattern + 1); /* Skip the @ sign */ free (matchpattern); matchpattern = 0; if ( readregexfile (tptr, &matchpattern) <= 0 ) { ms_log (2, "Cannot read match pattern regex file\n"); exit (1); } free (tptr); } } /* Expand reject pattern from a file if prefixed by '@' */ if ( rejectpattern ) { if ( *rejectpattern == '@' ) { tptr = strdup(rejectpattern + 1); /* Skip the @ sign */ free (rejectpattern); rejectpattern = 0; if ( readregexfile (tptr, &rejectpattern) <= 0 ) { ms_log (2, "Cannot read reject pattern regex file\n"); exit (1); } free (tptr); } } /* Compile match and reject patterns */ if ( matchpattern ) { match = (regex_t *) malloc (sizeof(regex_t)); if ( regcomp (match, matchpattern, REG_EXTENDED) != 0) { ms_log (2, "Cannot compile match regex: '%s'\n", matchpattern); } free (matchpattern); } if ( rejectpattern ) { reject = (regex_t *) malloc (sizeof(regex_t)); if ( regcomp (reject, rejectpattern, REG_EXTENDED) != 0) { ms_log (2, "Cannot compile reject regex: '%s'\n", rejectpattern); } free (rejectpattern); } /* Report the program version */ if ( verbose ) ms_log (1, "%s version: %s\n", PACKAGE, VERSION); return 0; } /* End of parameter_proc() */
/*************************************************************************** * 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_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, %"PRId64" samples, %-.10g Hz, %s\n", srcname, msr->sequence_number, msr->dataquality, msr->reclen, 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_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_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_parse: * * This routine will attempt to parse (detect and unpack) a Mini-SEED * record from a specified memory buffer and populate a supplied * MSRecord structure. * * If reclen is less than or equal to 0 the length of record is * automatically detected otherwise reclen should be the correct * record length. * * For auto detection of record length the record should include a * 1000 blockette or be followed by another record header in the * buffer. * * dataflag will be passed directly to msr_unpack(). * * Return values: * 0 : Success, populates the supplied MSRecord. * >0 : Data record detected but not enough data is present, the * return value is a hint of how many more bytes are needed. * <0 : libmseed error code (listed in libmseed.h) is returned. *********************************************************************/ int msr_parse ( char *record, int recbuflen, MSRecord **ppmsr, int reclen, flag dataflag, flag verbose ) { int detlen = 0; int retcode = 0; if ( ! ppmsr ) return MS_GENERROR; if ( ! record ) return MS_GENERROR; /* Sanity check: record length cannot be larger than buffer */ if ( reclen > 0 && reclen > recbuflen ) { ms_log (2, "ms_parse() Record length (%d) cannot be larger than buffer (%d)\n", reclen, recbuflen); return MS_GENERROR; } /* Autodetect the record length */ if ( reclen <= 0 ) { detlen = ms_detect (record, recbuflen); /* No data record detected */ if ( detlen < 0 ) { return MS_NOTSEED; } /* Found record but could not determine length */ if ( detlen == 0 ) { return 256; } if ( verbose > 2 ) { ms_log (1, "Detected record length of %d bytes\n", detlen); } reclen = detlen; } /* Check that record length is in supported range */ if ( reclen < MINRECLEN || reclen > MAXRECLEN ) { ms_log (2, "Record length is out of range: %d (allowed: %d to %d)\n", reclen, MINRECLEN, MAXRECLEN); return MS_OUTOFRANGE; } /* Check if more data is required, return hint */ if ( reclen > recbuflen ) { if ( verbose > 2 ) ms_log (1, "Detected %d byte record, need %d more bytes\n", reclen, (reclen - recbuflen)); return (reclen - recbuflen); } /* Unpack record */ if ( (retcode = msr_unpack (record, reclen, ppmsr, dataflag, verbose)) != MS_NOERROR ) { msr_free (ppmsr); return retcode; } return MS_NOERROR; } /* End of msr_parse() */
/************************************************************************ * msr_decode_geoscope: * * Decode GEOSCOPE gain ranged data (demultiplexed only) encoded * miniSEED data and place in supplied buffer as 32-bit floats. * * Return number of samples in output buffer on success, -1 on error. ************************************************************************/ int msr_decode_geoscope (char *input, int samplecount, float *output, int outputlength, int encoding, char *srcname, int swapflag) { int idx = 0; int mantissa; /* mantissa from SEED data */ int gainrange; /* gain range factor */ int exponent; /* total exponent */ int k; uint64_t exp2val; int16_t sint; double dsample = 0.0; union { uint8_t b[4]; uint32_t i; } sample32; if (!input || !output) return -1; if (samplecount <= 0 || outputlength <= 0) return -1; /* Make sure we recognize this as a GEOSCOPE encoding format */ if (encoding != DE_GEOSCOPE24 && encoding != DE_GEOSCOPE163 && encoding != DE_GEOSCOPE164) { ms_log (2, "msr_decode_geoscope(%s): unrecognized GEOSCOPE encoding: %d\n", srcname, encoding); return -1; } for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (float); idx++) { switch (encoding) { case DE_GEOSCOPE24: sample32.i = 0; if (swapflag) for (k = 0; k < 3; k++) sample32.b[2 - k] = input[k]; else for (k = 0; k < 3; k++) sample32.b[1 + k] = input[k]; mantissa = sample32.i; /* Take 2's complement for mantissa for overflow */ if (mantissa > MAX24) mantissa -= 2 * (MAX24 + 1); /* Store */ dsample = (double)mantissa; break; case DE_GEOSCOPE163: memcpy (&sint, input, sizeof (int16_t)); if (swapflag) ms_gswap2a (&sint); /* Recover mantissa and gain range factor */ mantissa = (sint & GEOSCOPE_MANTISSA_MASK); gainrange = (sint & GEOSCOPE_GAIN3_MASK) >> GEOSCOPE_SHIFT; /* Exponent is just gainrange for GEOSCOPE */ exponent = gainrange; /* Calculate sample as mantissa / 2^exponent */ exp2val = (uint64_t)1 << exponent; dsample = ((double)(mantissa - 2048)) / exp2val; break; case DE_GEOSCOPE164: memcpy (&sint, input, sizeof (int16_t)); if (swapflag) ms_gswap2a (&sint); /* Recover mantissa and gain range factor */ mantissa = (sint & GEOSCOPE_MANTISSA_MASK); gainrange = (sint & GEOSCOPE_GAIN4_MASK) >> GEOSCOPE_SHIFT; /* Exponent is just gainrange for GEOSCOPE */ exponent = gainrange; /* Calculate sample as mantissa / 2^exponent */ exp2val = (uint64_t)1 << exponent; dsample = ((double)(mantissa - 2048)) / exp2val; break; } /* Save sample in output array */ output[idx] = (float)dsample; outputlength -= sizeof (float); /* Increment edata pointer depending on size */ switch (encoding) { case DE_GEOSCOPE24: input += 3; break; case DE_GEOSCOPE163: case DE_GEOSCOPE164: input += 2; break; } } return idx; } /* End of msr_decode_geoscope() */
int main (int argc, char **argv) { MSRecord *msr = 0; int64_t totalrecs = 0; int64_t totalsamps = 0; int retcode; #ifndef WIN32 /* Signal handling, use POSIX calls with standardized semantics */ struct sigaction sa; sa.sa_flags = SA_RESTART; sigemptyset (&sa.sa_mask); sa.sa_handler = term_handler; sigaction (SIGINT, &sa, NULL); sigaction (SIGQUIT, &sa, NULL); sigaction (SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction (SIGHUP, &sa, NULL); sigaction (SIGPIPE, &sa, NULL); #endif /* Process given parameters (command line and parameter file) */ if (parameter_proc (argc, argv) < 0) return -1; /* Loop over the input file */ while ((retcode = ms_readmsr (&msr, inputfile, reclen, NULL, NULL, 1, printdata, verbose)) == MS_NOERROR) { totalrecs++; totalsamps += msr->samplecnt; msr_print (msr, ppackets); if (printdata && msr->numsamples > 0) { int line, col, cnt, samplesize; int lines = (msr->numsamples / 6) + 1; void *sptr; if ((samplesize = ms_samplesize (msr->sampletype)) == 0) { ms_log (2, "Unrecognized sample type: '%c'\n", msr->sampletype); } for (cnt = 0, line = 0; line < lines; line++) { for (col = 0; col < 6; col++) { if (cnt < msr->numsamples) { sptr = (char *)msr->datasamples + (cnt * samplesize); if (msr->sampletype == 'i') ms_log (0, "%10d ", *(int32_t *)sptr); else if (msr->sampletype == 'f') ms_log (0, "%10.8g ", *(float *)sptr); else if (msr->sampletype == 'd') ms_log (0, "%10.10g ", *(double *)sptr); cnt++; } } ms_log (0, "\n"); /* If only printing the first 6 samples break out here */ if (printdata == 1) break; } } } if (retcode != MS_ENDOFFILE) ms_log (2, "Cannot read %s: %s\n", inputfile, ms_errorstr (retcode)); /* Make sure everything is cleaned up */ ms_readmsr (&msr, NULL, 0, NULL, NULL, 0, 0, 0); if (basicsum) ms_log (1, "Records: %" PRId64 ", Samples: %" PRId64 "\n", totalrecs, totalsamps); return 0; } /* End of main() */
/********************************************************************** * ms_readmsr_main: * * This routine will open and read, with subsequent calls, all * Mini-SEED records in specified file. * * All static file reading parameters are stored in a MSFileParam * struct and returned (via a pointer to a pointer) for the calling * routine to use in subsequent calls. A MSFileParam struct will be * allocated if necessary. This routine is thread safe and can be * used to read multiple files in parallel as long as the file reading * parameters are managed appropriately. * * If reclen is 0 or negative the length of every record is * automatically detected. For auto detection of record length the * record must include a 1000 blockette or be followed by a valid * record header or end of file. * * If *fpos is not NULL it will be updated to reflect the file * position (offset from the beginning in bytes) from where the * returned record was read. As a special case, if *fpos is not NULL * and the value it points to is less than 0 this will be interpreted * as a (positive) starting offset from which to begin reading data; * this feature does not work with packed files. * * If *last is not NULL it will be set to 1 when the last record in * the file is being returned, otherwise it will be 0. * * If the skipnotdata flag is true any data chunks read that do not * have valid data record indicators (D, R, Q, M, etc.) will be skipped. * * dataflag will be passed directly to msr_unpack(). * * If a Selections list is supplied it will be used to determine when * a section of data in a packed file may be skipped, packed files are * internal to the IRIS DMC. * * After reading all the records in a file the controlling program * should call it one last time with msfile set to NULL. This will * close the file and free allocated memory. * * Returns MS_NOERROR and populates an MSRecord struct at *ppmsr on * successful read, returns MS_ENDOFFILE on EOF, otherwise returns a * libmseed error code (listed in libmseed.h) and *ppmsr is set to * NULL. *********************************************************************/ int ms_readmsr_main (MSFileParam **ppmsfp, MSRecord **ppmsr, const char *msfile, int reclen, off_t *fpos, int *last, flag skipnotdata, flag dataflag, Selections *selections, flag verbose) { MSFileParam *msfp; off_t packdatasize = 0; int packskipsize; int parseval = 0; int readsize = 0; int readcount = 0; int retcode = MS_NOERROR; if (!ppmsr) return MS_GENERROR; if (!ppmsfp) return MS_GENERROR; msfp = *ppmsfp; /* Initialize the file read parameters if needed */ if (!msfp) { msfp = (MSFileParam *)malloc (sizeof (MSFileParam)); if (msfp == NULL) { ms_log (2, "ms_readmsr_main(): Cannot allocate memory for MSFP\n"); return MS_GENERROR; } /* Redirect the supplied pointer to the allocated params */ *ppmsfp = msfp; msfp->fp = NULL; msfp->filename[0] = '\0'; msfp->rawrec = NULL; msfp->readlen = 0; msfp->readoffset = 0; msfp->packtype = 0; msfp->packhdroffset = 0; msfp->filepos = 0; msfp->filesize = 0; msfp->recordcount = 0; } /* When cleanup is requested */ if (msfile == NULL) { msr_free (ppmsr); if (msfp->fp != NULL) fclose (msfp->fp); if (msfp->rawrec != NULL) free (msfp->rawrec); /* If the file parameters are the global parameters reset them */ if (*ppmsfp == &gMSFileParam) { gMSFileParam.fp = NULL; gMSFileParam.filename[0] = '\0'; gMSFileParam.rawrec = NULL; gMSFileParam.readlen = 0; gMSFileParam.readoffset = 0; gMSFileParam.packtype = 0; gMSFileParam.packhdroffset = 0; gMSFileParam.filepos = 0; gMSFileParam.filesize = 0; gMSFileParam.recordcount = 0; } /* Otherwise free the MSFileParam */ else { free (*ppmsfp); *ppmsfp = NULL; } return MS_NOERROR; } /* Allocate reading buffer */ if (msfp->rawrec == NULL) { if (!(msfp->rawrec = (char *)malloc (MAXRECLEN))) { ms_log (2, "ms_readmsr_main(): Cannot allocate memory for read buffer\n"); return MS_GENERROR; } } /* Sanity check: track if we are reading the same file */ if (msfp->fp && strncmp (msfile, msfp->filename, sizeof (msfp->filename))) { ms_log (2, "ms_readmsr_main() called with a different file name without being reset\n"); /* Close previous file and reset needed variables */ if (msfp->fp != NULL) fclose (msfp->fp); msfp->fp = NULL; msfp->readlen = 0; msfp->readoffset = 0; msfp->packtype = 0; msfp->packhdroffset = 0; msfp->filepos = 0; msfp->filesize = 0; msfp->recordcount = 0; } /* Open the file if needed, redirect to stdin if file is "-" */ if (msfp->fp == NULL) { /* Store the filename for tracking */ strncpy (msfp->filename, msfile, sizeof (msfp->filename) - 1); msfp->filename[sizeof (msfp->filename) - 1] = '\0'; if (strcmp (msfile, "-") == 0) { msfp->fp = stdin; } else { if ((msfp->fp = fopen (msfile, "rb")) == NULL) { ms_log (2, "Cannot open file: %s (%s)\n", msfile, strerror (errno)); msr_free (ppmsr); return MS_GENERROR; } else { /* Determine file size */ struct stat sbuf; if (fstat (fileno (msfp->fp), &sbuf)) { ms_log (2, "Cannot open file: %s (%s)\n", msfile, strerror (errno)); msr_free (ppmsr); return MS_GENERROR; } msfp->filesize = sbuf.st_size; } } } /* Seek to a specified offset if requested */ if (fpos != NULL && *fpos < 0) { /* Only try to seek in real files, not stdin */ if (msfp->fp != stdin) { if (lmp_fseeko (msfp->fp, *fpos * -1, SEEK_SET)) { ms_log (2, "Cannot seek in file: %s (%s)\n", msfile, strerror (errno)); return MS_GENERROR; } msfp->filepos = *fpos * -1; msfp->readlen = 0; msfp->readoffset = 0; } } /* Zero the last record indicator */ if (last) *last = 0; /* Read data and search for records */ for (;;) { /* Read more data into buffer if not at EOF and buffer has less than MINRECLEN * or more data is needed for the current record detected in buffer. */ if (!feof (msfp->fp) && (MSFPBUFLEN (msfp) < MINRECLEN || parseval > 0)) { /* Reset offsets if no unprocessed data in buffer */ if (MSFPBUFLEN (msfp) <= 0) { msfp->readlen = 0; msfp->readoffset = 0; } /* Otherwise shift existing data to beginning of buffer */ else if (msfp->readoffset > 0) { ms_shift_msfp (msfp, msfp->readoffset); } /* Determine read size */ readsize = (MAXRECLEN - msfp->readlen); /* Read data into record buffer */ readcount = ms_fread (msfp->rawrec + msfp->readlen, 1, readsize, msfp->fp); if (readcount != readsize) { if (!feof (msfp->fp)) { ms_log (2, "Short read of %d bytes starting from %" PRId64 "\n", readsize, msfp->filepos); retcode = MS_GENERROR; break; } } /* Update read buffer length */ msfp->readlen += readcount; /* File position corresponding to start of buffer; not strictly necessary */ if (msfp->fp != stdin) msfp->filepos = lmp_ftello (msfp->fp) - msfp->readlen; } /* Test for packed file signature at the beginning of the file */ if (msfp->filepos == 0 && *(MSFPREADPTR (msfp)) == 'P' && MSFPBUFLEN (msfp) >= 48) { msfp->packtype = 0; /* Determine pack type, the negative pack type indicates initial header */ if (!memcmp ("PED", MSFPREADPTR (msfp), 3)) msfp->packtype = -1; else if (!memcmp ("PSD", MSFPREADPTR (msfp), 3)) msfp->packtype = -2; else if (!memcmp ("PLC", MSFPREADPTR (msfp), 3)) msfp->packtype = -6; else if (!memcmp ("PQI", MSFPREADPTR (msfp), 3)) msfp->packtype = -7; else if (!memcmp ("PLS", MSFPREADPTR (msfp), 3)) msfp->packtype = -8; if (verbose > 0) ms_log (1, "Detected packed file (%3.3s: type %d)\n", MSFPREADPTR (msfp), -msfp->packtype); } /* Read pack headers, initial and subsequent headers including (ignored) chksum values */ if (msfp->packtype && (msfp->packtype < 0 || msfp->filepos == msfp->packhdroffset) && MSFPBUFLEN (msfp) >= 48) { char hdrstr[30]; int64_t datasize; /* Determine bytes to skip before header: either initial ID block or type-specific chksum block */ packskipsize = (msfp->packtype < 0) ? 10 : packtypes[msfp->packtype][2]; if (msfp->packtype < 0) msfp->packtype = -msfp->packtype; /* Read pack length from pack header accounting for bytes that should be skipped */ memset (hdrstr, 0, sizeof (hdrstr)); memcpy (hdrstr, MSFPREADPTR (msfp) + (packtypes[msfp->packtype][0] + packskipsize - packtypes[msfp->packtype][1]), packtypes[msfp->packtype][1]); sscanf (hdrstr, " %" SCNd64, &datasize); packdatasize = (off_t)datasize; /* Next pack header = File position + skipsize + header size + data size * This offset is actually to the data block chksum which is skipped by the logic above, * the next pack header should directly follow the chksum. */ msfp->packhdroffset = msfp->filepos + packskipsize + packtypes[msfp->packtype][0] + packdatasize; if (verbose > 1) ms_log (1, "Read packed file header at offset %" PRId64 " (%d bytes follow), chksum offset: %" PRId64 "\n", (msfp->filepos + packskipsize), packdatasize, msfp->packhdroffset); /* Shift buffer to new reading offset (aligns records in buffer) */ ms_shift_msfp (msfp, msfp->readoffset + (packskipsize + packtypes[msfp->packtype][0])); } /* End of packed header processing */ /* Check for match if selections are supplied and pack header was read, */ /* only when enough data is in buffer and not reading from stdin pipe */ if (selections && msfp->packtype && packdatasize && MSFPBUFLEN (msfp) >= 48 && msfp->fp != stdin) { char srcname[100]; ms_recsrcname (MSFPREADPTR (msfp), srcname, 1); if (!ms_matchselect (selections, srcname, HPTERROR, HPTERROR, NULL)) { /* Update read position if next section is in buffer */ if (MSFPBUFLEN (msfp) >= (msfp->packhdroffset - msfp->filepos)) { if (verbose > 1) { ms_log (1, "Skipping (jump) packed section for %s (%d bytes) starting at offset %" PRId64 "\n", srcname, (msfp->packhdroffset - msfp->filepos), msfp->filepos); } msfp->readoffset += (msfp->packhdroffset - msfp->filepos); msfp->filepos = msfp->packhdroffset; packdatasize = 0; } /* Otherwise seek to next pack header and reset reading position */ else { if (verbose > 1) { ms_log (1, "Skipping (seek) packed section for %s (%d bytes) starting at offset %" PRId64 "\n", srcname, (msfp->packhdroffset - msfp->filepos), msfp->filepos); } if (lmp_fseeko (msfp->fp, msfp->packhdroffset, SEEK_SET)) { ms_log (2, "Cannot seek in file: %s (%s)\n", msfile, strerror (errno)); return MS_GENERROR; break; } msfp->filepos = msfp->packhdroffset; msfp->readlen = 0; msfp->readoffset = 0; packdatasize = 0; } /* Return to top of loop for proper pack header handling */ continue; } } /* End of selection processing */ /* Attempt to parse record from buffer */ if (MSFPBUFLEN (msfp) >= MINRECLEN) { int parselen = MSFPBUFLEN (msfp); /* Limit the parse length to offset of pack header if present in the buffer */ if (msfp->packhdroffset && msfp->packhdroffset < (msfp->filepos + MSFPBUFLEN (msfp))) parselen = msfp->packhdroffset - msfp->filepos; parseval = msr_parse (MSFPREADPTR (msfp), parselen, ppmsr, reclen, dataflag, verbose); /* Record detected and parsed */ if (parseval == 0) { if (verbose > 1) ms_log (1, "Read record length of %d bytes\n", (*ppmsr)->reclen); /* Test if this is the last record if file size is known (not pipe) */ if (last && msfp->filesize) if ((msfp->filesize - (msfp->filepos + (*ppmsr)->reclen)) < MINRECLEN) *last = 1; /* Return file position for this record */ if (fpos) *fpos = msfp->filepos; /* Update reading offset, file position and record count */ msfp->readoffset += (*ppmsr)->reclen; msfp->filepos += (*ppmsr)->reclen; msfp->recordcount++; retcode = MS_NOERROR; break; } else if (parseval < 0) { /* Skip non-data if requested */ if (skipnotdata) { if (verbose > 1) { if (MS_ISVALIDBLANK ((char *)MSFPREADPTR (msfp))) ms_log (1, "Skipped %d bytes of blank/noise record at byte offset %" PRId64 "\n", MINRECLEN, msfp->filepos); else ms_log (1, "Skipped %d bytes of non-data record at byte offset %" PRId64 "\n", MINRECLEN, msfp->filepos); } /* Skip MINRECLEN bytes, update reading offset and file position */ msfp->readoffset += MINRECLEN; msfp->filepos += MINRECLEN; } /* Parsing errors */ else { ms_log (2, "Cannot detect record at byte offset %" PRId64 ": %s\n", msfp->filepos, msfile); /* Print common errors and raw details if verbose */ ms_parse_raw (MSFPREADPTR (msfp), MSFPBUFLEN (msfp), verbose, -1); retcode = parseval; break; } } else /* parseval > 0 (found record but need more data) */ { /* Determine implied record length if needed */ int32_t impreclen = reclen; /* Check for parse hints that are larger than MAXRECLEN */ if ((MSFPBUFLEN (msfp) + parseval) > MAXRECLEN) { if (skipnotdata) { /* Skip MINRECLEN bytes, update reading offset and file position */ msfp->readoffset += MINRECLEN; msfp->filepos += MINRECLEN; } else { retcode = MS_OUTOFRANGE; break; } } /* Pack header check, if pack header offset is within buffer */ else if (impreclen <= 0 && msfp->packhdroffset && msfp->packhdroffset < (msfp->filepos + MSFPBUFLEN (msfp))) { impreclen = msfp->packhdroffset - msfp->filepos; /* Check that record length is within range and a power of 2. * Power of two if (X & (X - 1)) == 0 */ if (impreclen >= MINRECLEN && impreclen <= MAXRECLEN && (impreclen & (impreclen - 1)) == 0) { /* Set the record length implied by the next pack header */ reclen = impreclen; } else { ms_log (1, "Implied record length (%d) is invalid\n", impreclen); retcode = MS_NOTSEED; break; } } /* End of file check */ else if (impreclen <= 0 && feof (msfp->fp)) { impreclen = msfp->filesize - msfp->filepos; /* Check that record length is within range and a power of 2. * Power of two if (X & (X - 1)) == 0 */ if (impreclen >= MINRECLEN && impreclen <= MAXRECLEN && (impreclen & (impreclen - 1)) == 0) { /* Set the record length implied by the end of the file */ reclen = impreclen; } /* Otherwise a trucated record */ else { if (verbose) { if (msfp->filesize) ms_log (1, "Truncated record at byte offset %" PRId64 ", filesize %d: %s\n", msfp->filepos, msfp->filesize, msfile); else ms_log (1, "Truncated record at byte offset %" PRId64 "\n", msfp->filepos); } retcode = MS_ENDOFFILE; break; } } } } /* End of record detection */ /* Finished when within MINRECLEN from EOF and buffer less than MINRECLEN */ if ((msfp->filesize - msfp->filepos) < MINRECLEN && MSFPBUFLEN (msfp) < MINRECLEN) { if (msfp->recordcount == 0 && msfp->packtype == 0) { if (verbose > 0) ms_log (2, "%s: No data records read, not SEED?\n", msfile); retcode = MS_NOTSEED; } else { retcode = MS_ENDOFFILE; } break; } } /* End of reading, record detection and parsing loop */ /* Cleanup target MSRecord if returning an error */ if (retcode != MS_NOERROR) { msr_free (ppmsr); } return retcode; } /* End of ms_readmsr_main() */
/************************************************************************ * msr_unpack_data: * * Unpack Mini-SEED data samples for a given MSRecord. The packed * data is accessed in the record indicated by MSRecord->record and * the unpacked samples are placed in MSRecord->datasamples. The * resulting data samples are either 32-bit integers, 32-bit floats * or 64-bit floats in host byte order. * * Return number of samples unpacked or negative libmseed error code. ************************************************************************/ static int msr_unpack_data ( MSRecord *msr, int swapflag, int verbose ) { int datasize; /* byte size of data samples in record */ int nsamples; /* number of samples unpacked */ int unpacksize; /* byte size of unpacked samples */ int samplesize = 0; /* size of the data samples in bytes */ const char *dbuf; int32_t *diffbuff; int32_t x0, xn; /* Sanity record length */ if ( msr->reclen == -1 ) { ms_log (2, "msr_unpack_data(%s): Record size unknown\n", UNPACK_SRCNAME_2); return MS_NOTSEED; } switch (msr->encoding) { case DE_ASCII: samplesize = 1; break; case DE_INT16: case DE_INT32: case DE_FLOAT32: case DE_STEIM1: case DE_STEIM2: case DE_GEOSCOPE24: case DE_GEOSCOPE163: case DE_GEOSCOPE164: case DE_CDSN: case DE_SRO: case DE_DWWSSN: samplesize = 4; break; case DE_FLOAT64: samplesize = 8; break; default: samplesize = 0; break; } /* Calculate buffer size needed for unpacked samples */ unpacksize = msr->samplecnt * samplesize; /* (Re)Allocate space for the unpacked data */ if ( unpacksize > 0 ) { msr->datasamples = realloc (msr->datasamples, unpacksize); if ( msr->datasamples == NULL ) { ms_log (2, "msr_unpack_data(%s): Cannot (re)allocate memory\n", UNPACK_SRCNAME_2); return MS_GENERROR; } } else { if ( msr->datasamples ) free (msr->datasamples); msr->datasamples = 0; msr->numsamples = 0; } datasize = msr->reclen - msr->fsdh->data_offset; dbuf = msr->record + msr->fsdh->data_offset; if ( verbose > 2 ) ms_log (1, "%s: Unpacking %d samples\n", UNPACK_SRCNAME_2, msr->samplecnt); /* Decide if this is a encoding that we can decode */ switch (msr->encoding) { case DE_ASCII: if ( verbose > 1 ) ms_log (1, "%s: Found ASCII data\n", UNPACK_SRCNAME_2); nsamples = msr->samplecnt; memcpy (msr->datasamples, dbuf, nsamples); msr->sampletype = 'a'; break; case DE_INT16: if ( verbose > 1 ) ms_log (1, "%s: Unpacking INT-16 data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_int_16 ((int16_t *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'i'; break; case DE_INT32: if ( verbose > 1 ) ms_log (1, "%s: Unpacking INT-32 data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_int_32 ((int32_t *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'i'; break; case DE_FLOAT32: if ( verbose > 1 ) ms_log (1, "%s: Unpacking FLOAT-32 data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_float_32 ((float *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'f'; break; case DE_FLOAT64: if ( verbose > 1 ) ms_log (1, "%s: Unpacking FLOAT-64 data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_float_64 ((double *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'd'; break; case DE_STEIM1: diffbuff = (int32_t *) malloc(unpacksize); if ( diffbuff == NULL ) { ms_log (2, "msr_unpack_data(%s): Cannot allocate diff buffer\n", UNPACK_SRCNAME_2); return MS_GENERROR; } if ( verbose > 1 ) ms_log (1, "%s: Unpacking Steim-1 data frames\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_steim1 ((FRAME *)dbuf, datasize, msr->samplecnt, msr->samplecnt, msr->datasamples, diffbuff, &x0, &xn, swapflag, verbose); msr->sampletype = 'i'; free (diffbuff); break; case DE_STEIM2: diffbuff = (int32_t *) malloc(unpacksize); if ( diffbuff == NULL ) { ms_log (2, "msr_unpack_data(%s): Cannot allocate diff buffer\n", UNPACK_SRCNAME_2); return MS_GENERROR; } if ( verbose > 1 ) ms_log (1, "%s: Unpacking Steim-2 data frames\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_steim2 ((FRAME *)dbuf, datasize, msr->samplecnt, msr->samplecnt, msr->datasamples, diffbuff, &x0, &xn, swapflag, verbose); msr->sampletype = 'i'; free (diffbuff); break; case DE_GEOSCOPE24: case DE_GEOSCOPE163: case DE_GEOSCOPE164: if ( verbose > 1 ) { if ( msr->encoding == DE_GEOSCOPE24 ) ms_log (1, "%s: Unpacking GEOSCOPE 24bit integer data samples\n", UNPACK_SRCNAME_2); if ( msr->encoding == DE_GEOSCOPE163 ) ms_log (1, "%s: Unpacking GEOSCOPE 16bit gain ranged/3bit exponent data samples\n", UNPACK_SRCNAME_2); if ( msr->encoding == DE_GEOSCOPE164 ) ms_log (1, "%s: Unpacking GEOSCOPE 16bit gain ranged/4bit exponent data samples\n", UNPACK_SRCNAME_2); } nsamples = msr_unpack_geoscope (dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, msr->encoding, swapflag); msr->sampletype = 'f'; break; case DE_CDSN: if ( verbose > 1 ) ms_log (1, "%s: Unpacking CDSN encoded data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_cdsn ((int16_t *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'i'; break; case DE_SRO: if ( verbose > 1 ) ms_log (1, "%s: Unpacking SRO encoded data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_sro ((int16_t *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'i'; break; case DE_DWWSSN: if ( verbose > 1 ) ms_log (1, "%s: Unpacking DWWSSN encoded data samples\n", UNPACK_SRCNAME_2); nsamples = msr_unpack_dwwssn ((int16_t *)dbuf, msr->samplecnt, msr->samplecnt, msr->datasamples, swapflag); msr->sampletype = 'i'; break; default: ms_log (2, "%s: Unsupported encoding format %d (%s)\n", UNPACK_SRCNAME_2, msr->encoding, (char *) ms_encodingstr(msr->encoding)); return MS_UNKNOWNFORMAT; } return nsamples; } /* End of msr_unpack_data() */
/*************************************************************************** * readregexfile: * * Read a list of regular expressions from a file and combine them * into a single, compound expression which is returned in *pppattern. * The return buffer is reallocated as need to hold the growing * pattern. When called *pppattern should not point to any associated * memory. * * Returns the number of regexes parsed from the file or -1 on error. ***************************************************************************/ static int readregexfile (char *regexfile, char **pppattern) { FILE *fp; char line[1024]; char linepattern[1024]; int regexcnt = 0; int lengthbase; int lengthadd; if ( ! regexfile ) { ms_log (2, "readregexfile: regex file not supplied\n"); return -1; } if ( ! pppattern ) { ms_log (2, "readregexfile: pattern string buffer not supplied\n"); return -1; } /* Open the regex list file */ if ( (fp = fopen (regexfile, "rb")) == NULL ) { ms_log (2, "Cannot open regex list file %s: %s\n", regexfile, strerror (errno)); return -1; } if ( verbose ) ms_log (1, "Reading regex list from %s\n", regexfile); *pppattern = NULL; while ( (fgets (line, sizeof(line), fp)) != NULL) { /* Trim spaces and skip if empty lines */ if ( sscanf (line, " %s ", linepattern) != 1 ) continue; /* Skip comment lines */ if ( *linepattern == '#' ) continue; regexcnt++; /* Add regex to compound regex */ if ( *pppattern ) { lengthbase = strlen(*pppattern); lengthadd = strlen(linepattern) + 4; /* Length of addition plus 4 characters: |()\0 */ *pppattern = realloc (*pppattern, lengthbase + lengthadd); if ( *pppattern ) { snprintf ((*pppattern)+lengthbase, lengthadd, "|(%s)", linepattern); } else { ms_log (2, "Cannot allocate memory for regex string\n"); return -1; } } else { lengthadd = strlen(linepattern) + 3; /* Length of addition plus 3 characters: ()\0 */ *pppattern = malloc (lengthadd); if ( *pppattern ) { snprintf (*pppattern, lengthadd, "(%s)", linepattern); } else { ms_log (2, "Cannot allocate memory for regex string\n"); return -1; } } } fclose (fp); return regexcnt; } /* End of readregexfile() */
// Function that reads from a MiniSEED binary file from a char buffer and // returns a LinkedIDList. LinkedIDList * readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag unpack_data, int reclen, flag verbose, flag details, int header_byteorder, long long (*allocData) (int, char), void (*diag_print) (char*), void (*log_print) (char*)) { int retcode = 0; int retval = 0; flag swapflag = 0; flag bigendianhost = ms_bigendianhost(); // current offset of mseed char pointer int offset = 0; // Unpack without reading the data first flag dataflag = 0; // the timing_qual of BLK 1001 uint8_t timing_qual = 0xFF; // the calibration type, availability of BLK 300, 310, 320, 390, 395 int8_t calibration_type = -1; // Init all the pointers to NULL. Most compilers should do this anyway. LinkedIDList * idListHead = NULL; LinkedIDList * idListCurrent = NULL; LinkedIDList * idListLast = NULL; MSRecord *msr = NULL; ContinuousSegment * segmentCurrent = NULL; hptime_t lastgap = 0; hptime_t hptimetol = 0; hptime_t nhptimetol = 0; long long data_offset; LinkedRecordList *recordHead = NULL; LinkedRecordList *recordPrevious = NULL; LinkedRecordList *recordCurrent = NULL; int datasize; int record_count = 0; // A negative verbosity suppresses as much as possible. if (verbose < 0) { ms_loginit(&empty_print, NULL, &empty_print, NULL); } else { ms_loginit(log_print, "INFO: ", diag_print, "ERROR: "); } if (header_byteorder >= 0) { // Enforce little endian. if (header_byteorder == 0) { MS_UNPACKHEADERBYTEORDER(0); } // Enforce big endian. else { MS_UNPACKHEADERBYTEORDER(1); } } else { MS_UNPACKHEADERBYTEORDER(-1); } // Read all records and save them in a linked list. while (offset < buflen) { msr = msr_init(NULL); if ( msr == NULL ) { ms_log (2, "readMSEEDBuffer(): Error initializing msr\n"); return NULL; } if (verbose > 1) { ms_log(0, "readMSEEDBuffer(): calling msr_parse with " "mseed+offset=%d+%d, buflen=%d, reclen=%d, dataflag=%d, verbose=%d\n", mseed, offset, buflen, reclen, dataflag, verbose); } // If the record length is given, make sure at least that amount of data is available. if (reclen != -1) { if (offset + reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } } // Otherwise assume the smallest possible record length and assure that enough // data is present. else { if (offset + MINRECLEN > buflen) { ms_log(1, "readMSEEDBuffer(): Last record only has %i byte(s) which " "is not enough to constitute a full SEED record. Corrupt data? " "Record will be skipped.\n", buflen - offset); msr_free(&msr); break; } } // Skip empty or noise records. if (OBSPY_ISVALIDBLANK(mseed + offset)) { offset += MINRECLEN; continue; } // Pass (buflen - offset) because msr_parse() expects only a single record. This // way libmseed can take care to not overstep bounds. // Return values: // 0 : Success, populates the supplied MSRecord. // >0 : Data record detected but not enough data is present, the // return value is a hint of how many more bytes are needed. // <0 : libmseed error code (listed in libmseed.h) is returned. retcode = msr_parse ((mseed+offset), buflen - offset, &msr, reclen, dataflag, verbose); // Handle error. if (retcode < 0) { log_error(retcode, offset); msr_free(&msr); break; } // msr_parse() returns > 0 if a data record has been detected but the buffer either has not enough // data (this cannot happen with ObsPy's logic) or the last record has no Blockette 1000 and it cannot // determine the record length because there is no next record (this can happen in ObsPy) - handle that // case by just calling msr_parse() with an explicit record length set. else if ( retcode > 0 && retcode < (buflen - offset)) { // Check if the remaining bytes can exactly make up a record length. int r_bytes = buflen - offset; float exp = log10((float)r_bytes) / log10(2.0); if ((fmodf(exp, 1.0) < 0.0000001) && ((int)roundf_(exp) >= 7) && ((int)roundf_(exp) <= 256)) { retcode = msr_parse((mseed + offset), buflen - offset, &msr, r_bytes, dataflag, verbose); if ( retcode != 0 ) { log_error(retcode, offset); msr_free(&msr); break; } } else { msr_free(&msr); break; } } if (offset + msr->reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last msr->reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } // Test against selections if supplied if ( selections ) { char srcname[50]; hptime_t endtime; msr_srcname (msr, srcname, 1); endtime = msr_endtime (msr); if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) { // Add the record length for the next iteration offset += msr->reclen; // Free record. msr_free(&msr); continue; } } record_count += 1; recordCurrent = lrl_init (); // Append to linked record list if one exists. if ( recordHead != NULL ) { recordPrevious->next = recordCurrent; recordCurrent->previous = recordPrevious; recordCurrent->next = NULL; recordPrevious = recordCurrent; } // Otherwise create a new one. else { recordHead = recordCurrent; recordCurrent->previous = NULL; recordPrevious = recordCurrent; } recordCurrent->record = msr; // Figure out if the byte-order of the data has to be swapped. swapflag = 0; // If blockette 1000 is present, use it. if ( msr->Blkt1000 != 0) { /* If BE host and LE data need swapping */ if ( bigendianhost && msr->byteorder == 0 ) { swapflag = 1; } /* If LE host and BE data (or bad byte order value) need swapping */ if ( !bigendianhost && msr->byteorder > 0 ) { swapflag = 1; } } // Otherwise assume the data has the same byte order as the header. // This needs to be done on the raw header bytes as libmseed only returns // header fields in the native byte order. else { unsigned char* _t = (unsigned char*)mseed + offset + 20; unsigned int year = _t[0] | _t[1] << 8; unsigned int day = _t[2] | _t[3] << 8; // Swap data if header needs to be swapped. if (!MS_ISVALIDYEARDAY(year, day)) { swapflag = 1; } } // Actually unpack the data if the flag is not set and if the data // offset is valid. if ((unpack_data != 0) && (msr->fsdh->data_offset >= 48) && (msr->fsdh->data_offset < msr->reclen) && (msr->samplecnt > 0)) { retval = msr_unpack_data (msr, swapflag, verbose); } if ( retval > 0 ) { msr->numsamples = retval; } if ( msr->fsdh->start_time.fract > 9999 ) { ms_log(1, "readMSEEDBuffer(): Record with offset=%d has a " "fractional second (.0001 seconds) of %d. This is not " "strictly valid but will be interpreted as one or more " "additional seconds.", offset, msr->fsdh->start_time.fract); } // Add the record length for the next iteration offset += msr->reclen; } // Return empty id list if no records could be found. if (record_count == 0) { idListHead = lil_init(); return idListHead; } // All records that match the selection are now stored in a LinkedRecordList // that starts at recordHead. The next step is to sort them by matching ids // and then by time. recordCurrent = recordHead; while (recordCurrent != NULL) { // Check if the ID of the record is already available and if not create a // new one. // Start with the last id as it is most likely to be the correct one. idListCurrent = idListLast; while (idListCurrent != NULL) { if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 && strcmp(idListCurrent->station, recordCurrent->record->station) == 0 && strcmp(idListCurrent->location, recordCurrent->record->location) == 0 && strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 && idListCurrent->dataquality == recordCurrent->record->dataquality) { break; } else { idListCurrent = idListCurrent->previous; } } // Create a new id list if one is needed. if (idListCurrent == NULL) { idListCurrent = lil_init(); idListCurrent->previous = idListLast; if (idListLast != NULL) { idListLast->next = idListCurrent; } idListLast = idListCurrent; if (idListHead == NULL) { idListHead = idListCurrent; } // Set the IdList attributes. strcpy(idListCurrent->network, recordCurrent->record->network); strcpy(idListCurrent->station, recordCurrent->record->station); strcpy(idListCurrent->location, recordCurrent->record->location); strcpy(idListCurrent->channel, recordCurrent->record->channel); idListCurrent->dataquality = recordCurrent->record->dataquality; } // Now check if the current record fits exactly to the end of the last // segment of the current id. If not create a new segment. Therefore // if records with the same id are in wrong order a new segment will be // created. This is on purpose. segmentCurrent = idListCurrent->lastSegment; if (segmentCurrent != NULL) { hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta); nhptimetol = ( hptimetol ) ? -hptimetol : 0; lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta; } if (details == 1) { /* extract information on calibration BLKs */ calibration_type = -1; if (recordCurrent->record->blkts) { BlktLink *cur_blkt = recordCurrent->record->blkts; while (cur_blkt) { switch (cur_blkt->blkt_type) { case 300: calibration_type = 1; break; case 310: calibration_type = 2; break; case 320: calibration_type = 3; break; case 390: calibration_type = 4; break; case 395: calibration_type = -2; break; default: break; } cur_blkt = cur_blkt->next; } } /* extract information based on timing quality */ timing_qual = 0xFF; if (recordCurrent->record->Blkt1001 != 0) { timing_qual = recordCurrent->record->Blkt1001->timing_qual; } } if ( segmentCurrent != NULL && // This is important for zero data record coupled with not unpacking // the data. It needs to be split in two places: Before the zero data // record and after it. recordCurrent->record->samplecnt > 0 && segmentCurrent->samplecnt > 0 && segmentCurrent->sampletype == recordCurrent->record->sampletype && // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) && // Check if the times are within the time tolerance lastgap <= hptimetol && lastgap >= nhptimetol && segmentCurrent->timing_qual == timing_qual && segmentCurrent->calibration_type == calibration_type) { recordCurrent->previous = segmentCurrent->lastRecord; segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent; segmentCurrent->samplecnt += recordCurrent->record->samplecnt; segmentCurrent->endtime = msr_endtime(recordCurrent->record); } // Otherwise create a new segment and add the current record. else { segmentCurrent = seg_init(); segmentCurrent->previous = idListCurrent->lastSegment; if (idListCurrent->lastSegment != NULL) { idListCurrent->lastSegment->next = segmentCurrent; } else { idListCurrent->firstSegment = segmentCurrent; } idListCurrent->lastSegment = segmentCurrent; segmentCurrent->starttime = recordCurrent->record->starttime; segmentCurrent->endtime = msr_endtime(recordCurrent->record); segmentCurrent->samprate = recordCurrent->record->samprate; segmentCurrent->sampletype = recordCurrent->record->sampletype; segmentCurrent->samplecnt = recordCurrent->record->samplecnt; // Calculate high-precision sample period segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ? (HPTMODULUS / recordCurrent->record->samprate) : 0.0); segmentCurrent->timing_qual = timing_qual; segmentCurrent->calibration_type = calibration_type; segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent; recordCurrent->previous = NULL; } recordPrevious = recordCurrent->next; recordCurrent->next = NULL; recordCurrent = recordPrevious; } // Now loop over all segments, combine the records and free the msr // structures. idListCurrent = idListHead; while (idListCurrent != NULL) { segmentCurrent = idListCurrent->firstSegment; while (segmentCurrent != NULL) { if (segmentCurrent->datasamples) { free(segmentCurrent->datasamples); } // Allocate data via a callback function. if (unpack_data != 0) { segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype); } // Loop over all records, write the data to the buffer and free the msr structures. recordCurrent = segmentCurrent->firstRecord; data_offset = (long long)(segmentCurrent->datasamples); while (recordCurrent != NULL) { datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype); memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize); // Free the record. msr_free(&(recordCurrent->record)); // Increase the data_offset and the record. data_offset += (long long)datasize; recordCurrent = recordCurrent->next; } segmentCurrent = segmentCurrent->next; } idListCurrent = idListCurrent->next; } return idListHead; }
// Function that reads from a MiniSEED binary file from a char buffer and // returns a LinkedIDList. LinkedIDList * readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag unpack_data, int reclen, flag verbose, flag details, int header_byteorder, long (*allocData) (int, char), void (*diag_print) (char*), void (*log_print) (char*)) { int retcode = 0; int retval = 0; flag swapflag = 0; // current offset of mseed char pointer int offset = 0; // Unpack without reading the data first flag dataflag = 0; // the timing_qual of BLK 1001 uint8_t timing_qual = 0xFF; // the calibration type, availability of BLK 300, 310, 320, 390, 395 int8_t calibration_type = -1; // Init all the pointers to NULL. Most compilers should do this anyway. LinkedIDList * idListHead = NULL; LinkedIDList * idListCurrent = NULL; LinkedIDList * idListLast = NULL; MSRecord *msr = NULL; ContinuousSegment * segmentCurrent = NULL; hptime_t lastgap = 0; hptime_t hptimetol = 0; hptime_t nhptimetol = 0; long data_offset; LinkedRecordList *recordHead = NULL; LinkedRecordList *recordPrevious = NULL; LinkedRecordList *recordCurrent = NULL; int datasize; int record_count = 0; // A negative verbosity suppressed as much as possible. if (verbose < 0) { ms_loginit(&empty_print, NULL, &empty_print, NULL); } else { ms_loginit(log_print, "INFO: ", diag_print, "ERROR: "); } if (header_byteorder >= 0) { // Enforce little endian. if (header_byteorder == 0) { MS_UNPACKHEADERBYTEORDER(0); } // Enforce big endian. else { MS_UNPACKHEADERBYTEORDER(1); } } else { MS_UNPACKHEADERBYTEORDER(-1); } // // Read all records and save them in a linked list. // while (offset < buflen) { msr = msr_init(NULL); if ( msr == NULL ) { ms_log (2, "readMSEEDBuffer(): Error initializing msr\n"); return NULL; } if (verbose > 1) { ms_log(0, "readMSEEDBuffer(): calling msr_parse with " "mseed+offset=%d+%d, buflen=%d, reclen=%d, dataflag=%d, verbose=%d\n", mseed, offset, buflen, reclen, dataflag, verbose); } // If the record length is given, make sure at least that amount of data is available. if (reclen != -1) { if (offset + reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } } // Otherwise assume the smallest possible record length and assure that enough // data is present. else { if (offset + 256 > buflen) { ms_log(1, "readMSEEDBuffer(): Last record only has %i byte(s) which " "is not enough to constitute a full SEED record. Corrupt data? " "Record will be skipped.\n", buflen - offset); msr_free(&msr); break; } } // Pass (buflen - offset) because msr_parse() expects only a single record. This // way libmseed can take care to not overstep bounds. retcode = msr_parse ( (mseed+offset), buflen - offset, &msr, reclen, dataflag, verbose); if (retcode != MS_NOERROR) { switch ( retcode ) { case MS_ENDOFFILE: ms_log(1, "readMSEEDBuffer(): Unexpected end of file when " "parsing record starting at offset %d. The rest " "of the file will not be read.\n", offset); break; case MS_GENERROR: ms_log(1, "readMSEEDBuffer(): Generic error when parsing " "record starting at offset %d. The rest of the " "file will not be read.\n", offset); break; case MS_NOTSEED: ms_log(1, "readMSEEDBuffer(): Record starting at offset " "%d is not valid SEED. The rest of the file " "will not be read.\n", offset); break; case MS_WRONGLENGTH: ms_log(1, "readMSEEDBuffer(): Length of data read was not " "correct when parsing record starting at " "offset %d. The rest of the file will not be " "read.\n", offset); break; case MS_OUTOFRANGE: ms_log(1, "readMSEEDBuffer(): SEED record length out of " "range for record starting at offset %d. The " "rest of the file will not be read.\n", offset); break; case MS_UNKNOWNFORMAT: ms_log(1, "readMSEEDBuffer(): Unknown data encoding " "format for record starting at offset %d. The " "rest of the file will not be read.\n", offset); break; case MS_STBADCOMPFLAG: ms_log(1, "readMSEEDBuffer(): Invalid STEIM compression " "flag(s) in record starting at offset %d. The " "rest of the file will not be read.\n", offset); break; default: ms_log(1, "readMSEEDBuffer(): Unknown error '%d' in " "record starting at offset %d. The rest of the " "file will not be read.\n", retcode, offset); break; } msr_free(&msr); break; } if (offset + msr->reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last msr->reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } // Test against selections if supplied if ( selections ) { char srcname[50]; hptime_t endtime; msr_srcname (msr, srcname, 1); endtime = msr_endtime (msr); if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) { // Add the record length for the next iteration offset += msr->reclen; // Free record. msr_free(&msr); continue; } } record_count += 1; recordCurrent = lrl_init (); // Append to linked record list if one exists. if ( recordHead != NULL ) { recordPrevious->next = recordCurrent; recordCurrent->previous = recordPrevious; recordCurrent->next = NULL; recordPrevious = recordCurrent; } // Otherwise create a new one. else { recordHead = recordCurrent; recordCurrent->previous = NULL; recordPrevious = recordCurrent; } recordCurrent->record = msr; // Determine the byte order swapflag only for the very first record. // The byte order should not change within the file. // XXX: Maybe check for every record? if (swapflag <= 0) { // Returns 0 if the host is little endian, otherwise 1. flag bigendianhost = ms_bigendianhost(); // Set the swapbyteflag if it is needed. if ( msr->Blkt1000 != 0) { /* If BE host and LE data need swapping */ if ( bigendianhost && msr->byteorder == 0 ) { swapflag = 1; } /* If LE host and BE data (or bad byte order value) need swapping */ if ( !bigendianhost && msr->byteorder > 0 ) { swapflag = 1; } } } // Actually unpack the data if the flag is not set. if (unpack_data != 0) { retval = msr_unpack_data (msr, swapflag, verbose); } if ( retval > 0 ) { msr->numsamples = retval; } // Add the record length for the next iteration offset += msr->reclen; } // Return empty id list if no records could be found. if (record_count == 0) { idListHead = lil_init(); return idListHead; } // All records that match the selection are now stored in a LinkedRecordList // that starts at recordHead. The next step is to sort them by matching ids // and then by time. recordCurrent = recordHead; while (recordCurrent != NULL) { // Check if the ID of the record is already available and if not create a // new one. // Start with the last id as it is most likely to be the correct one. idListCurrent = idListLast; while (idListCurrent != NULL) { if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 && strcmp(idListCurrent->station, recordCurrent->record->station) == 0 && strcmp(idListCurrent->location, recordCurrent->record->location) == 0 && strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 && idListCurrent->dataquality == recordCurrent->record->dataquality) { break; } else { idListCurrent = idListCurrent->previous; } } // Create a new id list if one is needed. if (idListCurrent == NULL) { idListCurrent = lil_init(); idListCurrent->previous = idListLast; if (idListLast != NULL) { idListLast->next = idListCurrent; } idListLast = idListCurrent; if (idListHead == NULL) { idListHead = idListCurrent; } // Set the IdList attributes. strcpy(idListCurrent->network, recordCurrent->record->network); strcpy(idListCurrent->station, recordCurrent->record->station); strcpy(idListCurrent->location, recordCurrent->record->location); strcpy(idListCurrent->channel, recordCurrent->record->channel); idListCurrent->dataquality = recordCurrent->record->dataquality; } // Now check if the current record fits exactly to the end of the last // segment of the current id. If not create a new segment. Therefore // if records with the same id are in wrong order a new segment will be // created. This is on purpose. segmentCurrent = idListCurrent->lastSegment; if (segmentCurrent != NULL) { hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta); nhptimetol = ( hptimetol ) ? -hptimetol : 0; lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta; } if (details == 1) { /* extract information on calibration BLKs */ calibration_type = -1; if (recordCurrent->record->blkts) { BlktLink *cur_blkt = recordCurrent->record->blkts; while (cur_blkt) { switch (cur_blkt->blkt_type) { case 300: calibration_type = 1; break; case 310: calibration_type = 2; break; case 320: calibration_type = 3; break; case 390: calibration_type = 4; break; case 395: calibration_type = -2; break; default: break; } cur_blkt = cur_blkt->next; } } /* extract information based on timing quality */ timing_qual = 0xFF; if (recordCurrent->record->Blkt1001 != 0) { timing_qual = recordCurrent->record->Blkt1001->timing_qual; } } if ( segmentCurrent != NULL && segmentCurrent->sampletype == recordCurrent->record->sampletype && // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) && // Check if the times are within the time tolerance lastgap <= hptimetol && lastgap >= nhptimetol && segmentCurrent->timing_qual == timing_qual && segmentCurrent->calibration_type == calibration_type) { recordCurrent->previous = segmentCurrent->lastRecord; segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent; segmentCurrent->samplecnt += recordCurrent->record->samplecnt; segmentCurrent->endtime = msr_endtime(recordCurrent->record); } // Otherwise create a new segment and add the current record. else { segmentCurrent = seg_init(); segmentCurrent->previous = idListCurrent->lastSegment; if (idListCurrent->lastSegment != NULL) { idListCurrent->lastSegment->next = segmentCurrent; } else { idListCurrent->firstSegment = segmentCurrent; } idListCurrent->lastSegment = segmentCurrent; segmentCurrent->starttime = recordCurrent->record->starttime; segmentCurrent->endtime = msr_endtime(recordCurrent->record); segmentCurrent->samprate = recordCurrent->record->samprate; segmentCurrent->sampletype = recordCurrent->record->sampletype; segmentCurrent->samplecnt = recordCurrent->record->samplecnt; // Calculate high-precision sample period segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ? (HPTMODULUS / recordCurrent->record->samprate) : 0.0); segmentCurrent->timing_qual = timing_qual; segmentCurrent->calibration_type = calibration_type; segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent; recordCurrent->previous = NULL; } recordPrevious = recordCurrent->next; recordCurrent->next = NULL; recordCurrent = recordPrevious; } // Now loop over all segments, combine the records and free the msr // structures. idListCurrent = idListHead; while (idListCurrent != NULL) { segmentCurrent = idListCurrent->firstSegment; while (segmentCurrent != NULL) { if (segmentCurrent->datasamples) { free(segmentCurrent->datasamples); } // Allocate data via a callback function. if (unpack_data != 0) { segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype); } // Loop over all records, write the data to the buffer and free the msr structures. recordCurrent = segmentCurrent->firstRecord; data_offset = (long)(segmentCurrent->datasamples); while (recordCurrent != NULL) { datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype); memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize); // Free the record. msr_free(&(recordCurrent->record)); // Increase the data_offset and the record. data_offset += (long)datasize; recordCurrent = recordCurrent->next; } segmentCurrent = segmentCurrent->next; } idListCurrent = idListCurrent->next; } return idListHead; }
/*************************************************************************** * convertsamples: * * Convert samples to type needed for the specified pack encoding. * * Returns 0 on success, and -1 on failure ***************************************************************************/ static int convertsamples (MSRecord *msr, int packencoding) { char encodingtype; int32_t *idata; float *fdata; double *ddata; int idx; if ( ! msr ) { ms_log (2, "convertsamples: Error, no MSRecord specified!\n"); return -1; } /* Determine sample type needed for pack encoding */ switch (packencoding) { case DE_ASCII: encodingtype = 'a'; break; case DE_INT16: case DE_INT32: case DE_STEIM1: case DE_STEIM2: encodingtype = 'i'; break; case DE_FLOAT32: encodingtype = 'f'; break; case DE_FLOAT64: encodingtype = 'd'; break; default: encodingtype = msr->encoding; break; } idata = (int32_t *) msr->datasamples; fdata = (float *) msr->datasamples; ddata = (double *) msr->datasamples; /* Convert sample type if needed */ if ( msr->sampletype != encodingtype ) { if ( msr->sampletype == 'a' || encodingtype == 'a' ) { ms_log (2, "Error, cannot convert ASCII samples to/from numeric type\n"); return -1; } /* Convert to integers */ else if ( encodingtype == 'i' ) { if ( msr->sampletype == 'f' ) /* Convert floats to integers with simple rounding */ { for (idx = 0; idx < msr->numsamples; idx++) { /* Check for loss of sub-integer */ if ( (fdata[idx] - (int32_t)fdata[idx]) > 0.000001 ) { ms_log (2, "Warning, Loss of precision when converting floats to integers, loss: %g\n", (fdata[idx] - (int32_t)fdata[idx])); return -1; } idata[idx] = (int32_t) (fdata[idx] + 0.5); } } else if ( msr->sampletype == 'd' ) /* Convert doubles to integers with simple rounding */ { for (idx = 0; idx < msr->numsamples; idx++) { /* Check for loss of sub-integer */ if ( (ddata[idx] - (int32_t)ddata[idx]) > 0.000001 ) { ms_log (2, "Warning, Loss of precision when converting doubles to integers, loss: %g\n", (ddata[idx] - (int32_t)ddata[idx])); return -1; } idata[idx] = (int32_t) (ddata[idx] + 0.5); } /* Reallocate buffer for reduced size needed */ if ( ! (msr->datasamples = realloc (msr->datasamples,(size_t)(msr->numsamples * sizeof(int32_t)))) ) { ms_log (2, "Error, cannot re-allocate buffer for sample conversion\n"); return -1; } } msr->sampletype = 'i'; } /* Convert to floats */ else if ( encodingtype == 'f' ) { if ( msr->sampletype == 'i' ) /* Convert integers to floats */ { for (idx = 0; idx < msr->numsamples; idx++) fdata[idx] = (float) idata[idx]; } else if ( msr->sampletype == 'd' ) /* Convert doubles to floats */ { for (idx = 0; idx < msr->numsamples; idx++) fdata[idx] = (float) ddata[idx]; /* Reallocate buffer for reduced size needed */ if ( ! (msr->datasamples = realloc (msr->datasamples, (size_t)(msr->numsamples * sizeof(float)))) ) { ms_log (2, "Error, cannot re-allocate buffer for sample conversion\n"); return -1; } } msr->sampletype = 'f'; } /* Convert to doubles */ else if ( encodingtype == 'd' ) { if ( ! (ddata = (double *) malloc ((size_t)(msr->numsamples * sizeof(double)))) ) { ms_log (2, "Error, cannot allocate buffer for sample conversion to doubles\n"); return -1; } if ( msr->sampletype == 'i' ) /* Convert integers to doubles */ { for (idx = 0; idx < msr->numsamples; idx++) ddata[idx] = (double) idata[idx]; free (idata); } else if ( msr->sampletype == 'f' ) /* Convert floats to doubles */ { for (idx = 0; idx < msr->numsamples; idx++) ddata[idx] = (double) fdata[idx]; free (fdata); } msr->datasamples = ddata; msr->sampletype = 'd'; } } return 0; } /* End of convertsamples() */
/*************************************************************************** * msr_pack_header: * * Pack data header/blockettes into the SEED record at * MSRecord->record. Unlike msr_pack no default values are applied, * the header structures are expected to be self describing and no * Blockette 1000 will be added. This routine is only useful for * re-packing a record header. * * Returns the header length in bytes on success and -1 on error. ***************************************************************************/ int msr_pack_header ( MSRecord *msr, flag normalize, flag verbose ) { char srcname[50]; char *envvariable; flag headerswapflag = 0; int headerlen; int maxheaderlen; if ( ! msr ) return -1; /* Generate source name for MSRecord */ if ( msr_srcname (msr, srcname, 1) == NULL ) { ms_log (2, "msr_unpack_data(): Cannot generate srcname\n"); return MS_GENERROR; } /* Set shared srcname pointer to source name */ PACK_SRCNAME = &srcname[0]; /* Read possible environmental variables that force byteorder */ if ( packheaderbyteorder == -2 ) { if ( (envvariable = getenv("PACK_HEADER_BYTEORDER")) ) { if ( *envvariable != '0' && *envvariable != '1' ) { ms_log (2, "Environment variable PACK_HEADER_BYTEORDER must be set to '0' or '1'\n"); return -1; } else if ( *envvariable == '0' ) { packheaderbyteorder = 0; if ( verbose > 2 ) ms_log (1, "PACK_HEADER_BYTEORDER=0, packing little-endian header\n"); } else { packheaderbyteorder = 1; if ( verbose > 2 ) ms_log (1, "PACK_HEADER_BYTEORDER=1, packing big-endian header\n"); } } else { packheaderbyteorder = -1; } } if ( msr->reclen < MINRECLEN || msr->reclen > MAXRECLEN ) { ms_log (2, "msr_pack_header(%s): record length is out of range: %d\n", PACK_SRCNAME, msr->reclen); return -1; } if ( msr->byteorder != 0 && msr->byteorder != 1 ) { ms_log (2, "msr_pack_header(%s): byte order is not defined correctly: %d\n", PACK_SRCNAME, msr->byteorder); return -1; } if ( msr->fsdh ) { maxheaderlen = (msr->fsdh->data_offset > 0) ? msr->fsdh->data_offset : msr->reclen; } else { maxheaderlen = msr->reclen; } /* Check to see if byte swapping is needed */ if ( msr->byteorder != ms_bigendianhost() ) headerswapflag = 1; /* Check if byte order is forced */ if ( packheaderbyteorder >= 0 ) { headerswapflag = ( msr->byteorder != packheaderbyteorder ) ? 1: 0; } if ( verbose > 2 ) { if ( headerswapflag ) ms_log (1, "%s: Byte swapping needed for packing of header\n", PACK_SRCNAME); else ms_log (1, "%s: Byte swapping NOT needed for packing of header\n", PACK_SRCNAME); } headerlen = msr_pack_header_raw (msr, msr->record, maxheaderlen, headerswapflag, normalize, NULL, verbose); return headerlen; } /* End of msr_pack_header() */
int main (int argc, char **argv) { MSRecord *msr = 0; MSTraceGroup *mstg = 0; MSTrace *mst; int retcode; int64_t packedsamples; int64_t packedrecords; int lastrecord; int iseqnum = 1; #ifndef WIN32 /* Signal handling, use POSIX calls with standardized semantics */ struct sigaction sa; sa.sa_flags = SA_RESTART; sigemptyset (&sa.sa_mask); sa.sa_handler = term_handler; sigaction (SIGINT, &sa, NULL); sigaction (SIGQUIT, &sa, NULL); sigaction (SIGTERM, &sa, NULL); sa.sa_handler = SIG_IGN; sigaction (SIGHUP, &sa, NULL); sigaction (SIGPIPE, &sa, NULL); #endif /* Process given parameters (command line and parameter file) */ if (parameter_proc (argc, argv) < 0) return -1; /* Setup input encoding format if specified */ if ( encodingstr ) { int inputencoding = strtoul (encodingstr, NULL, 10); if ( inputencoding == 0 && errno == EINVAL ) { ms_log (2, "Error parsing input encoding format: %s\n", encodingstr); return -1; } MS_UNPACKENCODINGFORMAT (inputencoding); } /* Init MSTraceGroup */ mstg = mst_initgroup (mstg); /* Loop over the input file */ while ( (retcode = ms_readmsr (&msr, inputfile, reclen, NULL, &lastrecord, 1, 1, verbose)) == MS_NOERROR ) { msr_print (msr, ppackets); /* Convert sample type as needed for packencoding */ if ( packencoding >= 0 && packencoding != msr->encoding ) { if ( convertsamples (msr, packencoding) ) { ms_log (2, "Error converting samples for encoding %d\n", packencoding); break; } } if ( packreclen >= 0 ) msr->reclen = packreclen; else packreclen = msr->reclen; if ( packencoding >= 0 ) msr->encoding = packencoding; else packencoding = msr->encoding; if ( byteorder >= 0 ) msr->byteorder = byteorder; else byteorder = msr->byteorder; /* After unpacking the record, the start time in msr->starttime is a potentially corrected start time, if correction has been applied make sure the correction bit flag is set as it will be used as a packing template. */ if ( msr->fsdh->time_correct && ! (msr->fsdh->act_flags & 0x02) ) { ms_log (1, "Setting time correction applied flag for %s_%s_%s_%s\n", msr->network, msr->station, msr->location, msr->channel); msr->fsdh->act_flags |= 0x02; } /* Replace network code */ if ( netcode ) strncpy (msr->network, netcode, sizeof(msr->network)); /* If no samples in the record just pack the header */ if ( outfile && msr->numsamples == 0 ) { msr_pack_header (msr, 1, verbose); record_handler (msr->record, msr->reclen, NULL); } /* Pack each record individually */ else if ( outfile && ! tracepack ) { msr->sequence_number = iseqnum; packedrecords = msr_pack (msr, &record_handler, NULL, &packedsamples, 1, verbose); if ( packedrecords == -1 ) ms_log (2, "Cannot pack records\n"); else ms_log (1, "Packed %d records\n", packedrecords); iseqnum = msr->sequence_number; } /* Pack records from a MSTraceGroup */ else if ( outfile && tracepack ) { mst = mst_addmsrtogroup (mstg, msr, 0, -1.0, -1.0); if ( ! mst ) { ms_log (2, "Error adding MSRecord to MStrace!\n"); break; } /* Reset sequence number and free previous template */ if ( mst->prvtptr ) { MSRecord *tmsr = (MSRecord *) mst->prvtptr; /* Retain sequence number from previous template */ msr->sequence_number = tmsr->sequence_number; msr_free (&tmsr); } else { msr->sequence_number = 1; } /* Copy MSRecord and store as template */ mst->prvtptr = msr_duplicate (msr, 0); if ( ! mst->prvtptr ) { ms_log (2, "Error duplicating MSRecord for template!\n"); break; } /* Pack traces based on selected method */ packedrecords = 0; if ( tracepack == 1 ) { mst = mstg->traces; while ( mst ) { packedrecords += mst_pack (mst, &record_handler, NULL, packreclen, packencoding, byteorder, &packedsamples, 0, verbose, (MSRecord *)mst->prvtptr); mst = mst->next; } ms_log (1, "Packed %d records\n", packedrecords); } if ( tracepack == 2 && lastrecord ) { mst = mstg->traces; while ( mst ) { packedrecords += mst_pack (mst, &record_handler, NULL, packreclen, packencoding, byteorder, &packedsamples, 1, verbose, (MSRecord *)mst->prvtptr); mst = mst->next; } ms_log (1, "Packed %d records\n", packedrecords); } } } /* Make sure buffer of input data is flushed */ packedrecords = 0; if ( tracepack ) { mst = mstg->traces; while ( mst ) { packedrecords += mst_pack (mst, &record_handler, NULL, packreclen, packencoding, byteorder, &packedsamples, 1, verbose, (MSRecord *)mst->prvtptr); mst = mst->next; } if ( packedrecords ) ms_log (1, "Packed %d records\n", packedrecords); } if ( retcode != MS_ENDOFFILE ) ms_log (2, "Error reading %s: %s\n", inputfile, ms_errorstr(retcode)); /* Make sure everything is cleaned up */ ms_readmsr (&msr, NULL, 0, NULL, NULL, 0, 0, 0); mst_freegroup (&mstg); if ( outfile ) fclose (outfile); return 0; } /* End of main() */
/*************************************************************************** * msr_pack: * * Pack data into SEED data records. Using the record header values * in the MSRecord as a template the common header fields are packed * into the record header, blockettes in the blockettes chain are * packed and data samples are packed in the encoding format indicated * by the MSRecord->encoding field. A Blockette 1000 will be added if * one is not present. * * The MSRecord->datasamples array and MSRecord->numsamples value will * not be changed by this routine. It is the responsibility of the * calling routine to adjust the data buffer if desired. * * As each record is filled and finished they are passed to * record_handler which expects 1) a char * to the record, 2) the * length of the record and 3) a pointer supplied by the original * caller containing optional private data (handlerdata). It is the * responsibility of record_handler to process the record, the memory * will be re-used or freed when record_handler returns. * * If the flush flag != 0 all of the data will be packed into data * records even though the last one will probably not be filled. * * Default values are: data record & quality indicator = 'D', record * length = 4096, encoding = 11 (Steim2) and byteorder = 1 (MSBF). * The defaults are triggered when the the msr->dataquality is 0 or * msr->reclen, msr->encoding and msr->byteorder are -1 respectively. * * Returns the number of records created on success and -1 on error. ***************************************************************************/ int msr_pack ( MSRecord * msr, void (*record_handler) (char *, int, void *), void *handlerdata, int64_t *packedsamples, flag flush, flag verbose ) { uint16_t *HPnumsamples; uint16_t *HPdataoffset; struct blkt_1001_s *HPblkt1001 = NULL; char *rawrec; char *envvariable; char srcname[50]; flag headerswapflag = 0; flag dataswapflag = 0; flag packret; int samplesize; int headerlen; int dataoffset; int maxdatabytes; int maxsamples; int recordcnt = 0; int packsamples, packoffset; int64_t totalpackedsamples; hptime_t segstarttime; if ( ! msr ) return -1; if ( ! record_handler ) { ms_log (2, "msr_pack(): record_handler() function pointer not set!\n"); return -1; } /* Allocate stream processing state space if needed */ if ( ! msr->ststate ) { msr->ststate = (StreamState *) malloc (sizeof(StreamState)); if ( ! msr->ststate ) { ms_log (2, "msr_pack(): Could not allocate memory for StreamState\n"); return -1; } memset (msr->ststate, 0, sizeof(StreamState)); } /* Generate source name for MSRecord */ if ( msr_srcname (msr, srcname, 1) == NULL ) { ms_log (2, "msr_unpack_data(): Cannot generate srcname\n"); return MS_GENERROR; } /* Set shared srcname pointer to source name */ PACK_SRCNAME = &srcname[0]; /* Track original segment start time for new start time calculation */ segstarttime = msr->starttime; /* Read possible environmental variables that force byteorder */ if ( packheaderbyteorder == -2 ) { if ( (envvariable = getenv("PACK_HEADER_BYTEORDER")) ) { if ( *envvariable != '0' && *envvariable != '1' ) { ms_log (2, "Environment variable PACK_HEADER_BYTEORDER must be set to '0' or '1'\n"); return -1; } else if ( *envvariable == '0' ) { packheaderbyteorder = 0; if ( verbose > 2 ) ms_log (1, "PACK_HEADER_BYTEORDER=0, packing little-endian header\n"); } else { packheaderbyteorder = 1; if ( verbose > 2 ) ms_log (1, "PACK_HEADER_BYTEORDER=1, packing big-endian header\n"); } } else { packheaderbyteorder = -1; } } if ( packdatabyteorder == -2 ) { if ( (envvariable = getenv("PACK_DATA_BYTEORDER")) ) { if ( *envvariable != '0' && *envvariable != '1' ) { ms_log (2, "Environment variable PACK_DATA_BYTEORDER must be set to '0' or '1'\n"); return -1; } else if ( *envvariable == '0' ) { packdatabyteorder = 0; if ( verbose > 2 ) ms_log (1, "PACK_DATA_BYTEORDER=0, packing little-endian data samples\n"); } else { packdatabyteorder = 1; if ( verbose > 2 ) ms_log (1, "PACK_DATA_BYTEORDER=1, packing big-endian data samples\n"); } } else { packdatabyteorder = -1; } } /* Set default indicator, record length, byte order and encoding if needed */ if ( msr->dataquality == 0 ) msr->dataquality = 'D'; if ( msr->reclen == -1 ) msr->reclen = 4096; if ( msr->byteorder == -1 ) msr->byteorder = 1; if ( msr->encoding == -1 ) msr->encoding = DE_STEIM2; /* Cleanup/reset sequence number */ if ( msr->sequence_number <= 0 || msr->sequence_number > 999999) msr->sequence_number = 1; if ( msr->reclen < MINRECLEN || msr->reclen > MAXRECLEN ) { ms_log (2, "msr_pack(%s): Record length is out of range: %d\n", PACK_SRCNAME, msr->reclen); return -1; } if ( msr->numsamples <= 0 ) { ms_log (2, "msr_pack(%s): No samples to pack\n", PACK_SRCNAME); return -1; } samplesize = ms_samplesize (msr->sampletype); if ( ! samplesize ) { ms_log (2, "msr_pack(%s): Unknown sample type '%c'\n", PACK_SRCNAME, msr->sampletype); return -1; } /* Sanity check for msr/quality indicator */ if ( ! MS_ISDATAINDICATOR(msr->dataquality) ) { ms_log (2, "msr_pack(%s): Record header & quality indicator unrecognized: '%c'\n", PACK_SRCNAME, msr->dataquality); ms_log (2, "msr_pack(%s): Packing failed.\n", PACK_SRCNAME); return -1; } /* Allocate space for data record */ rawrec = (char *) malloc (msr->reclen); if ( rawrec == NULL ) { ms_log (2, "msr_pack(%s): Cannot allocate memory\n", PACK_SRCNAME); return -1; } /* Set header pointers to known offsets into FSDH */ HPnumsamples = (uint16_t *) (rawrec + 30); HPdataoffset = (uint16_t *) (rawrec + 44); /* Check to see if byte swapping is needed */ if ( msr->byteorder != ms_bigendianhost() ) headerswapflag = dataswapflag = 1; /* Check if byte order is forced */ if ( packheaderbyteorder >= 0 ) { headerswapflag = ( msr->byteorder != packheaderbyteorder ) ? 1 : 0; } if ( packdatabyteorder >= 0 ) { dataswapflag = ( msr->byteorder != packdatabyteorder ) ? 1 : 0; } if ( verbose > 2 ) { if ( headerswapflag && dataswapflag ) ms_log (1, "%s: Byte swapping needed for packing of header and data samples\n", PACK_SRCNAME); else if ( headerswapflag ) ms_log (1, "%s: Byte swapping needed for packing of header\n", PACK_SRCNAME); else if ( dataswapflag ) ms_log (1, "%s: Byte swapping needed for packing of data samples\n", PACK_SRCNAME); else ms_log (1, "%s: Byte swapping NOT needed for packing\n", PACK_SRCNAME); } /* Add a blank 1000 Blockette if one is not present, the blockette values will be populated in msr_pack_header_raw()/msr_normalize_header() */ if ( ! msr->Blkt1000 ) { struct blkt_1000_s blkt1000; memset (&blkt1000, 0, sizeof (struct blkt_1000_s)); if ( verbose > 2 ) ms_log (1, "%s: Adding 1000 Blockette\n", PACK_SRCNAME); if ( ! msr_addblockette (msr, (char *) &blkt1000, sizeof(struct blkt_1000_s), 1000, 0) ) { ms_log (2, "msr_pack(%s): Error adding 1000 Blockette\n", PACK_SRCNAME); return -1; } } headerlen = msr_pack_header_raw (msr, rawrec, msr->reclen, headerswapflag, 1, &HPblkt1001, verbose); if ( headerlen == -1 ) { ms_log (2, "msr_pack(%s): Error packing header\n", PACK_SRCNAME); return -1; } /* Determine offset to encoded data */ if ( msr->encoding == DE_STEIM1 || msr->encoding == DE_STEIM2 ) { dataoffset = 64; while ( dataoffset < headerlen ) dataoffset += 64; /* Zero memory between blockettes and data if any */ memset (rawrec + headerlen, 0, dataoffset - headerlen); } else { dataoffset = headerlen; } *HPdataoffset = (uint16_t) dataoffset; if ( headerswapflag ) ms_gswap2 (HPdataoffset); /* Determine the max data bytes and sample count */ maxdatabytes = msr->reclen - dataoffset; if ( msr->encoding == DE_STEIM1 ) { maxsamples = (int) (maxdatabytes/64) * STEIM1_FRAME_MAX_SAMPLES; } else if ( msr->encoding == DE_STEIM2 ) { maxsamples = (int) (maxdatabytes/64) * STEIM2_FRAME_MAX_SAMPLES; } else { maxsamples = maxdatabytes / samplesize; } /* Pack samples into records */ *HPnumsamples = 0; totalpackedsamples = 0; if ( packedsamples ) *packedsamples = 0; packoffset = 0; while ( (msr->numsamples - totalpackedsamples) > maxsamples || flush ) { packret = msr_pack_data (rawrec + dataoffset, (char *) msr->datasamples + packoffset, (int)(msr->numsamples - totalpackedsamples), maxdatabytes, &packsamples, &msr->ststate->lastintsample, msr->ststate->comphistory, msr->sampletype, msr->encoding, dataswapflag, verbose); if ( packret ) { ms_log (2, "msr_pack(%s): Error packing record\n", PACK_SRCNAME); return -1; } packoffset += packsamples * samplesize; /* Update number of samples */ *HPnumsamples = (uint16_t) packsamples; if ( headerswapflag ) ms_gswap2 (HPnumsamples); if ( verbose > 0 ) ms_log (1, "%s: Packed %d samples\n", PACK_SRCNAME, packsamples); /* Send record to handler */ record_handler (rawrec, msr->reclen, handlerdata); totalpackedsamples += packsamples; if ( packedsamples ) *packedsamples = totalpackedsamples; msr->ststate->packedsamples += packsamples; /* Update record header for next record */ msr->sequence_number = ( msr->sequence_number >= 999999 ) ? 1 : msr->sequence_number + 1; if ( msr->samprate > 0 ) msr->starttime = segstarttime + (hptime_t)(totalpackedsamples / msr->samprate * HPTMODULUS + 0.5); msr_update_header (msr, rawrec, headerswapflag, HPblkt1001, verbose); recordcnt++; msr->ststate->packedrecords++; /* Set compression history flag for subsequent records (Steim encodings) */ if ( ! msr->ststate->comphistory ) msr->ststate->comphistory = 1; if ( totalpackedsamples >= msr->numsamples ) break; } if ( verbose > 2 ) ms_log (1, "%s: Packed %d total samples\n", PACK_SRCNAME, totalpackedsamples); free (rawrec); return recordcnt; } /* End of msr_pack() */
/************************************************************************ * msr_decode_steim1: * * Decode Steim1 encoded miniSEED data and place in supplied buffer * as 32-bit integers. * * Return number of samples in output buffer on success, -1 on error. ************************************************************************/ int msr_decode_steim1 (int32_t *input, int inputlength, int samplecount, int32_t *output, int outputlength, char *srcname, int swapflag) { int32_t *outputptr = output; /* Pointer to next output sample location */ uint32_t frame[16]; /* Frame, 16 x 32-bit quantities = 64 bytes */ int32_t X0 = 0; /* Forward integration constant, aka first sample */ int32_t Xn = 0; /* Reverse integration constant, aka last sample */ int maxframes = inputlength / 64; int frameidx; int startnibble; int nibble; int widx; int diffcount; int idx; union dword { int8_t d8[4]; int16_t d16[2]; int32_t d32; } * word; if (inputlength <= 0) return 0; if (!input || !output || outputlength <= 0 || maxframes <= 0) return -1; if (decodedebug) ms_log (1, "Decoding %d Steim1 frames, swapflag: %d, srcname: %s\n", maxframes, swapflag, (srcname) ? srcname : ""); for (frameidx = 0; frameidx < maxframes && samplecount > 0; frameidx++) { /* Copy frame, each is 16x32-bit quantities = 64 bytes */ memcpy (frame, input + (16 * frameidx), 64); /* Save forward integration constant (X0) and reverse integration constant (Xn) and set the starting nibble index depending on frame. */ if (frameidx == 0) { if (swapflag) { ms_gswap4a (&frame[1]); ms_gswap4a (&frame[2]); } X0 = frame[1]; Xn = frame[2]; startnibble = 3; /* First frame: skip nibbles, X0, and Xn */ if (decodedebug) ms_log (1, "Frame %d: X0=%d Xn=%d\n", frameidx, X0, Xn); } else { startnibble = 1; /* Subsequent frames: skip nibbles */ if (decodedebug) ms_log (1, "Frame %d\n", frameidx); } /* Swap 32-bit word containing the nibbles */ if (swapflag) ms_gswap4a (&frame[0]); /* Decode each 32-bit word according to nibble */ for (widx = startnibble; widx < 16 && samplecount > 0; widx++) { /* W0: the first 32-bit contains 16 x 2-bit nibbles for each word */ nibble = EXTRACTBITRANGE (frame[0], (30 - (2 * widx)), 2); word = (union dword *)&frame[widx]; diffcount = 0; switch (nibble) { case 0: /* 00: Special flag, no differences */ if (decodedebug) ms_log (1, " W%02d: 00=special\n", widx); break; case 1: /* 01: Four 1-byte differences */ diffcount = 4; if (decodedebug) ms_log (1, " W%02d: 01=4x8b %d %d %d %d\n", widx, word->d8[0], word->d8[1], word->d8[2], word->d8[3]); break; case 2: /* 10: Two 2-byte differences */ diffcount = 2; if (swapflag) { ms_gswap2a (&word->d16[0]); ms_gswap2a (&word->d16[1]); } if (decodedebug) ms_log (1, " W%02d: 10=2x16b %d %d\n", widx, word->d16[0], word->d16[1]); break; case 3: /* 11: One 4-byte difference */ diffcount = 1; if (swapflag) ms_gswap4a (&word->d32); if (decodedebug) ms_log (1, " W%02d: 11=1x32b %d\n", widx, word->d32); break; } /* Done with decoding 32-bit word based on nibble */ /* Apply accumulated differences to calculate output samples */ if (diffcount > 0) { for (idx = 0; idx < diffcount && samplecount > 0; idx++, outputptr++) { if (outputptr == output) /* Ignore first difference, instead store X0 */ *outputptr = X0; else if (diffcount == 4) /* Otherwise store difference from previous sample */ *outputptr = *(outputptr - 1) + word->d8[idx]; else if (diffcount == 2) *outputptr = *(outputptr - 1) + word->d16[idx]; else if (diffcount == 1) *outputptr = *(outputptr - 1) + word->d32; samplecount--; } } } /* Done looping over nibbles and 32-bit words */ } /* Done looping over frames */ /* Check data integrity by comparing last sample to Xn (reverse integration constant) */ if (outputptr != output && *(outputptr - 1) != Xn) { ms_log (1, "%s: Warning: Data integrity check for Steim1 failed, Last sample=%d, Xn=%d\n", srcname, *(outputptr - 1), Xn); } return (outputptr - output); } /* End of msr_decode_steim1() */
/*************************************************************************** * parameter_proc: * * Process the command line parameters. * * Returns 0 on success, and -1 on failure ***************************************************************************/ static int parameter_proc (int argcount, char **argvec) { int optind; /* Process all command line arguments */ for (optind = 1; optind < argcount; optind++) { if (strcmp (argvec[optind], "-V") == 0) { ms_log (1, "%s version: %s\n", PACKAGE, VERSION); exit (0); } else if (strcmp (argvec[optind], "-h") == 0) { usage(); exit (0); } else if (strncmp (argvec[optind], "-v", 2) == 0) { verbose += strspn (&argvec[optind][1], "v"); } else if (strncmp (argvec[optind], "-p", 2) == 0) { ppackets += strspn (&argvec[optind][1], "p"); } else if (strcmp (argvec[optind], "-a") == 0) { reclen = -1; } else if (strcmp (argvec[optind], "-i") == 0) { tracepack = 0; } else if (strcmp (argvec[optind], "-t") == 0) { tracepack = 2; } else if (strcmp (argvec[optind], "-r") == 0) { reclen = strtol (argvec[++optind], NULL, 10); } else if (strcmp (argvec[optind], "-e") == 0) { encodingstr = argvec[++optind]; } else if (strcmp (argvec[optind], "-R") == 0) { packreclen = strtol (argvec[++optind], NULL, 10); } else if (strcmp (argvec[optind], "-E") == 0) { packencoding = strtol (argvec[++optind], NULL, 10); } else if (strcmp (argvec[optind], "-b") == 0) { byteorder = strtol (argvec[++optind], NULL, 10); } else if (strcmp (argvec[optind], "-o") == 0) { if ( (outfile = fopen(argvec[++optind], "wb")) == NULL ) { ms_log (2, "Error opening output file: %s\n", argvec[++optind]); exit (0); } } else if (strncmp (argvec[optind], "-", 1) == 0 && strlen (argvec[optind]) > 1 ) { ms_log (2, "Unknown option: %s\n", argvec[optind]); exit (1); } else if ( ! inputfile ) { inputfile = argvec[optind]; } else { ms_log (2, "Unknown option: %s\n", argvec[optind]); exit (1); } } /* Make sure an inputfile was specified */ if ( ! inputfile ) { ms_log (2, "No input file was specified\n\n"); ms_log (1, "%s version %s\n\n", PACKAGE, VERSION); ms_log (1, "Try %s -h for usage\n", PACKAGE); exit (1); } /* Make sure an outputfile was specified */ if ( ! outfile ) { ms_log (2, "No output file was specified\n\n"); ms_log (1, "Try %s -h for usage\n", PACKAGE); exit (1); } /* Report the program version */ if ( verbose ) ms_log (1, "%s version: %s\n", PACKAGE, VERSION); return 0; } /* End of parameter_proc() */
/******************************************************************** * ms_detect: * * Determine SEED data record length with the following steps: * * 1) determine that the buffer contains a SEED data record by * verifying known signatures (fields with known limited values) * * 2) search the record up to recbuflen bytes for a 1000 blockette. * * 3) If no blockette 1000 is found search at 256-byte offsets for the * fixed section of the next header or blank/noise record, thereby * implying the record length. * * Returns: * -1 : data record not detected or error * 0 : data record detected but could not determine length * >0 : size of the record in bytes *********************************************************************/ int ms_detect ( const char *record, int recbuflen ) { uint16_t blkt_offset; /* Byte offset for next blockette */ uint8_t swapflag = 0; /* Byte swapping flag */ uint8_t foundlen = 0; /* Found record length */ int32_t reclen = -1; /* Size of record in bytes */ uint16_t blkt_type; uint16_t next_blkt; struct fsdh_s *fsdh; struct blkt_1000_s *blkt_1000; const char *nextfsdh; /* Buffer must be at least 48 bytes (the fixed section) */ if ( recbuflen < 48 ) return -1; /* Check for valid fixed section of header */ if ( ! MS_ISVALIDHEADER(record) ) return -1; fsdh = (struct fsdh_s *) record; /* Check to see if byte swapping is needed by checking for sane year */ if ( (fsdh->start_time.year < 1900) || (fsdh->start_time.year > 2050) ) swapflag = 1; blkt_offset = fsdh->blockette_offset; /* Swap order of blkt_offset if needed */ if ( swapflag ) ms_gswap2 (&blkt_offset); /* Loop through blockettes as long as number is non-zero and viable */ while ( blkt_offset != 0 && blkt_offset <= recbuflen ) { memcpy (&blkt_type, record + blkt_offset, 2); memcpy (&next_blkt, record + blkt_offset + 2, 2); if ( swapflag ) { ms_gswap2 (&blkt_type); ms_gswap2 (&next_blkt); } /* Found a 1000 blockette, not truncated */ if ( blkt_type == 1000 && (int)(blkt_offset + 4 + sizeof(struct blkt_1000_s)) <= recbuflen ) { blkt_1000 = (struct blkt_1000_s *) (record + blkt_offset + 4); foundlen = 1; /* Calculate record size in bytes as 2^(blkt_1000->reclen) */ reclen = (unsigned int) 1 << blkt_1000->reclen; break; } /* Saftey check for invalid offset */ if ( next_blkt != 0 && next_blkt < blkt_offset ) { ms_log (2, "Invalid blockette offset (%d) less than current offset (%d)\n", next_blkt, blkt_offset); return -1; } blkt_offset = next_blkt; } /* If record length was not determined by a 1000 blockette scan the buffer * and search for the next record */ if ( reclen == -1 ) { nextfsdh = record + 256; /* Check for record header or blank/noise record at 256 byte offsets */ while ( ((nextfsdh - record) + 48) < recbuflen ) { if ( MS_ISVALIDHEADER(nextfsdh) || MS_ISVALIDBLANK(nextfsdh) ) { foundlen = 1; reclen = nextfsdh - record; break; } nextfsdh += 256; } } if ( ! foundlen ) return 0; else return reclen; } /* End of ms_detect() */