Exemple #1
0
/***************************************************************************
 * 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() */
Exemple #3
0
/***************************************************************************
 * 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() */
Exemple #4
0
/************************************************************************
 *  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() */
Exemple #5
0
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() */
Exemple #6
0
/************************************************************************
 *  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() */
Exemple #7
0
/***************************************************************************
 * 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() */
Exemple #8
0
/***************************************************************************
 * 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() */
Exemple #9
0
/***************************************************************************
 * 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() */
Exemple #10
0
/***************************************************************************
 * 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() */
Exemple #11
0
/***************************************************************************
 * 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() */
Exemple #12
0
/***************************************************************************
 * 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() */
Exemple #13
0
/**********************************************************************
 * 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() */
Exemple #15
0
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() */
Exemple #18
0
/***************************************************************************
 * 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() */
Exemple #19
0
// 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;
}
Exemple #20
0
// 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;
}
Exemple #21
0
/***************************************************************************
 * 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() */
Exemple #22
0
/***************************************************************************
 * 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() */
Exemple #23
0
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() */
Exemple #24
0
/***************************************************************************
 * 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() */
Exemple #26
0
/***************************************************************************
 * 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() */
Exemple #27
0
/********************************************************************
 * 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() */