diff --git a/ChangeLog b/ChangeLog index 5f5fbc8..d7d125b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2023.162: + - Update libmseed to 3.0.15 with fixes for v2 packing. + 2023.161: - Update libmseed to 3.0.14 - Convert -EH option from header replacement to JSON Merge Patch diff --git a/libmseed/ChangeLog b/libmseed/ChangeLog index fb9d7f7..ed17cf1 100644 --- a/libmseed/ChangeLog +++ b/libmseed/ChangeLog @@ -1,3 +1,9 @@ +2023.162: 3.0.15 + - Print sample rate in Hz consistently in msr3_print() + - Fix writing of SNR values field 9 of Blockette 201 (v2) + - Read and write microsecond offsets to/from Blockette 500 (v2) + - Fix addition of Clock Model field 9 of Blocketee 500 (v2) + 2023.160: 3.0.14 - Add FAQ to documentation and update example code to match API changes. - Change sample type for text encoding to 't', value 'a' still supported. diff --git a/libmseed/genutils.c b/libmseed/genutils.c index 7d5939c..81bc1cd 100644 --- a/libmseed/genutils.c +++ b/libmseed/genutils.c @@ -863,7 +863,7 @@ ms_nstime2time (nstime_t nstime, uint16_t *year, uint16_t *yday, { struct tm tms; int64_t isec; - int ifract; + int32_t ifract; /* Reduce to Unix/POSIX epoch time and fractional seconds */ isec = MS_NSTIME2EPOCH (nstime); @@ -876,8 +876,9 @@ ms_nstime2time (nstime_t nstime, uint16_t *year, uint16_t *yday, ifract = NSTMODULUS - (-ifract); } - if (!(ms_gmtime64_r (&isec, &tms))) - return -1; + if (year || yday || hour || min || sec) + if (!(ms_gmtime64_r (&isec, &tms))) + return -1; if (year) *year = tms.tm_year + 1900; diff --git a/libmseed/libmseed.h b/libmseed/libmseed.h index cc3d3af..5ebdb9c 100644 --- a/libmseed/libmseed.h +++ b/libmseed/libmseed.h @@ -28,8 +28,8 @@ extern "C" { #endif -#define LIBMSEED_VERSION "3.0.14" //!< Library version -#define LIBMSEED_RELEASE "2023.160" //!< Library release date +#define LIBMSEED_VERSION "3.0.15" //!< Library version +#define LIBMSEED_RELEASE "2023.162" //!< Library release date /** @defgroup io-functions File and URL I/O */ /** @defgroup miniseed-record Record Handling */ diff --git a/libmseed/msrutils.c b/libmseed/msrutils.c index 317f87f..75147fd 100644 --- a/libmseed/msrutils.c +++ b/libmseed/msrutils.c @@ -295,7 +295,7 @@ msr3_print (MS3Record *msr, int8_t details) { ms_log (0, "%s, %d, %d, %" PRId64 " samples, %-.10g Hz, %s\n", msr->sid, msr->pubversion, msr->reclen, - msr->samplecnt, msr->samprate, time); + msr->samplecnt, msr3_sampratehz(msr), time); } } /* End of msr3_print() */ diff --git a/libmseed/pack.c b/libmseed/pack.c index 427ffec..b92f5ff 100644 --- a/libmseed/pack.c +++ b/libmseed/pack.c @@ -1148,16 +1148,27 @@ msr3_pack_header2 (MS3Record *msr, char *record, uint32_t recbuflen, int8_t verb if ((ehval = yyjson_ptr_get (ehiterval, "/Time")) && yyjson_is_str (ehval)) { - if (ms_timestr2btime (yyjson_get_str (ehval), (uint8_t *)pMS2B500_YEAR (record + written), - msr->sid, swapflag) == -1) + uint32_t l_nsec; + uint16_t l_fsec; + int8_t l_msec_offset; + + l_nsec = ms_timestr2btime (yyjson_get_str (ehval), + (uint8_t *)pMS2B500_YEAR (record + written), + msr->sid, swapflag); + + if (l_nsec == -1) { ms_log (2, "%s: Cannot convert B500 time: %s\n", msr->sid, yyjson_get_str (ehval)); yyjson_doc_free (ehdoc); return -1; } - } - *pMS2B500_MICROSECOND (record + written) = msec_offset; + /* Calculate time at fractional 100usec resolution and microsecond offset */ + l_fsec = l_nsec / 100000; + l_msec_offset = ((l_nsec / 1000) - (l_fsec * 100)); + + *pMS2B500_MICROSECOND (record + written) = l_msec_offset; + } if ((ehval = yyjson_ptr_get (ehiterval, "/ReceptionQuality")) && yyjson_is_num (ehval)) *pMS2B500_RECEPTIONQUALITY (record + written) = (uint8_t)yyjson_get_num (ehval); @@ -1168,7 +1179,7 @@ msr3_pack_header2 (MS3Record *msr, char *record, uint32_t recbuflen, int8_t verb if ((ehval = yyjson_ptr_get (ehiterval, "/Type")) && yyjson_is_str (ehval)) ms_strncpopen (pMS2B500_EXCEPTIONTYPE (record + written), yyjson_get_str (ehval), 16); - if ((ehval = yyjson_ptr_get (ehiterval, "/FDSN/Clock/Model")) && yyjson_is_str (ehval)) + if ((ehval = yyjson_ptr_get (ehroot, "/FDSN/Clock/Model")) && yyjson_is_str (ehval)) ms_strncpopen (pMS2B500_CLOCKMODEL (record + written), yyjson_get_str (ehval), 32); if ((ehval = yyjson_ptr_get (ehiterval, "/ClockStatus")) && yyjson_is_str (ehval)) @@ -1190,7 +1201,7 @@ msr3_pack_header2 (MS3Record *msr, char *record, uint32_t recbuflen, int8_t verb /* Determine which detection type: MURDOCK versus the generic type */ if ((ehval = yyjson_ptr_get (ehiterval, "/Type")) && yyjson_is_str (ehval) && - strncasecmp (yyjson_get_str (ehval), "MURDOCK", 6) == 0) + strncasecmp (yyjson_get_str (ehval), "MURDOCK", 7) == 0) { blockette_type = 201; blockette_length = 60; @@ -1265,7 +1276,7 @@ msr3_pack_header2 (MS3Record *msr, char *record, uint32_t recbuflen, int8_t verb yyjson_val *ehsubiterval; int idx = 0; - if ((ehsubarr = yyjson_ptr_get (ehiterval, "/MEDSNR")) && yyjson_is_arr (ehval)) + if ((ehsubarr = yyjson_ptr_get (ehiterval, "/MEDSNR")) && yyjson_is_arr (ehsubarr)) { yyjson_arr_iter_init (ehsubarr, &ehsubiter); diff --git a/libmseed/unpack.c b/libmseed/unpack.c index c6f09b2..565a645 100644 --- a/libmseed/unpack.c +++ b/libmseed/unpack.c @@ -796,7 +796,12 @@ msr3_unpack_mseed2 (char *record, int reclen, MS3Record **ppmsr, if (exception.time == NSTERROR) return MS_GENERROR; - exception.usec = *pMS2B500_MICROSECOND (record + blkt_offset); + /* Apply microsecond precision if non-zero */ + if (*pMS2B500_MICROSECOND (record + blkt_offset) != 0) + { + exception.time += (nstime_t)*pMS2B500_MICROSECOND (record + blkt_offset) * (NSTMODULUS / 1000000); + } + exception.receptionquality = *pMS2B500_RECEPTIONQUALITY (record + blkt_offset); exception.count = HO4u (*pMS2B500_EXCEPTIONCOUNT (record + blkt_offset), msr->swapflag); ms_strncpcleantail (exception.type, pMS2B500_EXCEPTIONTYPE (record + blkt_offset), 16); @@ -849,6 +854,7 @@ msr3_unpack_mseed2 (char *record, int reclen, MS3Record **ppmsr, msr->extralength = length; } + /* Otherwise add it to existing headers */ else { ival = *pMS2B1001_TIMINGQUALITY (record + blkt_offset); @@ -897,13 +903,10 @@ msr3_unpack_mseed2 (char *record, int reclen, MS3Record **ppmsr, mseh_free_parsestate (&parsestate); } - /* Check for a Blockette 1000 */ - if (B1000offset == 0) + /* Check for a Blockette 1000 and log warning if not found */ + if (B1000offset == 0 && verbose > 1) { - if (verbose > 1) - { - ms_log (1, "%s: Warning: No Blockette 1000 found\n", msr->sid); - } + ms_log (1, "%s: Warning: No Blockette 1000 found\n", msr->sid); } /* Check that the data offset is after the blockette chain */