Ejemplo n.º 1
0
// Function that reads from a MiniSEED binary file from a char buffer and
// returns a LinkedIDList.
LinkedIDList *
readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag
                 unpack_data, int reclen, flag verbose, flag details,
                 int header_byteorder, long (*allocData) (int, char),
                 void (*diag_print) (char*), void (*log_print) (char*))
{
    int retcode = 0;
    int retval = 0;
    flag swapflag = 0;

    // current offset of mseed char pointer
    int offset = 0;

    // Unpack without reading the data first
    flag dataflag = 0;

    // the timing_qual of BLK 1001
    uint8_t timing_qual = 0xFF;

    // the calibration type, availability of BLK 300, 310, 320, 390, 395
    int8_t calibration_type = -1;

    // Init all the pointers to NULL. Most compilers should do this anyway.
    LinkedIDList * idListHead = NULL;
    LinkedIDList * idListCurrent = NULL;
    LinkedIDList * idListLast = NULL;
    MSRecord *msr = NULL;
    ContinuousSegment * segmentCurrent = NULL;
    hptime_t lastgap = 0;
    hptime_t hptimetol = 0;
    hptime_t nhptimetol = 0;
    long data_offset;
    LinkedRecordList *recordHead = NULL;
    LinkedRecordList *recordPrevious = NULL;
    LinkedRecordList *recordCurrent = NULL;
    int datasize;
    int record_count = 0;

    // A negative verbosity suppressed as much as possible.
    if (verbose < 0) {
        ms_loginit(&empty_print, NULL, &empty_print, NULL);
    }
    else {
        ms_loginit(log_print, "INFO: ", diag_print, "ERROR: ");
    }

    if (header_byteorder >= 0) {
        // Enforce little endian.
        if (header_byteorder == 0) {
            MS_UNPACKHEADERBYTEORDER(0);
        }
        // Enforce big endian.
        else {
            MS_UNPACKHEADERBYTEORDER(1);
        }
    }
    else {
        MS_UNPACKHEADERBYTEORDER(-1);
    }

    //
    // Read all records and save them in a linked list.
    //
    while (offset < buflen) {
        msr = msr_init(NULL);
        if ( msr == NULL ) {
            ms_log (2, "readMSEEDBuffer(): Error initializing msr\n");
            return NULL;
        }
        if (verbose > 1) {
            ms_log(0, "readMSEEDBuffer(): calling msr_parse with "
                      "mseed+offset=%d+%d, buflen=%d, reclen=%d, dataflag=%d, verbose=%d\n",
                      mseed, offset, buflen, reclen, dataflag, verbose);
        }

        // If the record length is given, make sure at least that amount of data is available.
        if (reclen != -1) {
            if (offset + reclen > buflen) {
                ms_log(1, "readMSEEDBuffer(): Last reclen exceeds buflen, skipping.\n");
                msr_free(&msr);
                break;
            }
        }
        // Otherwise assume the smallest possible record length and assure that enough
        // data is present.
        else {
            if (offset + 256 > buflen) {
                ms_log(1, "readMSEEDBuffer(): Last record only has %i byte(s) which "
                          "is not enough to constitute a full SEED record. Corrupt data? "
                          "Record will be skipped.\n", buflen - offset);
                msr_free(&msr);
                break;
            }
        }

        // Pass (buflen - offset) because msr_parse() expects only a single record. This
        // way libmseed can take care to not overstep bounds.
        retcode = msr_parse ( (mseed+offset), buflen - offset, &msr, reclen, dataflag, verbose);
        if (retcode != MS_NOERROR) {
            switch ( retcode ) {
                case MS_ENDOFFILE:
                    ms_log(1, "readMSEEDBuffer(): Unexpected end of file when "
                              "parsing record starting at offset %d. The rest "
                              "of the file will not be read.\n", offset);
                    break;
                case MS_GENERROR:
                    ms_log(1, "readMSEEDBuffer(): Generic error when parsing "
                              "record starting at offset %d. The rest of the "
                              "file will not be read.\n", offset);
                    break;
                case MS_NOTSEED:
                    ms_log(1, "readMSEEDBuffer(): Record starting at offset "
                              "%d is not valid SEED. The rest of the file "
                              "will not be read.\n", offset);
                    break;
                case MS_WRONGLENGTH:
                    ms_log(1, "readMSEEDBuffer(): Length of data read was not "
                              "correct when parsing record starting at "
                              "offset %d. The rest of the file will not be "
                              "read.\n", offset);
                    break;
                case MS_OUTOFRANGE:
                    ms_log(1, "readMSEEDBuffer(): SEED record length out of "
                              "range for record starting at offset %d. The "
                              "rest of the file will not be read.\n", offset);
                    break;
                case MS_UNKNOWNFORMAT:
                    ms_log(1, "readMSEEDBuffer(): Unknown data encoding "
                              "format for record starting at offset %d. The "
                              "rest of the file will not be read.\n", offset);
                    break;
                case MS_STBADCOMPFLAG:
                    ms_log(1, "readMSEEDBuffer(): Invalid STEIM compression "
                              "flag(s) in record starting at offset %d. The "
                              "rest of the file will not be read.\n", offset);
                    break;
                default:
                    ms_log(1, "readMSEEDBuffer(): Unknown error '%d' in "
                              "record starting at offset %d. The rest of the "
                              "file will not be read.\n", retcode, offset);
                    break;
            }
            msr_free(&msr);
            break;
        }
        if (offset + msr->reclen > buflen) {
            ms_log(1, "readMSEEDBuffer(): Last msr->reclen exceeds buflen, skipping.\n");
            msr_free(&msr);
            break;
        }

        // Test against selections if supplied
        if ( selections ) {
            char srcname[50];
            hptime_t endtime;
            msr_srcname (msr, srcname, 1);
            endtime = msr_endtime (msr);
            if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) {
                // Add the record length for the next iteration
                offset += msr->reclen;
                // Free record.
                msr_free(&msr);
                continue;
            }
        }
        record_count += 1;

        recordCurrent = lrl_init ();
        // Append to linked record list if one exists.
        if ( recordHead != NULL ) {
            recordPrevious->next = recordCurrent;
            recordCurrent->previous = recordPrevious;
            recordCurrent->next = NULL;
            recordPrevious = recordCurrent;
        }
        // Otherwise create a new one.
        else {
            recordHead = recordCurrent;
            recordCurrent->previous = NULL;
            recordPrevious = recordCurrent;
        }
        recordCurrent->record = msr;

        // Determine the byte order swapflag only for the very first record.
        // The byte order should not change within the file.
        // XXX: Maybe check for every record?
        if (swapflag <= 0) {
            // Returns 0 if the host is little endian, otherwise 1.
            flag bigendianhost = ms_bigendianhost();
            // Set the swapbyteflag if it is needed.
            if ( msr->Blkt1000 != 0) {
                /* If BE host and LE data need swapping */
                if ( bigendianhost && msr->byteorder == 0 ) {
                    swapflag = 1;
                }
                /* If LE host and BE data (or bad byte order value) need swapping */
                if ( !bigendianhost && msr->byteorder > 0 ) {
                    swapflag = 1;
                }
            }
        }

        // Actually unpack the data if the flag is not set.
        if (unpack_data != 0) {
            retval = msr_unpack_data (msr, swapflag, verbose);
        }

        if ( retval > 0 ) {
            msr->numsamples = retval;
        }

        // Add the record length for the next iteration
        offset += msr->reclen;
    }

    // Return empty id list if no records could be found.
    if (record_count == 0) {
        idListHead = lil_init();
        return idListHead;
    }


    // All records that match the selection are now stored in a LinkedRecordList
    // that starts at recordHead. The next step is to sort them by matching ids
    // and then by time.
    recordCurrent = recordHead;
    while (recordCurrent != NULL) {
        // Check if the ID of the record is already available and if not create a
        // new one.
        // Start with the last id as it is most likely to be the correct one.
        idListCurrent = idListLast;
        while (idListCurrent != NULL) {
            if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 &&
                strcmp(idListCurrent->station, recordCurrent->record->station) == 0 &&
                strcmp(idListCurrent->location, recordCurrent->record->location) == 0 &&
                strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 &&
                idListCurrent->dataquality == recordCurrent->record->dataquality) {
                break;
            }
            else {
                idListCurrent = idListCurrent->previous;
            }
        }

        // Create a new id list if one is needed.
        if (idListCurrent == NULL) {
            idListCurrent = lil_init();
            idListCurrent->previous = idListLast;
            if (idListLast != NULL) {
                idListLast->next = idListCurrent;
            }
            idListLast = idListCurrent;
            if (idListHead == NULL) {
                idListHead = idListCurrent;
            }

            // Set the IdList attributes.
            strcpy(idListCurrent->network, recordCurrent->record->network);
            strcpy(idListCurrent->station, recordCurrent->record->station);
            strcpy(idListCurrent->location, recordCurrent->record->location);
            strcpy(idListCurrent->channel, recordCurrent->record->channel);
            idListCurrent->dataquality = recordCurrent->record->dataquality;
        }

        // Now check if the current record fits exactly to the end of the last
        // segment of the current id. If not create a new segment. Therefore
        // if records with the same id are in wrong order a new segment will be
        // created. This is on purpose.
        segmentCurrent = idListCurrent->lastSegment;
        if (segmentCurrent != NULL) {
            hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta);
            nhptimetol = ( hptimetol ) ? -hptimetol : 0;
            lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta;
        }
        if (details == 1) {
            /* extract information on calibration BLKs */
            calibration_type = -1;
            if (recordCurrent->record->blkts) {
                BlktLink *cur_blkt = recordCurrent->record->blkts;
                while (cur_blkt) {
                    switch (cur_blkt->blkt_type) {
                    case 300:
                        calibration_type = 1;
                        break;
                    case 310:
                        calibration_type = 2;
                        break;
                    case 320:
                        calibration_type = 3;
                        break;
                    case 390:
                        calibration_type = 4;
                        break;
                    case 395:
                        calibration_type = -2;
                        break;
                    default:
                        break;
                    }
                    cur_blkt = cur_blkt->next;
                }
            }
            /* extract information based on timing quality */
            timing_qual = 0xFF;
            if (recordCurrent->record->Blkt1001 != 0) {
                timing_qual = recordCurrent->record->Blkt1001->timing_qual;
            }
        }
        if ( segmentCurrent != NULL &&
             segmentCurrent->sampletype == recordCurrent->record->sampletype &&
             // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001
             MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) &&
             // Check if the times are within the time tolerance
             lastgap <= hptimetol && lastgap >= nhptimetol &&
             segmentCurrent->timing_qual == timing_qual &&
             segmentCurrent->calibration_type == calibration_type) {
            recordCurrent->previous = segmentCurrent->lastRecord;
            segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent;
            segmentCurrent->samplecnt += recordCurrent->record->samplecnt;
            segmentCurrent->endtime = msr_endtime(recordCurrent->record);
        }
        // Otherwise create a new segment and add the current record.
        else {
            segmentCurrent = seg_init();
            segmentCurrent->previous = idListCurrent->lastSegment;
            if (idListCurrent->lastSegment != NULL) {
                idListCurrent->lastSegment->next = segmentCurrent;
            }
            else {
                idListCurrent->firstSegment = segmentCurrent;
            }
            idListCurrent->lastSegment = segmentCurrent;

            segmentCurrent->starttime = recordCurrent->record->starttime;
            segmentCurrent->endtime = msr_endtime(recordCurrent->record);
            segmentCurrent->samprate = recordCurrent->record->samprate;
            segmentCurrent->sampletype = recordCurrent->record->sampletype;
            segmentCurrent->samplecnt = recordCurrent->record->samplecnt;
            // Calculate high-precision sample period
            segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ?
                           (HPTMODULUS / recordCurrent->record->samprate) : 0.0);
            segmentCurrent->timing_qual = timing_qual;
            segmentCurrent->calibration_type = calibration_type;
            segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent;
            recordCurrent->previous = NULL;
        }
        recordPrevious = recordCurrent->next;
        recordCurrent->next = NULL;
        recordCurrent = recordPrevious;
    }


    // Now loop over all segments, combine the records and free the msr
    // structures.
    idListCurrent = idListHead;
    while (idListCurrent != NULL)
    {
        segmentCurrent = idListCurrent->firstSegment;

        while (segmentCurrent != NULL) {
            if (segmentCurrent->datasamples) {
                free(segmentCurrent->datasamples);
            }
            // Allocate data via a callback function.
            if (unpack_data != 0) {
                segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype);
            }

            // Loop over all records, write the data to the buffer and free the msr structures.
            recordCurrent = segmentCurrent->firstRecord;
            data_offset = (long)(segmentCurrent->datasamples);
            while (recordCurrent != NULL) {
                datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype);
                memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize);
                // Free the record.
                msr_free(&(recordCurrent->record));
                // Increase the data_offset and the record.
                data_offset += (long)datasize;
                recordCurrent = recordCurrent->next;
            }

            segmentCurrent = segmentCurrent->next;
        }
        idListCurrent = idListCurrent->next;
    }
    return idListHead;
}
void
mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  MSTraceGroup *mstg = NULL;
  MSTrace *mst = NULL;
  const char **my_fnames = NULL;
  char *filename;
  int buflen;
  int reclen;
  double timetol, sampratetol;
  flag dataquality, skipnodata, dataflag, verbose;
  int i, j, nfields;
  mxArray *tmp_val;
  double *tmp_val_ptr;
  int32_t *data;

  /* Sanity check input and output */
  if ( nrhs != 8 )
    {
      mexPrintf ("mexMsReadTracesNative - Read Mini-SEED data into Matlab\n\n");
      mexPrintf ("Usage: mexMsReadTracesNative (filename, reclen, timetol, sampratetol, dataquality, skipnotdata, dataflag, verbosity)\n");
      mexPrintf ("  filename    - Name of file to read Mini-SEED data from\n");
      mexPrintf ("  reclen      - Mini-SEED data record length, -1 for autodetection\n");
      mexPrintf ("  timetol     - Time tolerance, use -1.0 for 1/2 sample period\n");
      mexPrintf ("  sampratetol - Sample rate tolerance, use -1.0 for default tolerance\n");
      mexPrintf ("  dataquality - Include data quality in determination of unique time series, use 0 or 1\n");
      mexPrintf ("  skipnotdata - Skip blocks in input file that are not Mini-SEED data\n");
      mexPrintf ("  dataflag    - Flag to control return of data samples or not, 0 or 1\n");
      mexPrintf ("  verbosity   - Level of diagnostic messages, use 0 - 3\n\n");
      mexErrMsgTxt ("8 input arguments required.");
    }
  else if ( nlhs > 1 )
    {
      mexErrMsgTxt ("Too many output arguments.");
    }

  /* Redirect libmseed logging messages to Matlab functions */
  ms_loginit ((void *)&mexPrintf, NULL, (void *)&mexWarnMsgTxt, NULL);

  /* Get the length of the input string */
  buflen = (mxGetM (prhs[0]) * mxGetN (prhs[0])) + 1;

  /* Allocate memory for input string */
  filename = mxCalloc (buflen, sizeof (char));

  /* Assign the input arguments to variables */
  if ( mxGetString (prhs[0], filename, buflen) )
    mexErrMsgTxt ("Not enough space. Filename string is truncated.");
  reclen = (int) mxGetScalar(prhs[1]);
  timetol = mxGetScalar(prhs[2]);
  sampratetol = mxGetScalar(prhs[3]);
  dataquality = (flag) mxGetScalar(prhs[4]);
  skipnodata = (flag) mxGetScalar(prhs[5]);
  dataflag = (flag) mxGetScalar(prhs[6]);
  verbose = (flag) mxGetScalar(prhs[7]);

  /* Read the file */
  if ( ms_readtraces (&mstg, filename, reclen, timetol, sampratetol, dataquality,
		      skipnodata, dataflag, verbose) != MS_NOERROR )
    mexErrMsgTxt ("Error reading files");

  /* Print some information to the Matlab command prompt */
  mst_printtracelist (mstg, 0, verbose, 1);

  /* Create the Matlab output structure */
  mst = mstg->traces;
  for (i=0; i < mstg->numtraces; i++)
    {
      if (i==0)
   	{
	  nfields = 13;
	  my_fnames = mxCalloc (nfields, sizeof (*my_fnames));
	  my_fnames[0] = "network";
	  my_fnames[1] = "station";
	  my_fnames[2] = "location";
	  my_fnames[3] = "channel";
	  my_fnames[4] = "dataquality";
	  my_fnames[5] = "type";
	  my_fnames[6] = "startTime";
	  my_fnames[7] = "endTime";
	  my_fnames[8] = "sampleRate";
	  my_fnames[9] = "sampleCount";
	  my_fnames[10] = "numberOfSamples";
	  my_fnames[11] = "sampleType";
	  my_fnames[12] = "data";
	  plhs[0] = mxCreateStructMatrix(mstg->numtraces, 1, nfields, my_fnames);
	  mxFree(my_fnames);
   	}

      /* Copy the data of the mst structure to the matlab output structure. */
      data = (int32_t*) mst->datasamples;
      tmp_val = mxCreateDoubleMatrix(mst->numsamples, 1, mxREAL);
      tmp_val_ptr = mxGetPr(tmp_val);
      for (j = 0; j < mst->numsamples; j++)
      {
# if ENDIANNESS
        tmp_val_ptr[j] = (double) data[j];
# else
        tmp_val_ptr[j] = (double) (int32_t)(__builtin_bswap32 (data[j]));
# endif
        //tmp_val_ptr[j] = 100.0;
      }

      mxSetFieldByNumber(plhs[0], i, 0, mxCreateString(mst->network));
      mxSetFieldByNumber(plhs[0], i, 1, mxCreateString(mst->station));
      mxSetFieldByNumber(plhs[0], i, 2, mxCreateString(mst->location));
      mxSetFieldByNumber(plhs[0], i, 3, mxCreateString(mst->channel));
      mxSetFieldByNumber(plhs[0], i, 4, mxCreateDoubleScalar((int)mst->dataquality));
      mxSetFieldByNumber(plhs[0], i, 5, mxCreateDoubleScalar((int)mst->type));
      mxSetFieldByNumber(plhs[0], i, 6, mxCreateDoubleScalar(mst->starttime));
      mxSetFieldByNumber(plhs[0], i, 7, mxCreateDoubleScalar(mst->endtime));
      mxSetFieldByNumber(plhs[0], i, 8, mxCreateDoubleScalar(mst->samprate));
      mxSetFieldByNumber(plhs[0], i, 9, mxCreateDoubleScalar(mst->samplecnt));
      mxSetFieldByNumber(plhs[0], i, 10, mxCreateDoubleScalar(mst->numsamples));
      mxSetFieldByNumber(plhs[0], i, 11, mxCreateDoubleScalar((int)mst->sampletype));
      mxSetFieldByNumber(plhs[0], i, 12, tmp_val);

      mst = mst->next;
    }

  mst_freegroup (&mstg);
}
Ejemplo n.º 3
0
int main(int argc, char **argv) {

#ifndef WIN32
    // Signal handling, use POSIX calls with standardized semantics
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = term_handler;
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGQUIT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    sa.sa_handler = SIG_IGN;
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGPIPE, &sa, NULL);
#endif

    /*
    printf("LONG_MIN %ld\n", LONG_MIN);
    printf("LONG_MAX %ld\n", LONG_MAX);
    printf("INT_MIN %d\n", INT_MIN);
    printf("INT_MAX %d\n", INT_MAX);
     */

    // set default error message prefix
    ms_loginit(NULL, NULL, NULL, "ERROR: ");

    // defaults
    verbose = 0;
    strcpy(port_path_hint, "/dev/usbdev1.1");
    strcpy(propfile, PROP_FILE_NAME_DEFAULT);

    // Process input parameters
    if (parameter_proc(argc, argv) < 0)
        return 1;
    init_properties(propfile);

    // set encoding type
    // possible: DE_ASCII, DE_INT16, DE_INT32, DE_FLOAT32, DE_FLOAT64, DE_STEIM1, DE_STEIM2
    // supported: DE_INT16, DE_INT32, DE_STEIM1, DE_STEIM2
    if (strcmp(mswrite_data_encoding_type, "DE_INT16") == 0) {
        mswrite_data_encoding_type_code = DE_INT16;
        num_samples_in_record = (SLREC_DATA_SIZE) / 2;
    } else if (strcmp(mswrite_data_encoding_type, "DE_INT32") == 0) {
        mswrite_data_encoding_type_code = DE_INT32;
        num_samples_in_record = (SLREC_DATA_SIZE) / 4;
        /*
    } else if (strcmp(mswrite_data_encoding_type, "DE_ASCII") == 0) {
        mswrite_data_encoding_type_code = DE_ASCII;
    } else if (strcmp(mswrite_data_encoding_type, "DE_FLOAT32") == 0) {
        mswrite_data_encoding_type_code = DE_FLOAT32;
    } else if (strcmp(mswrite_data_encoding_type, "DE_FLOAT64") == 0) {
        mswrite_data_encoding_type_code = DE_FLOAT64;
         */
    } else if (strcmp(mswrite_data_encoding_type, "DE_STEIM1") == 0) {
        mswrite_data_encoding_type_code = DE_STEIM1;
        num_samples_in_record = (SLREC_DATA_SIZE) / 4; // estimate, inefficient, assumes int32 data
    } else if (strcmp(mswrite_data_encoding_type, "DE_STEIM2") == 0) {
        mswrite_data_encoding_type_code = DE_STEIM2;
        num_samples_in_record = (SLREC_DATA_SIZE) / 4; // estimate, inefficient, assumes int32 data
    }

    // enter infinite loop, term_handler() performs cleanup
    while (1) {

        // find device and connect
        find_device_and_connect(port_path_hint);

        // set sample rate and gain for SEP064
        if (do_settings_sep064) {
            if (set_seo064_sample_rate_and_gain(nominal_sample_rate, nominal_gain, TIMEOUT_SMALL, verbose)) {
                continue;
            }
        }

        // collect data and write
        if (collect_and_write()) { // collect_and_write() returned error
            logprintf(ERROR_FLAG, "Reading from %s, will try reconnecting...\n", port_path);
            disconnect(verbose);
        } else {
            break; // collect_and_write() returned normally
        }

    }

    return (0);

} /* End of main() */
Ejemplo n.º 4
0
Archivo: msi.c Proyecto: 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() */
Ejemplo n.º 5
0
// Function that reads from a MiniSEED binary file from a char buffer and
// returns a LinkedIDList.
LinkedIDList *
readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag
                 unpack_data, int reclen, flag verbose, flag details,
                 int header_byteorder, long long (*allocData) (int, char),
                 void (*diag_print) (char*), void (*log_print) (char*))
{
    int retcode = 0;
    int retval = 0;
    flag swapflag = 0;
    flag bigendianhost = ms_bigendianhost();

    // current offset of mseed char pointer
    int offset = 0;

    // Unpack without reading the data first
    flag dataflag = 0;

    // the timing_qual of BLK 1001
    uint8_t timing_qual = 0xFF;

    // the calibration type, availability of BLK 300, 310, 320, 390, 395
    int8_t calibration_type = -1;

    // Init all the pointers to NULL. Most compilers should do this anyway.
    LinkedIDList * idListHead = NULL;
    LinkedIDList * idListCurrent = NULL;
    LinkedIDList * idListLast = NULL;
    MSRecord *msr = NULL;
    ContinuousSegment * segmentCurrent = NULL;
    hptime_t lastgap = 0;
    hptime_t hptimetol = 0;
    hptime_t nhptimetol = 0;
    long long data_offset;
    LinkedRecordList *recordHead = NULL;
    LinkedRecordList *recordPrevious = NULL;
    LinkedRecordList *recordCurrent = NULL;
    int datasize;
    int record_count = 0;

    // A negative verbosity suppresses as much as possible.
    if (verbose < 0) {
        ms_loginit(&empty_print, NULL, &empty_print, NULL);
    }
    else {
        ms_loginit(log_print, "INFO: ", diag_print, "ERROR: ");
    }

    if (header_byteorder >= 0) {
        // Enforce little endian.
        if (header_byteorder == 0) {
            MS_UNPACKHEADERBYTEORDER(0);
        }
        // Enforce big endian.
        else {
            MS_UNPACKHEADERBYTEORDER(1);
        }
    }
    else {
        MS_UNPACKHEADERBYTEORDER(-1);
    }

    // Read all records and save them in a linked list.
    while (offset < buflen) {
        msr = msr_init(NULL);
        if ( msr == NULL ) {
            ms_log (2, "readMSEEDBuffer(): Error initializing msr\n");
            return NULL;
        }
        if (verbose > 1) {
            ms_log(0, "readMSEEDBuffer(): calling msr_parse with "
                      "mseed+offset=%d+%d, buflen=%d, reclen=%d, dataflag=%d, verbose=%d\n",
                      mseed, offset, buflen, reclen, dataflag, verbose);
        }

        // If the record length is given, make sure at least that amount of data is available.
        if (reclen != -1) {
            if (offset + reclen > buflen) {
                ms_log(1, "readMSEEDBuffer(): Last reclen exceeds buflen, skipping.\n");
                msr_free(&msr);
                break;
            }
        }
        // Otherwise assume the smallest possible record length and assure that enough
        // data is present.
        else {
            if (offset + MINRECLEN > buflen) {
                ms_log(1, "readMSEEDBuffer(): Last record only has %i byte(s) which "
                          "is not enough to constitute a full SEED record. Corrupt data? "
                          "Record will be skipped.\n", buflen - offset);
                msr_free(&msr);
                break;
            }
        }

        // Skip empty or noise records.
        if (OBSPY_ISVALIDBLANK(mseed + offset)) {
            offset += MINRECLEN;
            continue;
        }

        // Pass (buflen - offset) because msr_parse() expects only a single record. This
        // way libmseed can take care to not overstep bounds.
        // Return values:
        //   0 : Success, populates the supplied MSRecord.
        //  >0 : Data record detected but not enough data is present, the
        //       return value is a hint of how many more bytes are needed.
        //  <0 : libmseed error code (listed in libmseed.h) is returned.
        retcode = msr_parse ((mseed+offset), buflen - offset, &msr, reclen, dataflag, verbose);
        // Handle error.
        if (retcode < 0) {
            log_error(retcode, offset);
            msr_free(&msr);
            break;
        }
        // msr_parse() returns > 0 if a data record has been detected but the buffer either has not enough
        // data (this cannot happen with ObsPy's logic) or the last record has no Blockette 1000 and it cannot
        // determine the record length because there is no next record (this can happen in ObsPy) - handle that
        // case by just calling msr_parse() with an explicit record length set.
        else if ( retcode > 0 && retcode < (buflen - offset)) {

            // Check if the remaining bytes can exactly make up a record length.
            int r_bytes = buflen - offset;
            float exp = log10((float)r_bytes) / log10(2.0);
            if ((fmodf(exp, 1.0) < 0.0000001) && ((int)roundf_(exp) >= 7) && ((int)roundf_(exp) <= 256)) {

                retcode = msr_parse((mseed + offset), buflen - offset, &msr, r_bytes, dataflag, verbose);

                if ( retcode != 0 ) {
                    log_error(retcode, offset);
                    msr_free(&msr);
                    break;
                }

            }
            else {
                msr_free(&msr);
                break;
            }
        }

        if (offset + msr->reclen > buflen) {
            ms_log(1, "readMSEEDBuffer(): Last msr->reclen exceeds buflen, skipping.\n");
            msr_free(&msr);
            break;
        }

        // Test against selections if supplied
        if ( selections ) {
            char srcname[50];
            hptime_t endtime;
            msr_srcname (msr, srcname, 1);
            endtime = msr_endtime (msr);
            if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) {
                // Add the record length for the next iteration
                offset += msr->reclen;
                // Free record.
                msr_free(&msr);
                continue;
            }
        }
        record_count += 1;

        recordCurrent = lrl_init ();
        // Append to linked record list if one exists.
        if ( recordHead != NULL ) {
            recordPrevious->next = recordCurrent;
            recordCurrent->previous = recordPrevious;
            recordCurrent->next = NULL;
            recordPrevious = recordCurrent;
        }
        // Otherwise create a new one.
        else {
            recordHead = recordCurrent;
            recordCurrent->previous = NULL;
            recordPrevious = recordCurrent;
        }
        recordCurrent->record = msr;


        // Figure out if the byte-order of the data has to be swapped.
        swapflag = 0;
        // If blockette 1000 is present, use it.
        if ( msr->Blkt1000 != 0) {
            /* If BE host and LE data need swapping */
            if ( bigendianhost && msr->byteorder == 0 ) {
                swapflag = 1;
            }
            /* If LE host and BE data (or bad byte order value) need swapping */
            if ( !bigendianhost && msr->byteorder > 0 ) {
                swapflag = 1;
            }
        }
        // Otherwise assume the data has the same byte order as the header.
        // This needs to be done on the raw header bytes as libmseed only returns
        // header fields in the native byte order.
        else {
            unsigned char* _t = (unsigned char*)mseed + offset + 20;
            unsigned int year = _t[0] | _t[1] << 8;
            unsigned int day = _t[2] | _t[3] << 8;
            // Swap data if header needs to be swapped.
            if (!MS_ISVALIDYEARDAY(year, day)) {
                swapflag = 1;
            }
        }

        // Actually unpack the data if the flag is not set and if the data
        // offset is valid.
        if ((unpack_data != 0) && (msr->fsdh->data_offset >= 48) &&
            (msr->fsdh->data_offset < msr->reclen) &&
            (msr->samplecnt > 0)) {
            retval = msr_unpack_data (msr, swapflag, verbose);
        }

        if ( retval > 0 ) {
            msr->numsamples = retval;
        }

        if ( msr->fsdh->start_time.fract > 9999 ) {
            ms_log(1, "readMSEEDBuffer(): Record with offset=%d has a "
                      "fractional second (.0001 seconds) of %d. This is not "
                      "strictly valid but will be interpreted as one or more "
                      "additional seconds.",
                      offset, msr->fsdh->start_time.fract);
        }

        // Add the record length for the next iteration
        offset += msr->reclen;
    }

    // Return empty id list if no records could be found.
    if (record_count == 0) {
        idListHead = lil_init();
        return idListHead;
    }


    // All records that match the selection are now stored in a LinkedRecordList
    // that starts at recordHead. The next step is to sort them by matching ids
    // and then by time.
    recordCurrent = recordHead;
    while (recordCurrent != NULL) {
        // Check if the ID of the record is already available and if not create a
        // new one.
        // Start with the last id as it is most likely to be the correct one.
        idListCurrent = idListLast;
        while (idListCurrent != NULL) {
            if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 &&
                strcmp(idListCurrent->station, recordCurrent->record->station) == 0 &&
                strcmp(idListCurrent->location, recordCurrent->record->location) == 0 &&
                strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 &&
                idListCurrent->dataquality == recordCurrent->record->dataquality) {
                break;
            }
            else {
                idListCurrent = idListCurrent->previous;
            }
        }

        // Create a new id list if one is needed.
        if (idListCurrent == NULL) {
            idListCurrent = lil_init();
            idListCurrent->previous = idListLast;
            if (idListLast != NULL) {
                idListLast->next = idListCurrent;
            }
            idListLast = idListCurrent;
            if (idListHead == NULL) {
                idListHead = idListCurrent;
            }

            // Set the IdList attributes.
            strcpy(idListCurrent->network, recordCurrent->record->network);
            strcpy(idListCurrent->station, recordCurrent->record->station);
            strcpy(idListCurrent->location, recordCurrent->record->location);
            strcpy(idListCurrent->channel, recordCurrent->record->channel);
            idListCurrent->dataquality = recordCurrent->record->dataquality;
        }

        // Now check if the current record fits exactly to the end of the last
        // segment of the current id. If not create a new segment. Therefore
        // if records with the same id are in wrong order a new segment will be
        // created. This is on purpose.
        segmentCurrent = idListCurrent->lastSegment;
        if (segmentCurrent != NULL) {
            hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta);
            nhptimetol = ( hptimetol ) ? -hptimetol : 0;
            lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta;
        }
        if (details == 1) {
            /* extract information on calibration BLKs */
            calibration_type = -1;
            if (recordCurrent->record->blkts) {
                BlktLink *cur_blkt = recordCurrent->record->blkts;
                while (cur_blkt) {
                    switch (cur_blkt->blkt_type) {
                    case 300:
                        calibration_type = 1;
                        break;
                    case 310:
                        calibration_type = 2;
                        break;
                    case 320:
                        calibration_type = 3;
                        break;
                    case 390:
                        calibration_type = 4;
                        break;
                    case 395:
                        calibration_type = -2;
                        break;
                    default:
                        break;
                    }
                    cur_blkt = cur_blkt->next;
                }
            }
            /* extract information based on timing quality */
            timing_qual = 0xFF;
            if (recordCurrent->record->Blkt1001 != 0) {
                timing_qual = recordCurrent->record->Blkt1001->timing_qual;
            }
        }
        if ( segmentCurrent != NULL &&

             // This is important for zero data record coupled with not unpacking
             // the data. It needs to be split in two places: Before the zero data
             // record and after it.
             recordCurrent->record->samplecnt > 0 && segmentCurrent->samplecnt > 0 &&

             segmentCurrent->sampletype == recordCurrent->record->sampletype &&
             // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001
             MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) &&
             // Check if the times are within the time tolerance
             lastgap <= hptimetol && lastgap >= nhptimetol &&
             segmentCurrent->timing_qual == timing_qual &&
             segmentCurrent->calibration_type == calibration_type) {
            recordCurrent->previous = segmentCurrent->lastRecord;
            segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent;
            segmentCurrent->samplecnt += recordCurrent->record->samplecnt;
            segmentCurrent->endtime = msr_endtime(recordCurrent->record);
        }
        // Otherwise create a new segment and add the current record.
        else {
            segmentCurrent = seg_init();
            segmentCurrent->previous = idListCurrent->lastSegment;
            if (idListCurrent->lastSegment != NULL) {
                idListCurrent->lastSegment->next = segmentCurrent;
            }
            else {
                idListCurrent->firstSegment = segmentCurrent;
            }
            idListCurrent->lastSegment = segmentCurrent;

            segmentCurrent->starttime = recordCurrent->record->starttime;
            segmentCurrent->endtime = msr_endtime(recordCurrent->record);
            segmentCurrent->samprate = recordCurrent->record->samprate;
            segmentCurrent->sampletype = recordCurrent->record->sampletype;
            segmentCurrent->samplecnt = recordCurrent->record->samplecnt;
            // Calculate high-precision sample period
            segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ?
                           (HPTMODULUS / recordCurrent->record->samprate) : 0.0);
            segmentCurrent->timing_qual = timing_qual;
            segmentCurrent->calibration_type = calibration_type;
            segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent;
            recordCurrent->previous = NULL;
        }
        recordPrevious = recordCurrent->next;
        recordCurrent->next = NULL;
        recordCurrent = recordPrevious;
    }


    // Now loop over all segments, combine the records and free the msr
    // structures.
    idListCurrent = idListHead;
    while (idListCurrent != NULL)
    {
        segmentCurrent = idListCurrent->firstSegment;

        while (segmentCurrent != NULL) {
            if (segmentCurrent->datasamples) {
                free(segmentCurrent->datasamples);
            }
            // Allocate data via a callback function.
            if (unpack_data != 0) {
                segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype);
            }

            // Loop over all records, write the data to the buffer and free the msr structures.
            recordCurrent = segmentCurrent->firstRecord;
            data_offset = (long long)(segmentCurrent->datasamples);
            while (recordCurrent != NULL) {
                datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype);
                memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize);
                // Free the record.
                msr_free(&(recordCurrent->record));
                // Increase the data_offset and the record.
                data_offset += (long long)datasize;
                recordCurrent = recordCurrent->next;
            }

            segmentCurrent = segmentCurrent->next;
        }
        idListCurrent = idListCurrent->next;
    }
    return idListHead;
}