/*************************************************************************** * msr_update_header: * * Update the header values that change between records: start time, * sequence number, etc. * * Returns 0 on success or -1 on error. ***************************************************************************/ static int msr_update_header ( MSRecord *msr, char *rawrec, flag swapflag, struct blkt_1001_s *blkt1001, flag verbose ) { struct fsdh_s *fsdh; char seqnum[7]; if ( ! msr || ! rawrec ) return -1; if ( verbose > 2 ) ms_log (1, "%s: Updating fixed section of data header\n", PACK_SRCNAME); fsdh = (struct fsdh_s *) rawrec; /* Pack values into the fixed section of header */ snprintf (seqnum, 7, "%06d", msr->sequence_number); memcpy (fsdh->sequence_number, seqnum, 6); /* Update fixed-section start time */ ms_hptime2btime (msr->starttime, &(fsdh->start_time)); /* Swap byte order? */ if ( swapflag ) { MS_SWAPBTIME (&fsdh->start_time); } /* Update microseconds if Blockette 1001 is present */ if ( msr->Blkt1001 && blkt1001 ) { hptime_t sec, usec; /* Calculate microseconds offset */ sec = msr->starttime / (HPTMODULUS / 10000); usec = msr->starttime - (sec * (HPTMODULUS / 10000)); usec /= (HPTMODULUS / 1000000); /* Update microseconds offset in blockette chain entry */ msr->Blkt1001->usec = (int8_t) usec; /* Update microseconds offset in packed header */ blkt1001->usec = (int8_t) usec; } return 0; } /* End of msr_update_header() */
/*************************************************************************** * msr_update_header: * * Update the header values that change between records: start time, * sequence number, etc. * * Returns 0 on success or -1 on error. ***************************************************************************/ static int msr_update_header (MSRecord *msr, char *rawrec, flag swapflag, struct blkt_1001_s *blkt1001, char *srcname, flag verbose) { struct fsdh_s *fsdh; hptime_t hptimems; int8_t usecoffset; char seqnum[7]; if (!msr || !rawrec) return -1; if (verbose > 2) ms_log (1, "%s: Updating fixed section of data header\n", srcname); fsdh = (struct fsdh_s *)rawrec; /* Pack values into the fixed section of header */ snprintf (seqnum, 7, "%06d", msr->sequence_number); memcpy (fsdh->sequence_number, seqnum, 6); /* Get start time rounded to tenths of milliseconds and microsecond offset */ ms_hptime2tomsusecoffset (msr->starttime, &hptimems, &usecoffset); /* Update fixed-section start time */ ms_hptime2btime (hptimems, &(fsdh->start_time)); /* Swap byte order? */ if (swapflag) { MS_SWAPBTIME (&fsdh->start_time); } /* Update microsecond offset value if Blockette 1001 is present */ if (msr->Blkt1001 && blkt1001) { /* Update microseconds offset in blockette chain entry */ msr->Blkt1001->usec = usecoffset; /* Update microseconds offset in packed header */ blkt1001->usec = usecoffset; } return 0; } /* End of msr_update_header() */
/*************************************************************************** * ds_streamproc: * * Save MiniSEED records in a custom directory/file structure. The * appropriate directories and files are created if nesecessary. If * files already exist they are appended to. If 'msr' is NULL then * ds_shutdown() will be called to close all open files and free all * associated memory. * * This version has been modified from others to add the add the suffix * integer supplied with ds_streamproc() to the defkey and file name. * * Returns 0 on success, -1 on error. ***************************************************************************/ extern int ds_streamproc (DataStream *datastream, MSRecord *msr, long suffix, int verbose) { DataStreamGroup *foundgroup = NULL; BTime stime; strlist *fnlist, *fnptr; char net[3], sta[6], loc[3], chan[4]; char filename[400]; char definition[400]; char pathformat[600]; char tstr[20]; int fnlen = 0; /* Set Verbosity for ds_ functions */ dsverbose = verbose; /* Special case for stream shutdown */ if ( ! msr ) { if ( dsverbose >= 1 ) fprintf (stderr, "Closing archiving for: %s\n", datastream->path ); ds_shutdown ( datastream ); return 0; } if ( ! msr->fsdh ) { fprintf (stderr, "ds_streamproc(): msr->fsdh must be available\n"); return -1; } /* Build file path and name from datastream->path */ filename[0] = '\0'; definition[0] = '\0'; snprintf (pathformat, sizeof(pathformat), "%s", datastream->path); strparse (pathformat, "/", &fnlist); fnptr = fnlist; /* Special case of an absolute path (first entry is empty) */ if ( *fnptr->element == '\0' ) { if ( fnptr->next != 0 ) { strncat (filename, "/", sizeof(filename)); fnptr = fnptr->next; } else { fprintf (stderr, "ds_streamproc(): empty path format\n"); strparse (NULL, NULL, &fnlist); return -1; } } /* Convert normalized starttime to BTime structure */ if ( ms_hptime2btime (msr->starttime, &stime) ) { fprintf (stderr, "ds_streamproc(): cannot convert start time to separate fields\n"); strparse (NULL, NULL, &fnlist); return -1; } while ( fnptr != 0 ) { int tdy; char *w, *p, def; p = fnptr->element; /* Special case of no file given */ if ( *p == '\0' && fnptr->next == 0 ) { fprintf (stderr, "ds_streamproc(): no file name specified, only %s\n", filename); strparse (NULL, NULL, &fnlist); return -1; } while ( (w = strpbrk (p, "%#")) != NULL ) { def = ( *w == '%' ); *w = '\0'; strncat (filename, p, (sizeof(filename) - fnlen)); fnlen = strlen (filename); w += 1; switch ( *w ) { case 'n' : ms_strncpclean (net, msr->fsdh->network, 2); strncat (filename, net, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, net, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 's' : ms_strncpclean (sta, msr->fsdh->station, 5); strncat (filename, sta, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, sta, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'l' : ms_strncpclean (loc, msr->fsdh->location, 2); strncat (filename, loc, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, loc, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'c' : ms_strncpclean (chan, msr->fsdh->channel, 3); strncat (filename, chan, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, chan, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'Y' : snprintf (tstr, sizeof(tstr), "%04d", (int) stime.year); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'y' : tdy = (int) stime.year; while ( tdy > 100 ) { tdy -= 100; } snprintf (tstr, sizeof(tstr), "%02d", tdy); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'j' : snprintf (tstr, sizeof(tstr), "%03d", (int) stime.day); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'H' : snprintf (tstr, sizeof(tstr), "%02d", (int) stime.hour); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'M' : snprintf (tstr, sizeof(tstr), "%02d", (int) stime.min); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'S' : snprintf (tstr, sizeof(tstr), "%02d", (int) stime.sec); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'F' : snprintf (tstr, sizeof(tstr), "%04d", (int) stime.fract); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'q' : snprintf (tstr, sizeof(tstr), "%c", msr->dataquality); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'L' : snprintf (tstr, sizeof(tstr), "%d", msr->reclen); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'r' : snprintf (tstr, sizeof(tstr), "%ld", (long int) (msr->samprate+0.5)); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case 'R' : snprintf (tstr, sizeof(tstr), "%.6f", msr->samprate); strncat (filename, tstr, (sizeof(filename) - fnlen)); if ( def ) strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case '%' : strncat (filename, "%", (sizeof(filename) - fnlen)); fnlen = strlen (filename); p = w + 1; break; case '#' : strncat (filename, "#", (sizeof(filename) - fnlen)); fnlen = strlen (filename); p = w + 1; break; default : fprintf (stderr, "Unknown layout format code: '%c'\n", *w); p = w; break; } } strncat (filename, p, (sizeof(filename) - fnlen)); fnlen = strlen (filename); /* If not the last entry then it should be a directory */ if ( fnptr->next != 0 ) { if ( access (filename, F_OK) ) { if ( errno == ENOENT ) { if ( dsverbose >= 1 ) fprintf (stderr, "Creating directory: %s\n", filename); if (mkdir (filename, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) { fprintf (stderr, "ds_streamproc: mkdir(%s) %s\n", filename, strerror (errno)); strparse (NULL, NULL, &fnlist); return -1; } } else { fprintf (stderr, "%s: access denied, %s\n", filename, strerror(errno)); strparse (NULL, NULL, &fnlist); return -1; } } strncat (filename, "/", (sizeof(filename) - fnlen)); fnlen++; } fnptr = fnptr->next; } strparse (NULL, NULL, &fnlist); /* Add ".suffix" to filename and definition if suffix is not 0 */ if ( suffix ) { snprintf (tstr, sizeof(tstr), ".%ld", suffix); strncat (filename, tstr, (sizeof(filename) - fnlen)); strncat (definition, tstr, (sizeof(definition) - fnlen)); fnlen = strlen (filename); } /* Make sure the filename and definition are NULL terminated */ *(filename + sizeof(filename) - 1) = '\0'; *(definition + sizeof(definition) -1) = '\0'; /* Check for previously used stream entry, otherwise create it */ foundgroup = ds_getstream (datastream, msr, definition, filename); if (foundgroup != NULL) { /* Write binary data samples to approriate file */ if ( msr->datasamples && msr->numsamples ) { if ( dsverbose >= 3 ) fprintf (stderr, "Writing binary data samples to data stream file %s\n", filename); if ( !write (foundgroup->filed, msr->datasamples, msr->numsamples * ms_samplesize(msr->sampletype)) ) { fprintf (stderr, "ds_streamproc: failed to write binary data samples\n"); return -1; } else { foundgroup->modtime = time (NULL); } } /* Write the data record to the appropriate file */ else { if ( dsverbose >= 3 ) fprintf (stderr, "Writing data record to data stream file %s\n", filename); if ( !write (foundgroup->filed, msr->record, msr->reclen) ) { fprintf (stderr, "ds_streamproc: failed to write data record\n"); return -1; } else { foundgroup->modtime = time (NULL); } } return 0; } return -1; } /* End of ds_streamproc() */
/*************************************************************************** * msr_normalize_header: * * Normalize header values between the MSRecord struct and the * associated fixed-section of the header and blockettes. Essentially * this updates the SEED structured data in the MSRecord.fsdh struct * and MSRecord.blkts chain with values stored at the MSRecord level. * * Returns the header length in bytes on success or -1 on error. ***************************************************************************/ int msr_normalize_header ( MSRecord *msr, flag verbose ) { struct blkt_link_s *cur_blkt; char seqnum[7]; int offset = 0; int blktcnt = 0; int reclenexp = 0; int reclenfind; if ( ! msr ) return -1; /* Update values in fixed section of data header */ if ( msr->fsdh ) { if ( verbose > 2 ) ms_log (1, "Normalizing fixed section of data header\n"); /* Roll-over sequence number if necessary */ if ( msr->sequence_number > 999999 ) msr->sequence_number = 1; /* Update values in the MSRecord.fsdh struct */ snprintf (seqnum, 7, "%06d", msr->sequence_number); memcpy (msr->fsdh->sequence_number, seqnum, 6); msr->fsdh->dataquality = msr->dataquality; msr->fsdh->reserved = ' '; ms_strncpopen (msr->fsdh->network, msr->network, 2); ms_strncpopen (msr->fsdh->station, msr->station, 5); ms_strncpopen (msr->fsdh->location, msr->location, 2); ms_strncpopen (msr->fsdh->channel, msr->channel, 3); ms_hptime2btime (msr->starttime, &(msr->fsdh->start_time)); /* When the sampling rate is <= 32767 Hertz determine the factor * and multipler through rational approximation. For higher rates * set the factor and multiplier to 0. */ if ( msr->samprate <= 32767.0 ) { ms_genfactmult (msr->samprate, &(msr->fsdh->samprate_fact), &(msr->fsdh->samprate_mult)); } else { if ( verbose > 1 ) ms_log (1, "Sampling rate too high to approximate factor & multiplier: %g\n", msr->samprate); msr->fsdh->samprate_fact = 0; msr->fsdh->samprate_mult = 0; } offset += 48; if ( msr->blkts ) msr->fsdh->blockette_offset = offset; else msr->fsdh->blockette_offset = 0; } /* Traverse blockette chain and performs necessary updates*/ cur_blkt = msr->blkts; if ( cur_blkt && verbose > 2 ) ms_log (1, "Normalizing blockette chain\n"); while ( cur_blkt ) { offset += 4; if ( cur_blkt->blkt_type == 100 && msr->Blkt100 ) { msr->Blkt100->samprate = (float)msr->samprate; offset += sizeof (struct blkt_100_s); } else if ( cur_blkt->blkt_type == 1000 && msr->Blkt1000 ) { msr->Blkt1000->byteorder = msr->byteorder; msr->Blkt1000->encoding = msr->encoding; /* Calculate the record length as an exponent of 2 */ for (reclenfind=1, reclenexp=1; reclenfind <= MAXRECLEN; reclenexp++) { reclenfind *= 2; if ( reclenfind == msr->reclen ) break; } if ( reclenfind != msr->reclen ) { ms_log (2, "msr_normalize_header(): Record length %d is not a power of 2\n", msr->reclen); return -1; } msr->Blkt1000->reclen = reclenexp; offset += sizeof (struct blkt_1000_s); } else if ( cur_blkt->blkt_type == 1001 ) { hptime_t sec, usec; /* Insert microseconds offset */ sec = msr->starttime / (HPTMODULUS / 10000); usec = msr->starttime - (sec * (HPTMODULUS / 10000)); usec /= (HPTMODULUS / 1000000); msr->Blkt1001->usec = (int8_t) usec; offset += sizeof (struct blkt_1001_s); } blktcnt++; cur_blkt = cur_blkt->next; } if ( msr->fsdh ) msr->fsdh->numblockettes = blktcnt; return offset; } /* End of msr_normalize_header() */