Example #1
0
// Frees a LinkedRecordList. The given Record is assumed to be the head of the
// list.
void
lrl_free(LinkedRecordList * lrl)
{
    LinkedRecordList * next;
    while ( lrl != NULL) {
        next = lrl->next;
        msr_free(&lrl->record);
        free(lrl);
        if (next == NULL) {
            break;
        }
        lrl = next;
    }
    lrl = NULL;
}
    bool MSeedWriter::write(IntegerMSeedRecord::SharedPtr_t sampleRange)
    {
        // наполнения хедера mseed
        MSRecord* msr = msr_init(NULL);

        // общие для записей данные
        strcpy(msr->network, sampleRange->network().toLatin1().constData());
        strcpy(msr->station, sampleRange->station().toLatin1().constData());
        strcpy(msr->location, sampleRange->location().toLatin1().constData());
        strcpy(msr->channel, sampleRange->channelName().toLatin1().constData());

        msr->samprate = sampleRange->samplingRateHz();

        msr->reclen = _recordLength;
        msr->record = NULL;
        msr->encoding = _encoding;  // compression
        msr->byteorder = 1;         // big endian byte order

        BTime btime = dateTimeToBTime(sampleRange->startTime());
        msr->starttime = ms_btime2hptime(&btime);

        msr->sampletype = 'i';      // declare type to be 32-bit integers

        msr->datasamples = sampleRange->data().data();
        msr->numsamples = sampleRange->data().size();

        flag verbose = _verbose;
        _packedSamples = 0;
        _packedRecords = msr_pack(msr, &binaryStreamRecorder, _binaryStream.get(), &_packedSamples, 1, verbose);
        if (_packedRecords == -1)
        {
            return false;
        }

        msr->datasamples = NULL;
        msr_free(&msr);

        ms_log(0, "Packed %d samples into %d records\n", _packedSamples, _packedRecords);
        return true;
    }
Example #3
0
int
main (int argc, char **argv)
{
  MSRecord *msr = 0;
  MSTraceGroup *mstg = 0;
  MSTrace *mst;
  int retcode;

  int totalrecs  = 0;
  int totalsamps = 0;
  int packedsamples;
  int packedrecords;
  int lastrecord;
  int iseqnum = 1;
  
#ifndef WIN32
  /* Signal handling, use POSIX calls with standardized semantics */
  struct sigaction sa;
  
  sa.sa_flags = SA_RESTART;
  sigemptyset (&sa.sa_mask);
  
  sa.sa_handler = term_handler;
  sigaction (SIGINT, &sa, NULL);
  sigaction (SIGQUIT, &sa, NULL);
  sigaction (SIGTERM, &sa, NULL);
  
  sa.sa_handler = SIG_IGN;
  sigaction (SIGHUP, &sa, NULL);
  sigaction (SIGPIPE, &sa, NULL);
#endif
  
  /* Process given parameters (command line and parameter file) */
  if (parameter_proc (argc, argv) < 0)
    return -1;
  
  /* Setup input encoding format if specified */
  if ( encodingstr )
    {
      int inputencoding = strtoul (encodingstr, NULL, 10);
      
      if ( inputencoding == 0 && errno == EINVAL )
	{
	  ms_log (2, "Error parsing input encoding format: %s\n", encodingstr);
	  return -1;
	}
      
      MS_UNPACKENCODINGFORMAT (inputencoding);
    }
  
  /* Init MSTraceGroup */
  mstg = mst_initgroup (mstg);
  
  /* Loop over the input file */
  while ( (retcode = ms_readmsr (&msr, inputfile, reclen, NULL, &lastrecord,
				 1, 1, verbose)) == MS_NOERROR )
    {
      totalrecs++;
      totalsamps += msr->samplecnt;
      
      msr_print (msr, ppackets);
      
      if ( packreclen >= 0 )
	msr->reclen = packreclen;
      else
	packreclen = msr->reclen;
      
      if ( packencoding >= 0 )
	msr->encoding = packencoding;
      else
	packencoding = msr->encoding;
      
      if ( byteorder >= 0 )
	msr->byteorder = byteorder;
      else
	byteorder = msr->byteorder;
      
      /* After unpacking the record, the start time in msr->starttime
	 is a potentially corrected start time, if correction has been
	 applied make sure the correction bit flag is set as it will
	 be used as a packing template. */
      if ( msr->fsdh->time_correct && ! (msr->fsdh->act_flags & 0x02) )
	{
	  ms_log (1, "Setting time correction applied flag for %s_%s_%s_%s\n",
		  msr->network, msr->station, msr->location, msr->channel);
	  msr->fsdh->act_flags |= 0x02;
	}
      
      /* If no samples in the record just pack the header */
      if ( outfile && msr->numsamples == 0 )
	{
	  msr_pack_header (msr, 1, verbose);
	  record_handler (msr->record, msr->reclen, NULL);
	}
      
      /* Pack each record individually */
      else if ( outfile && ! tracepack )
	{
	  msr->sequence_number = iseqnum;
	  
	  packedrecords = msr_pack (msr, &record_handler, NULL, &packedsamples, 1, verbose);
	  
	  if ( packedrecords == -1 )
	    ms_log (2, "Cannot pack records\n"); 
	  else
	    ms_log (1, "Packed %d records\n", packedrecords); 
	  
	  iseqnum = msr->sequence_number;
	}
      
      /* Pack records from a MSTraceGroup */
      else if ( outfile && tracepack )
	{
	  mst = mst_addmsrtogroup (mstg, msr, 0, -1.0, -1.0);
	  
	  if ( ! mst )
	    {
	      ms_log (2, "Error adding MSRecord to MStrace!\n");
	      break;
	    }
	  	  
	  /* Reset sequence number and free previous template */
	  if ( mst->prvtptr )
	    {
	      MSRecord *tmsr = (MSRecord *) mst->prvtptr;
	      
	      /* Retain sequence number from previous template */
	      msr->sequence_number = tmsr->sequence_number;
	      
	      msr_free (&tmsr);
	    }
	  else
	    {
	      msr->sequence_number = 1;
	    }
	  
	  /* Copy MSRecord and store as template */
	  mst->prvtptr = msr_duplicate (msr, 0);
	  
	  if ( ! mst->prvtptr )
	    {
	      ms_log (2, "Error duplicating MSRecord for template!\n");
	      break;
	    }
	  
	  /* Pack traces based on selected method */
	  packedrecords = 0;
	  if ( tracepack == 1 )
	    {
	      mst = mstg->traces;
	      while ( mst )
		{
		  packedrecords += mst_pack (mst, &record_handler, NULL, packreclen,
					     packencoding, byteorder, &packedsamples,
					     lastrecord, verbose, (MSRecord *)mst->prvtptr);
		  mst = mst->next;
		}
	      
	      ms_log (1, "Packed %d records\n", packedrecords);
	    }
	  if ( tracepack == 2 && lastrecord )
	    {
	      mst = mstg->traces;
	      while ( mst )
		{
		  packedrecords += mst_pack (mst, &record_handler, NULL, packreclen,
					     packencoding, byteorder, &packedsamples,
					     lastrecord, verbose, (MSRecord *)mst->prvtptr);
		  mst = mst->next;
		}
	      
	      ms_log (1, "Packed %d records\n", packedrecords);
	    }
	}
    }
  
  if ( retcode != MS_ENDOFFILE )
    ms_log (2, "Error reading %s: %s\n", inputfile, ms_errorstr(retcode));
  
  /* Make sure everything is cleaned up */
  ms_readmsr (&msr, NULL, 0, NULL, NULL, 0, 0, 0);
  mst_freegroup (&mstg);
  
  if ( outfile )
    fclose (outfile);
  
  getchar();

  return 0;
}  /* End of main() */
Example #4
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;
}
Example #5
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);

}
Example #6
0
/**********************************************************************
 * ms_readmsr_main:
 *
 * This routine will open and read, with subsequent calls, all
 * Mini-SEED records in specified file.
 *
 * All static file reading parameters are stored in a MSFileParam
 * struct and returned (via a pointer to a pointer) for the calling
 * routine to use in subsequent calls.  A MSFileParam struct will be
 * allocated if necessary.  This routine is thread safe and can be
 * used to read multiple files in parallel as long as the file reading
 * parameters are managed appropriately.
 *
 * If reclen is 0 or negative the length of every record is
 * automatically detected.  For auto detection of record length the
 * record must include a 1000 blockette or be followed by a valid
 * record header or end of file.
 *
 * If *fpos is not NULL it will be updated to reflect the file
 * position (offset from the beginning in bytes) from where the
 * returned record was read.  As a special case, if *fpos is not NULL
 * and the value it points to is less than 0 this will be interpreted
 * as a (positive) starting offset from which to begin reading data;
 * this feature does not work with packed files.
 *
 * If *last is not NULL it will be set to 1 when the last record in
 * the file is being returned, otherwise it will be 0.
 *
 * If the skipnotdata flag is true any data chunks read that do not
 * have valid data record indicators (D, R, Q, M, etc.) will be skipped.
 *
 * dataflag will be passed directly to msr_unpack().
 *
 * If a Selections list is supplied it will be used to determine when
 * a section of data in a packed file may be skipped, packed files are
 * internal to the IRIS DMC.
 *
 * After reading all the records in a file the controlling program
 * should call it one last time with msfile set to NULL.  This will
 * close the file and free allocated memory.
 *
 * Returns MS_NOERROR and populates an MSRecord struct at *ppmsr on
 * successful read, returns MS_ENDOFFILE on EOF, otherwise returns a
 * libmseed error code (listed in libmseed.h) and *ppmsr is set to
 * NULL.
 *********************************************************************/
int
ms_readmsr_main (MSFileParam **ppmsfp, MSRecord **ppmsr, const char *msfile,
                 int reclen, off_t *fpos, int *last, flag skipnotdata,
                 flag dataflag, Selections *selections, flag verbose)
{
  MSFileParam *msfp;
  off_t packdatasize = 0;
  int packskipsize;
  int parseval  = 0;
  int readsize  = 0;
  int readcount = 0;
  int retcode   = MS_NOERROR;

  if (!ppmsr)
    return MS_GENERROR;

  if (!ppmsfp)
    return MS_GENERROR;

  msfp = *ppmsfp;

  /* Initialize the file read parameters if needed */
  if (!msfp)
  {
    msfp = (MSFileParam *)malloc (sizeof (MSFileParam));

    if (msfp == NULL)
    {
      ms_log (2, "ms_readmsr_main(): Cannot allocate memory for MSFP\n");
      return MS_GENERROR;
    }

    /* Redirect the supplied pointer to the allocated params */
    *ppmsfp = msfp;

    msfp->fp            = NULL;
    msfp->filename[0]   = '\0';
    msfp->rawrec        = NULL;
    msfp->readlen       = 0;
    msfp->readoffset    = 0;
    msfp->packtype      = 0;
    msfp->packhdroffset = 0;
    msfp->filepos       = 0;
    msfp->filesize      = 0;
    msfp->recordcount   = 0;
  }

  /* When cleanup is requested */
  if (msfile == NULL)
  {
    msr_free (ppmsr);

    if (msfp->fp != NULL)
      fclose (msfp->fp);

    if (msfp->rawrec != NULL)
      free (msfp->rawrec);

    /* If the file parameters are the global parameters reset them */
    if (*ppmsfp == &gMSFileParam)
    {
      gMSFileParam.fp            = NULL;
      gMSFileParam.filename[0]   = '\0';
      gMSFileParam.rawrec        = NULL;
      gMSFileParam.readlen       = 0;
      gMSFileParam.readoffset    = 0;
      gMSFileParam.packtype      = 0;
      gMSFileParam.packhdroffset = 0;
      gMSFileParam.filepos       = 0;
      gMSFileParam.filesize      = 0;
      gMSFileParam.recordcount   = 0;
    }
    /* Otherwise free the MSFileParam */
    else
    {
      free (*ppmsfp);
      *ppmsfp = NULL;
    }

    return MS_NOERROR;
  }

  /* Allocate reading buffer */
  if (msfp->rawrec == NULL)
  {
    if (!(msfp->rawrec = (char *)malloc (MAXRECLEN)))
    {
      ms_log (2, "ms_readmsr_main(): Cannot allocate memory for read buffer\n");
      return MS_GENERROR;
    }
  }

  /* Sanity check: track if we are reading the same file */
  if (msfp->fp && strncmp (msfile, msfp->filename, sizeof (msfp->filename)))
  {
    ms_log (2, "ms_readmsr_main() called with a different file name without being reset\n");

    /* Close previous file and reset needed variables */
    if (msfp->fp != NULL)
      fclose (msfp->fp);

    msfp->fp            = NULL;
    msfp->readlen       = 0;
    msfp->readoffset    = 0;
    msfp->packtype      = 0;
    msfp->packhdroffset = 0;
    msfp->filepos       = 0;
    msfp->filesize      = 0;
    msfp->recordcount   = 0;
  }

  /* Open the file if needed, redirect to stdin if file is "-" */
  if (msfp->fp == NULL)
  {
    /* Store the filename for tracking */
    strncpy (msfp->filename, msfile, sizeof (msfp->filename) - 1);
    msfp->filename[sizeof (msfp->filename) - 1] = '\0';

    if (strcmp (msfile, "-") == 0)
    {
      msfp->fp = stdin;
    }
    else
    {
      if ((msfp->fp = fopen (msfile, "rb")) == NULL)
      {
        ms_log (2, "Cannot open file: %s (%s)\n", msfile, strerror (errno));
        msr_free (ppmsr);

        return MS_GENERROR;
      }
      else
      {
        /* Determine file size */
        struct stat sbuf;

        if (fstat (fileno (msfp->fp), &sbuf))
        {
          ms_log (2, "Cannot open file: %s (%s)\n", msfile, strerror (errno));
          msr_free (ppmsr);

          return MS_GENERROR;
        }

        msfp->filesize = sbuf.st_size;
      }
    }
  }

  /* Seek to a specified offset if requested */
  if (fpos != NULL && *fpos < 0)
  {
    /* Only try to seek in real files, not stdin */
    if (msfp->fp != stdin)
    {
      if (lmp_fseeko (msfp->fp, *fpos * -1, SEEK_SET))
      {
        ms_log (2, "Cannot seek in file: %s (%s)\n", msfile, strerror (errno));

        return MS_GENERROR;
      }

      msfp->filepos    = *fpos * -1;
      msfp->readlen    = 0;
      msfp->readoffset = 0;
    }
  }

  /* Zero the last record indicator */
  if (last)
    *last = 0;

  /* Read data and search for records */
  for (;;)
  {
    /* Read more data into buffer if not at EOF and buffer has less than MINRECLEN
       * or more data is needed for the current record detected in buffer. */
    if (!feof (msfp->fp) && (MSFPBUFLEN (msfp) < MINRECLEN || parseval > 0))
    {
      /* Reset offsets if no unprocessed data in buffer */
      if (MSFPBUFLEN (msfp) <= 0)
      {
        msfp->readlen    = 0;
        msfp->readoffset = 0;
      }
      /* Otherwise shift existing data to beginning of buffer */
      else if (msfp->readoffset > 0)
      {
        ms_shift_msfp (msfp, msfp->readoffset);
      }

      /* Determine read size */
      readsize = (MAXRECLEN - msfp->readlen);

      /* Read data into record buffer */
      readcount = ms_fread (msfp->rawrec + msfp->readlen, 1, readsize, msfp->fp);

      if (readcount != readsize)
      {
        if (!feof (msfp->fp))
        {
          ms_log (2, "Short read of %d bytes starting from %" PRId64 "\n",
                  readsize, msfp->filepos);
          retcode = MS_GENERROR;
          break;
        }
      }

      /* Update read buffer length */
      msfp->readlen += readcount;

      /* File position corresponding to start of buffer; not strictly necessary */
      if (msfp->fp != stdin)
        msfp->filepos = lmp_ftello (msfp->fp) - msfp->readlen;
    }

    /* Test for packed file signature at the beginning of the file */
    if (msfp->filepos == 0 && *(MSFPREADPTR (msfp)) == 'P' && MSFPBUFLEN (msfp) >= 48)
    {
      msfp->packtype = 0;

      /* Determine pack type, the negative pack type indicates initial header */
      if (!memcmp ("PED", MSFPREADPTR (msfp), 3))
        msfp->packtype = -1;
      else if (!memcmp ("PSD", MSFPREADPTR (msfp), 3))
        msfp->packtype = -2;
      else if (!memcmp ("PLC", MSFPREADPTR (msfp), 3))
        msfp->packtype = -6;
      else if (!memcmp ("PQI", MSFPREADPTR (msfp), 3))
        msfp->packtype = -7;
      else if (!memcmp ("PLS", MSFPREADPTR (msfp), 3))
        msfp->packtype = -8;

      if (verbose > 0)
        ms_log (1, "Detected packed file (%3.3s: type %d)\n", MSFPREADPTR (msfp), -msfp->packtype);
    }

    /* Read pack headers, initial and subsequent headers including (ignored) chksum values */
    if (msfp->packtype && (msfp->packtype < 0 || msfp->filepos == msfp->packhdroffset) && MSFPBUFLEN (msfp) >= 48)
    {
      char hdrstr[30];
      int64_t datasize;

      /* Determine bytes to skip before header: either initial ID block or type-specific chksum block */
      packskipsize = (msfp->packtype < 0) ? 10 : packtypes[msfp->packtype][2];

      if (msfp->packtype < 0)
        msfp->packtype = -msfp->packtype;

      /* Read pack length from pack header accounting for bytes that should be skipped */
      memset (hdrstr, 0, sizeof (hdrstr));
      memcpy (hdrstr, MSFPREADPTR (msfp) + (packtypes[msfp->packtype][0] + packskipsize - packtypes[msfp->packtype][1]),
              packtypes[msfp->packtype][1]);
      sscanf (hdrstr, " %" SCNd64, &datasize);
      packdatasize = (off_t)datasize;

      /* Next pack header = File position + skipsize + header size + data size
	   * This offset is actually to the data block chksum which is skipped by the logic above,
	   * the next pack header should directly follow the chksum. */
      msfp->packhdroffset = msfp->filepos + packskipsize + packtypes[msfp->packtype][0] + packdatasize;

      if (verbose > 1)
        ms_log (1, "Read packed file header at offset %" PRId64 " (%d bytes follow), chksum offset: %" PRId64 "\n",
                (msfp->filepos + packskipsize), packdatasize,
                msfp->packhdroffset);

      /* Shift buffer to new reading offset (aligns records in buffer) */
      ms_shift_msfp (msfp, msfp->readoffset + (packskipsize + packtypes[msfp->packtype][0]));
    } /* End of packed header processing */

    /* Check for match if selections are supplied and pack header was read, */
    /* only when enough data is in buffer and not reading from stdin pipe */
    if (selections && msfp->packtype && packdatasize && MSFPBUFLEN (msfp) >= 48 && msfp->fp != stdin)
    {
      char srcname[100];

      ms_recsrcname (MSFPREADPTR (msfp), srcname, 1);

      if (!ms_matchselect (selections, srcname, HPTERROR, HPTERROR, NULL))
      {
        /* Update read position if next section is in buffer */
        if (MSFPBUFLEN (msfp) >= (msfp->packhdroffset - msfp->filepos))
        {
          if (verbose > 1)
          {
            ms_log (1, "Skipping (jump) packed section for %s (%d bytes) starting at offset %" PRId64 "\n",
                    srcname, (msfp->packhdroffset - msfp->filepos), msfp->filepos);
          }

          msfp->readoffset += (msfp->packhdroffset - msfp->filepos);
          msfp->filepos = msfp->packhdroffset;
          packdatasize  = 0;
        }

        /* Otherwise seek to next pack header and reset reading position */
        else
        {
          if (verbose > 1)
          {
            ms_log (1, "Skipping (seek) packed section for %s (%d bytes) starting at offset %" PRId64 "\n",
                    srcname, (msfp->packhdroffset - msfp->filepos), msfp->filepos);
          }

          if (lmp_fseeko (msfp->fp, msfp->packhdroffset, SEEK_SET))
          {
            ms_log (2, "Cannot seek in file: %s (%s)\n", msfile, strerror (errno));

            return MS_GENERROR;
            break;
          }

          msfp->filepos    = msfp->packhdroffset;
          msfp->readlen    = 0;
          msfp->readoffset = 0;
          packdatasize     = 0;
        }

        /* Return to top of loop for proper pack header handling */
        continue;
      }
    } /* End of selection processing */

    /* Attempt to parse record from buffer */
    if (MSFPBUFLEN (msfp) >= MINRECLEN)
    {
      int parselen = MSFPBUFLEN (msfp);

      /* Limit the parse length to offset of pack header if present in the buffer */
      if (msfp->packhdroffset && msfp->packhdroffset < (msfp->filepos + MSFPBUFLEN (msfp)))
        parselen = msfp->packhdroffset - msfp->filepos;

      parseval = msr_parse (MSFPREADPTR (msfp), parselen, ppmsr, reclen, dataflag, verbose);

      /* Record detected and parsed */
      if (parseval == 0)
      {
        if (verbose > 1)
          ms_log (1, "Read record length of %d bytes\n", (*ppmsr)->reclen);

        /* Test if this is the last record if file size is known (not pipe) */
        if (last && msfp->filesize)
          if ((msfp->filesize - (msfp->filepos + (*ppmsr)->reclen)) < MINRECLEN)
            *last = 1;

        /* Return file position for this record */
        if (fpos)
          *fpos = msfp->filepos;

        /* Update reading offset, file position and record count */
        msfp->readoffset += (*ppmsr)->reclen;
        msfp->filepos += (*ppmsr)->reclen;
        msfp->recordcount++;

        retcode = MS_NOERROR;
        break;
      }
      else if (parseval < 0)
      {
        /* Skip non-data if requested */
        if (skipnotdata)
        {
          if (verbose > 1)
          {
            if (MS_ISVALIDBLANK ((char *)MSFPREADPTR (msfp)))
              ms_log (1, "Skipped %d bytes of blank/noise record at byte offset %" PRId64 "\n",
                      MINRECLEN, msfp->filepos);
            else
              ms_log (1, "Skipped %d bytes of non-data record at byte offset %" PRId64 "\n",
                      MINRECLEN, msfp->filepos);
          }

          /* Skip MINRECLEN bytes, update reading offset and file position */
          msfp->readoffset += MINRECLEN;
          msfp->filepos += MINRECLEN;
        }
        /* Parsing errors */
        else
        {
          ms_log (2, "Cannot detect record at byte offset %" PRId64 ": %s\n",
                  msfp->filepos, msfile);

          /* Print common errors and raw details if verbose */
          ms_parse_raw (MSFPREADPTR (msfp), MSFPBUFLEN (msfp), verbose, -1);

          retcode = parseval;
          break;
        }
      }
      else /* parseval > 0 (found record but need more data) */
      {
        /* Determine implied record length if needed */
        int32_t impreclen = reclen;

        /* Check for parse hints that are larger than MAXRECLEN */
        if ((MSFPBUFLEN (msfp) + parseval) > MAXRECLEN)
        {
          if (skipnotdata)
          {
            /* Skip MINRECLEN bytes, update reading offset and file position */
            msfp->readoffset += MINRECLEN;
            msfp->filepos += MINRECLEN;
          }
          else
          {
            retcode = MS_OUTOFRANGE;
            break;
          }
        }

        /* Pack header check, if pack header offset is within buffer */
        else if (impreclen <= 0 && msfp->packhdroffset &&
                 msfp->packhdroffset < (msfp->filepos + MSFPBUFLEN (msfp)))
        {
          impreclen = msfp->packhdroffset - msfp->filepos;

          /* Check that record length is within range and a power of 2.
		   * Power of two if (X & (X - 1)) == 0 */
          if (impreclen >= MINRECLEN && impreclen <= MAXRECLEN &&
              (impreclen & (impreclen - 1)) == 0)
          {
            /* Set the record length implied by the next pack header */
            reclen = impreclen;
          }
          else
          {
            ms_log (1, "Implied record length (%d) is invalid\n", impreclen);

            retcode = MS_NOTSEED;
            break;
          }
        }

        /* End of file check */
        else if (impreclen <= 0 && feof (msfp->fp))
        {
          impreclen = msfp->filesize - msfp->filepos;

          /* Check that record length is within range and a power of 2.
		   * Power of two if (X & (X - 1)) == 0 */
          if (impreclen >= MINRECLEN && impreclen <= MAXRECLEN &&
              (impreclen & (impreclen - 1)) == 0)
          {
            /* Set the record length implied by the end of the file */
            reclen = impreclen;
          }
          /* Otherwise a trucated record */
          else
          {
            if (verbose)
            {
              if (msfp->filesize)
                ms_log (1, "Truncated record at byte offset %" PRId64 ", filesize %d: %s\n",
                        msfp->filepos, msfp->filesize, msfile);
              else
                ms_log (1, "Truncated record at byte offset %" PRId64 "\n",
                        msfp->filepos);
            }

            retcode = MS_ENDOFFILE;
            break;
          }
        }
      }
    } /* End of record detection */

    /* Finished when within MINRECLEN from EOF and buffer less than MINRECLEN */
    if ((msfp->filesize - msfp->filepos) < MINRECLEN && MSFPBUFLEN (msfp) < MINRECLEN)
    {
      if (msfp->recordcount == 0 && msfp->packtype == 0)
      {
        if (verbose > 0)
          ms_log (2, "%s: No data records read, not SEED?\n", msfile);
        retcode = MS_NOTSEED;
      }
      else
      {
        retcode = MS_ENDOFFILE;
      }

      break;
    }
  } /* End of reading, record detection and parsing loop */

  /* Cleanup target MSRecord if returning an error */
  if (retcode != MS_NOERROR)
  {
    msr_free (ppmsr);
  }

  return retcode;
} /* End of ms_readmsr_main() */
Example #7
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;
}
Example #8
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,
                 long (*allocData) (int, 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;
    hptime_t hptimetol;
    hptime_t nhptimetol;
    long data_offset;
    LinkedRecordList *recordHead = NULL;
    LinkedRecordList *recordPrevious = NULL;
    LinkedRecordList *recordCurrent = NULL;
    int datasize;


    //
    // Read all records and save them in a linked list.
    //
    int record_count = 0;
    while (offset < buflen) {
        msr = msr_init(NULL);
        retcode = msr_parse ( (mseed+offset), buflen, &msr, reclen, dataflag, verbose);
        if ( ! (retcode == MS_NOERROR)) {
            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 byteorder swapflag only for the very first record. The byteorder
        // 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;
}
Example #9
0
int main( int argc, char **argv )
{
   SHM_INFO        region;
   long            RingKey;         /* Key to the transport ring to read from */
   MSG_LOGO        getlogo[NLOGO], logo;
   long            gotsize;
   char            msg[MAX_TRACEBUF_SIZ];
   char           *getSta, *getComp, *getNet, *getLoc, *inRing;
   char            wildSta, wildComp, wildNet, wildLoc;
   unsigned char   Type_Mseed;
   unsigned char   Type_TraceBuf,Type_TraceBuf2;
   unsigned char   Type_TraceComp, Type_TraceComp2;
   unsigned char   InstWildcard, ModWildcard;
   short          *short_data;
   int            *long_data;
   TRACE2_HEADER  *trh;
   char            orig_datatype[3];
   char            stime[256];
   char            etime[256];
   int             i;
   int             rc;
   int             nLogo = NLOGO;
   static unsigned char InstId;        /* local installation id              */
   char            ModName[MAX_MOD_STR];
   char		   *modid_name;
   unsigned char   sequence_number = 0;
   // int             statistics_flag;
   time_t monitor_start_time = 0;
   double start_time, end_time;
   unsigned long packet_total=0;
   unsigned long packet_total_size=0;
   MSRecord *msr = NULL;	/* mseed record */
   logit_init("ring2mongo", 200, 256, 1); 
   char *mongo_user = getenv("MONGO_USER");
   char *mongo_passwd=getenv("MONGO_PASSWD");
   char *mongo_host=getenv("MONGO_HOST");
   char *mongo_port=getenv("MONGO_PORT");
   if(mongo_user == NULL ||
      mongo_passwd==NULL ||
      mongo_host== NULL  ||
      mongo_port==NULL){
        printf("Ensure the following ENV varibles are set\n *MONGO_USER\n *MONGO_PASSWD\n *MONGO_HOST\n *MONGO_PORT\n");
        exit(1);
        return(1);
      }
   char mongo_str[128]="mongodb://";
   
   strcat(mongo_str, mongo_user);
   strcat(mongo_str, ":");
   strcat(mongo_str, mongo_passwd);
   strcat(mongo_str, "@");
   strcat(mongo_str, mongo_host);
   strcat(mongo_str, ":");
   strcat(mongo_str, mongo_port);   
   strcat(mongo_str, "/");
   //mongo stuff
   mongoc_client_t *m_client;
   mongoc_collection_t *m_collection;
   mongoc_init ();
   m_client = mongoc_client_new (mongo_str);
   m_collection = mongoc_client_get_collection (m_client, "waveforms", "ring");
  
   mongoc_bulk_operation_t *m_bulk;
   bson_error_t m_error;
   bson_t *m_doc;
   bson_t m_reply;
   bson_t *m_data;
   /*wait for this many messages before performing bulk write
   For real time continuous data it shoudl be ~ number of channels on ring*/
   int MONGO_BULK_MAX = 30; 
   int m_count = 0; /* counter for mongo bulk */
   bool m_ret;
   /*end mongo stuff*/
   
   
   

  /* Initialize pointers
  **********************/
  trh  = (TRACE2_HEADER *) msg;
  long_data  =  (int *)( msg + sizeof(TRACE2_HEADER) );
  short_data = (short *)( msg + sizeof(TRACE2_HEADER) );


  /* Check command line argument
  
  *****************************/
  if ( argc < 2 || argc > 6)
  {
     if(argc > 6)
     fprintf(stderr, "ring2mongo: Too many parameters\n");
     fprintf(stderr,"Usage: %s <ring name> [sta] [comp] [net] [loc] \n", argv[0]);
     fprintf(stderr, " Note: All parameters are positional, and all but first are optional.\n");
     fprintf(stderr, " the full data contained in the packet is printed out.\n");
     fprintf(stderr, " If sta comp net (but not loc) are specified then only TraceBuf\n");
     fprintf(stderr, " packets will be fetched (not TraceBuf2); otherwise both are fetched.\n");
     fprintf(stderr, " Example: %s WAVE_RING PHOB wild NC wild n\n", argv[0]);
     fprintf(stderr, " MSEED capability starting with version 2.5.1, prints mseed headers\n");
     fprintf(stderr, " of TYPE_MSEED packets (no filtering yet).\n");
     exit( 1 );
     return 1;
  }

  /* process given parameters */
  inRing  = argv[1];         /* first parameter is ring name */

  /* any parameters not given are set as wildcards */
  getSta = getComp = getNet = getLoc = "";
  wildSta = wildComp = wildNet = wildLoc = 1;
  if(argc > 2)
  {  /* at least station parameter given */
    getSta = argv[2];
    wildSta  = IsWild(getSta);
    if(argc > 3)
    {  /* channel (component) parameter given */
      getComp = argv[3];
      wildComp = IsWild(getComp);
      if(argc > 4)
      {  /* network parameter given */
        getNet = argv[4];
        wildNet = IsWild(getNet);
        if(argc > 5)
        {  /* location parameter given (SCNL) */
          getLoc  = argv[5];
          wildLoc = IsWild(getLoc);
        }
        else
        {  /* SCN without location parameter given */
          nLogo = 3;    /* do not include tracebuf2s in search */
        }
      }
    }
  }


  /* Attach to ring
  *****************/
  if ((RingKey = GetKey( inRing )) == -1 )
  {
    fprintf( stderr, "Invalid RingName; exiting!\n" );
    exit( -1 );
    return -1;
  }
  tport_attach( &region, RingKey );

/* Look up local installation id
   *****************************/
   if ( GetLocalInst( &InstId ) != 0 )
   {
      fprintf(stderr, "ring2mongo: error getting local installation id; exiting!\n" );
      exit( -1 );
      return -1;
   }

  /* Specify logos to get
  ***********************/
  if ( GetType( "TYPE_MSEED", &Type_Mseed ) != 0 ) {
     fprintf(stderr, "%s: WARNING: Invalid message type <TYPE_MSEED>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     Type_Mseed = TYPE_NOTUSED;
  }
  if ( GetType( "TYPE_TRACEBUF", &Type_TraceBuf ) != 0 ) {
     fprintf(stderr, "%s: Invalid message type <TYPE_TRACEBUF>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     exit( -1 );
     return -1;
  }
  if ( GetType( "TYPE_TRACE_COMP_UA", &Type_TraceComp ) != 0 ) {
     fprintf(stderr, "%s: Invalid message type <TYPE_TRACE_COMP_UA>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     exit( -1 );
     return -1;
  }
  if ( GetType( "TYPE_TRACEBUF2", &Type_TraceBuf2 ) != 0 ) {
     fprintf(stderr, "%s: Invalid message type <TYPE_TRACEBUF2>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     exit( -1 );
     return -1;
  }
  if ( GetType( "TYPE_TRACE2_COMP_UA", &Type_TraceComp2 ) != 0 ) {
     fprintf(stderr,"%s: Invalid message type <TYPE_TRACE2_COMP_UA>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     exit( -1 );
     return -1;
  }
  if ( GetModId( "MOD_WILDCARD", &ModWildcard ) != 0 ) {
     fprintf(stderr, "%s: Invalid moduleid <MOD_WILDCARD>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     exit( -1 );
     return -1;
  }
  if ( GetInst( "INST_WILDCARD", &InstWildcard ) != 0 ) {
     fprintf(stderr, "%s: Invalid instid <INST_WILDCARD>! Missing from earthworm.d or earthworm_global.d\n", argv[0] );
     exit( -1 );
     return -1;
  }

  for( i=0; i<nLogo; i++ ) {
      getlogo[i].instid = InstWildcard;
      getlogo[i].mod    = ModWildcard;
  }
  getlogo[0].type = Type_Mseed;
  getlogo[1].type = Type_TraceBuf;
  getlogo[2].type = Type_TraceComp;
  if (nLogo >= 4) {     /* if nLogo=5 then include TraceBuf2s */
      getlogo[3].type = Type_TraceBuf2;
      getlogo[4].type = Type_TraceComp2;
  }
  logit("", "Starting ring2mongo");
  /* Flush the ring
  *****************/
  while ( tport_copyfrom( &region, getlogo, nLogo, &logo, &gotsize,
            (char *)&msg, MAX_TRACEBUF_SIZ, &sequence_number ) != GET_NONE ){
         packet_total++;
         packet_total_size+=gotsize;
  }
  logit( "et",  "ring2mongo: inRing flushed %ld packets of %ld bytes total.\n",
	packet_total, packet_total_size);

  while (tport_getflag( &region ) != TERMINATE ) {
    rc = tport_copyfrom( &region, getlogo, nLogo,
               &logo, &gotsize, msg, MAX_TRACEBUF_SIZ, &sequence_number );

    if ( rc == GET_NONE ){
      sleep_ew( 200 );
      continue;
    }

    if ( rc == GET_TOOBIG ){
      logit("et", "ring2mongo: retrieved message too big (%ld) for msg\n",
        gotsize );
      continue;
    }
    if ( rc == GET_NOTRACK )
      logit("et", "ring2mongo: Tracking error.\n");

    if ( rc == GET_MISS_LAPPED )
      logit("et", "ring2mongo: Got lapped on the ring.\n");

    if ( rc == GET_MISS_SEQGAP )
      logit( "et", "ring2mongo: Gap in sequence numbers\n");

    if ( rc == GET_MISS )
      logit( "et", "ring2mongo: Missed messages\n");

    /* Check SCNL of the retrieved message */


    if (Type_Mseed != TYPE_NOTUSED && logo.type == Type_Mseed) {
      /* Unpack record header and not data samples */
      /*hard coded zero for dataflag(1) and verbose(0)for ring2mongo*/
      if ( msr_unpack (msg, gotsize, &msr, 1, 0) != MS_NOERROR) {
         logit("et", "Error parsing mseed record\n");
         continue;
      }

      /* Print record information */
      msr_print (msr, 0);

      msr_free (&msr);
      continue;
    }
    /*end Mseed*/
    
    if ( (wildSta  || (strcmp(getSta,trh->sta)  ==0)) &&
         (wildComp || (strcmp(getComp,trh->chan)==0)) &&
         (wildNet  || (strcmp(getNet,trh->net)  ==0)) &&
         (((logo.type == Type_TraceBuf2 ||
            logo.type == Type_TraceComp2) &&
         (wildLoc  || (strcmp(getLoc,trh->loc) == 0))) ||
         ( (logo.type == Type_TraceBuf ||
             logo.type == Type_TraceComp))))
    {
      
      
      strcpy(orig_datatype, trh->datatype);
      char scnl[20];     
      scnl[0] = 0;
      strcat( scnl, trh->sta);
      strcat( scnl, ".");
      strcat( scnl, trh->chan);
      strcat( scnl, ".");
      strcat( scnl, trh->net);
      strcat( scnl, ".");
      strcat( scnl, trh->loc);
      
      if(WaveMsg2MakeLocal( trh ) < 0){
        
        char  dt[3];        
        
        /* now put a space if there are any punctuation marks */

        for ( i=0; i<15; i++ ) {
          if ( !isalnum(scnl[i]) && !ispunct(scnl[i]))
            scnl[i] = ' ';
        }
        strncpy( dt, trh->datatype, 2 );
        for ( i=0; i<2; i++ ) {
          if ( !isalnum(dt[i]) && !ispunct(dt[i]))
            dt[i] = ' ';
        }
        dt[i] = 0;
        logit("et", "WARNING: WaveMsg2MakeLocal rejected tracebuf.  Discard (%s).\n",
          scnl );
        logit("et", "\tdatatype=[%s]\n", dt);
        continue;
      }
        
      /*lets get ready to mongo....*/
      if(m_count < MONGO_BULK_MAX){
        /*initialize when m_count ==0 */
        if(m_count==0){
          m_bulk = mongoc_collection_create_bulk_operation (m_collection, true, NULL);
        }       
        m_data = bson_new ();
        m_doc = BCON_NEW ("key",   BCON_UTF8 (scnl),
                          "nsamp", BCON_INT32 (trh->nsamp),
                          "starttime", BCON_DOUBLE (trh->starttime*1000),
                          "endtime", BCON_DOUBLE (trh->endtime*1000),
                          "samprate", BCON_DOUBLE (trh->samprate),
                          "datatype", BCON_UTF8 (trh->datatype)
        );
       char index[4];
       bson_append_array_begin (m_doc, "data", -1, m_data);
        for ( i = 0; i < trh->nsamp; i++ ){
          snprintf(index, 4, "%d", i);
          if ( (strcmp (trh->datatype, "s2")==0) || (strcmp (trh->datatype, "i2")==0) ){
            bson_append_int32 (m_data, index, -1, short_data[i]);
           }else{
             bson_append_int32 (m_data, index, -1, long_data[i]);
           }
          }
        bson_append_array_end (m_doc, m_data);                             
        mongoc_bulk_operation_insert (m_bulk, m_doc);
        bson_destroy (m_doc);
        bson_destroy (m_data);
        
        m_count++;
        if(m_count==MONGO_BULK_MAX){
          
          /*write and destroty above stuff */  
          m_ret = mongoc_bulk_operation_execute (m_bulk, &m_reply, &m_error);
          if (!m_ret){
             logit ("et", "Error: %s\n", m_error.message);
           }
          bson_destroy (&m_reply);
          mongoc_bulk_operation_destroy (m_bulk);
          m_count = 0;
        }
      } 
    }
  } /* end of while loop */
  logit("et", "signing off"); 
  exit (0);
  return 0;
}
Example #10
0
/***************************************************************************
 * msr_duplicate:
 *
 * Duplicate an MSRecord struct
 * including the fixed-section data
 * header and blockette chain.  If
 * the datadup flag is true and the
 * source MSRecord has associated
 * data samples copy them as well.
 *
 * Returns a pointer to a new MSRecord on success and NULL on error.
 ***************************************************************************/
MSRecord *
msr_duplicate (MSRecord *msr, flag datadup)
{
  MSRecord *dupmsr = 0;
  int samplesize = 0;
  
  if ( ! msr )
    return NULL;
  
  /* Allocate target MSRecord structure */
  if ( (dupmsr = msr_init (NULL)) == NULL )
    return NULL;
  
  /* Copy MSRecord structure */
  memcpy (dupmsr, msr, sizeof(MSRecord));
  
  /* Copy fixed-section data header structure */
  if ( msr->fsdh )
    {
      /* Allocate memory for new FSDH structure */
      if ( (dupmsr->fsdh = (struct fsdh_s *) malloc (sizeof(struct fsdh_s))) == NULL )
	{
	  ms_log (2, "msr_duplicate(): Error allocating memory\n");
	  free (dupmsr);
	  return NULL;
	}
      
      /* Copy the contents */
      memcpy (dupmsr->fsdh, msr->fsdh, sizeof(struct fsdh_s));
    }
  
  /* Copy the blockette chain */
  if ( msr->blkts )
    {
      BlktLink *blkt = msr->blkts;
      BlktLink *next = NULL;
      
      dupmsr->blkts = 0;
      while ( blkt )
	{
	  next = blkt->next;
	  
	  /* Add blockette to chain of new MSRecord */
	  if ( msr_addblockette (dupmsr, blkt->blktdata, blkt->blktdatalen,
				 blkt->blkt_type, 0) == NULL )
	    {
	      ms_log (2, "msr_duplicate(): Error adding blockettes\n");
	      msr_free (&dupmsr);
	      return NULL;
	    }
	  
	  blkt = next;
	}
    }
  
  /* Copy data samples if requested and available */
  if ( datadup && msr->datasamples )
    {
      /* Determine size of samples in bytes */
      samplesize = ms_samplesize (msr->sampletype);
      
      if ( samplesize == 0 )
	{
	  ms_log (2, "msr_duplicate(): unrecognized sample type: '%c'\n",
		  msr->sampletype);
	  free (dupmsr);
	  return NULL;
	}
      
      /* Allocate memory for new data array */
      if ( (dupmsr->datasamples = (void *) malloc ((size_t)(msr->numsamples * samplesize))) == NULL )
	{
	  ms_log (2, "msr_duplicate(): Error allocating memory\n");
	  free (dupmsr);
	  return NULL;
	}
      
      /* Copy the data array */
      memcpy (dupmsr->datasamples, msr->datasamples, ((size_t)(msr->numsamples * samplesize)));
    }
  /* Otherwise make sure the sample array and count are zero */
  else
    {
      dupmsr->datasamples = 0;
      dupmsr->numsamples = 0;
    }
  
  return dupmsr;
} /* End of msr_duplicate() */
Example #11
0
/**********************************************************************
 * msr_parse:
 *
 * This routine will attempt to parse (detect and unpack) a Mini-SEED
 * record from a specified memory buffer and populate a supplied
 * MSRecord structure.
 *
 * If reclen is less than or equal to 0 the length of record is
 * automatically detected otherwise reclen should be the correct
 * record length.
 *
 * For auto detection of record length the record should include a
 * 1000 blockette or be followed by another record header in the
 * buffer.
 *
 * dataflag will be passed directly to msr_unpack().
 *
 * Return values:
 *   0 : Success, populates the supplied MSRecord.
 *  >0 : Data record detected but not enough data is present, the
 *       return value is a hint of how many more bytes are needed.
 *  <0 : libmseed error code (listed in libmseed.h) is returned.
 *********************************************************************/
int
msr_parse ( char *record, int recbuflen, MSRecord **ppmsr, int reclen,
	    flag dataflag, flag verbose )
{
  int detlen = 0;
  int retcode = 0;
  
  if ( ! ppmsr )
    return MS_GENERROR;
  
  if ( ! record )
    return MS_GENERROR;
  
  /* Sanity check: record length cannot be larger than buffer */
  if ( reclen > 0 && reclen > recbuflen )
    {
      ms_log (2, "ms_parse() Record length (%d) cannot be larger than buffer (%d)\n",
	      reclen, recbuflen);
      return MS_GENERROR;
    }
  
  /* Autodetect the record length */
  if ( reclen <= 0 )
    {
      detlen = ms_detect (record, recbuflen);
      
      /* No data record detected */
      if ( detlen < 0 )
	{
	  return MS_NOTSEED;
	}
      
      /* Found record but could not determine length */
      if ( detlen == 0 )
	{
	  return 256;
	}
      
      if ( verbose > 2 )
	{
	  ms_log (1, "Detected record length of %d bytes\n", detlen);
	}
      
      reclen = detlen;
    }
  
  /* Check that record length is in supported range */
  if ( reclen < MINRECLEN || reclen > MAXRECLEN )
    {
      ms_log (2, "Record length is out of range: %d (allowed: %d to %d)\n",
	      reclen, MINRECLEN, MAXRECLEN);
      
      return MS_OUTOFRANGE;
    }
  
  /* Check if more data is required, return hint */
  if ( reclen > recbuflen )
    {
      if ( verbose > 2 )
	ms_log (1, "Detected %d byte record, need %d more bytes\n",
		reclen, (reclen - recbuflen));
      
      return (reclen - recbuflen);
    }
  
  /* Unpack record */
  if ( (retcode = msr_unpack (record, reclen, ppmsr, dataflag, verbose)) != MS_NOERROR )
    {
      msr_free (ppmsr);
      
      return retcode;
    }
  
  return MS_NOERROR;
}  /* End of msr_parse() */