Example #1
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() */
Example #2
0
/************************************************************************
 *  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() */
Example #3
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() */