示例#1
0
/***************************************************************************
 * collect_and_write:
 *
 * Attempt to connect to a device, slows down the loop checking
 * after 20 attempts with a larger delay to reduce pointless
 * work being done.
 *
 * Returns 0 on success and -1 otherwise.
 ***************************************************************************/
int collect_and_write() {

    int32_t idata[2000]; // enough space for data of 2 records
    hptime_t hptime;
    hptime_t start_hptime_est = 0;
    hptime_t last_hptime;
    DOUBLE dt, dt_est, sample_rate_est;
    DOUBLE start_hptime_current, record_window_current, record_window_est;
    DOUBLE prev_start_hptime_est = -1;
    int n_start_hptime_est;

    // debug
    hptime_t start_hptime_nominal = 0;
    hptime_t prev_start_next_hptime_est = 0;
    double diff_end, diff_end_cumul = 0.0;

    char seedtimestr[64];

    // decay constant depends on required decay time and sample rate
    //double decay_minutes = 60.0; // 1 hour
    double decay_minutes = 1.0;
    double decay_consant = 1.0 / (decay_minutes * 60.0 * (double) nominal_sample_rate);


    // initialize last_hptime to current time
    last_hptime = current_utc_hptime();

    // initialize dt_est based on nominal sample rate
    dt_est = (nominal_sample_rate == 80) ? 1.0 / SAMP_PER_SEC_80 : (nominal_sample_rate == 40) ? 1.0 / SAMP_PER_SEC_40 : 1.0 / SAMP_PER_SEC_20;
    //	‘a’: 20.032 SPS
    //	‘b’: 39.860 SPS
    //	‘c’: 79.719 SPS
    // initialize record_window_est based on  nominal sample rate and record length
    record_window_est = dt_est * num_samples_in_record;

    if (DEBUG) {
        logprintf(MSG_FLAG, "Initialize: last_hptime=%lld, dt_est=%lld, dt=%lf, dt_end=%lf, dt_end_cumul=%lf)\n",
                last_hptime, dt_est, record_window_est);
    }

    int first = 1;
    MSRecord *pmsrecord = msr_init(NULL);
    strcpy(pmsrecord->network, station_network);
    strcpy(pmsrecord->station, station_name);
    strcpy(pmsrecord->location, "");
    sprintf(pmsrecord->channel, "%s%s", channel_prefix, component);
    pmsrecord->samprate = 1.0;
    pmsrecord->reclen = SLRECSIZE;
    pmsrecord->encoding = mswrite_data_encoding_type_code;
    pmsrecord->byteorder = 1;
    pmsrecord->datasamples = idata;
    pmsrecord->numsamples = 0;
    pmsrecord->sampletype = 'i';

    while (1) {

        // load data up to SLRECSIZE
        long ivalue;
        int nsamp = 0;
        start_hptime_current = 0;
        n_start_hptime_est = 0;
        while (nsamp < num_samples_in_record) {
            ivalue = read_next_value(&hptime, TIMEOUT_LARGE);
            if (ivalue == READ_ERROR || ivalue < MIN_DATA || ivalue > MAX_DATA) {
                logprintf(MSG_FLAG, "READ_ERROR: port=%s, nsamp=%d, ivalue=%ld\n", port_path, nsamp, ivalue);
                pmsrecord->datasamples = NULL;
                msr_free(&pmsrecord);
                return (-1);
            }
            if (DEBUG && nsamp == 0) {
                start_hptime_nominal = hptime;
            }
            idata[pmsrecord->numsamples + nsamp] = (int32_t) ivalue;
            dt = (DOUBLE) (hptime - last_hptime) / (DOUBLE) HPTMODULUS;
            last_hptime = hptime;
            if (verbose > 3) {
                logprintf(MSG_FLAG, "%d %ld %s (dt=%lf)\n", nsamp, ivalue, ms_hptime2seedtimestr(hptime, seedtimestr, 1), (double) dt);
            }
            // estimate start time and dt
            // use only later samples in record since writing previous record may delay reading of first samples of this record
            if (nsamp >= num_samples_in_record / 2) {
                // 20131107 AJL - use all samples, may give better start time estimate, since buffering should compensate for any delay of first samples
                //if (1) {
                // start time estimate is timestamp of current data minus dt_est*nsamp
                start_hptime_current += (hptime - (hptime_t) ((DOUBLE) 0.5 + dt_est * (DOUBLE) HPTMODULUS * (DOUBLE) nsamp));
                n_start_hptime_est++;
                // accumulate dt_est using low-pass filter
                //dt_est = dt_est + (DOUBLE) decay_consant * (dt - dt_est);
            }
            nsamp++;
        }
        start_hptime_current /= n_start_hptime_est;
        if (prev_start_hptime_est > 0) {
            record_window_current = (DOUBLE) (start_hptime_current - prev_start_hptime_est) / (DOUBLE) HPTMODULUS;
        } else {
            record_window_current = record_window_est;
        }
        // accumulate record_window_est using low-pass filter
        record_window_est = record_window_est + (DOUBLE) decay_consant * (record_window_current - record_window_est);
        if (prev_start_hptime_est > 0) {
            start_hptime_est = prev_start_hptime_est + (hptime_t) ((DOUBLE) 0.5 + record_window_est * (DOUBLE) HPTMODULUS);
        } else {
            start_hptime_est = start_hptime_current;
        }
        prev_start_hptime_est = start_hptime_est;
        // test - truncate dt to 1/10000 s to match precision of miniseed btime
        //logprintf(MSG_FLAG, "0 sample_rate_est=%lf (dt=%lfs)\n", (double) ((DOUBLE) 1.0 / dt_est), (double) dt_est);
        dt_est = record_window_est / (DOUBLE) num_samples_in_record;
        sample_rate_est = (DOUBLE) 1.0 / dt_est;
        if (DEBUG) {
            diff_end = (double) (start_hptime_est - prev_start_next_hptime_est) / (double) HPTMODULUS;
            if (!first)
                diff_end_cumul += diff_end;
            logprintf(MSG_FLAG, "sample_rate_est=%lf (dt=%lfs)\n", (double) sample_rate_est, (double) dt_est);
            logprintf(MSG_FLAG, "start_hptime_est=%lld, start_hptime_nominal=%lld, dt=%lf, dt_end=%lf, dt_end_cumul=%lf)\n", start_hptime_est, start_hptime_nominal,
                    (double) ((DOUBLE) (start_hptime_est - start_hptime_nominal) / (DOUBLE) HPTMODULUS), diff_end, diff_end_cumul);
            prev_start_next_hptime_est = start_hptime_est + (hptime_t) ((DOUBLE) 0.5 + dt_est * (DOUBLE) HPTMODULUS * (DOUBLE) nsamp);
        }

        pmsrecord->starttime = start_hptime_est - (DOUBLE) HPTMODULUS * pmsrecord->numsamples / pmsrecord->samprate;
        pmsrecord->samprate = mswrite_header_sample_rate > 0.0 ? mswrite_header_sample_rate : sample_rate_est;
        pmsrecord->numsamples += nsamp;

        int64_t npackedsamples = 0;
        if (msr_pack(pmsrecord, record_handler, NULL, &npackedsamples, 0, verbose) < 0) {
            logprintf(ERROR_FLAG, "Error encoding data!\n");
            exit(1);
        }

        pmsrecord->numsamples -= npackedsamples;
        memmove(&idata[0], &idata[npackedsamples], pmsrecord->numsamples * 4);
    }

    return (0);

}
示例#2
0
文件: msi.c 项目: ovsm-dev/sdp
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() */
示例#3
0
文件: msrutils.c 项目: 3rdcycle/obspy
/***************************************************************************
 * 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() */