From 0e1cfe4b493967c5117ee8d90c58142052039eb1 Mon Sep 17 00:00:00 2001 From: Andy Nowacki Date: Tue, 25 Jul 2023 09:44:41 +0100 Subject: [PATCH] Upgrade libmseed library to v3.0.16 The new v3.0.16 of libmseed has a different API to the previous unstable v3 versions, so a minor upgrade of the library is needed. - Update installation instructions since the package is registered. - Update C types to match new libmseed structs. - Add tests for Julia type constructors. --- NEWS.md | 8 ++++++++ Project.toml | 4 ++-- README.md | 9 ++++++--- src/c_types.jl | 19 +++++++++++-------- src/io.jl | 2 +- src/julia_types.jl | 29 +++++++++++++++++++---------- src/nanoseconddatetime.jl | 4 ++++ test/julia_types.jl | 12 ++++++++++++ test/runtests.jl | 1 + 9 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 test/julia_types.jl diff --git a/NEWS.md b/NEWS.md index b3f97e5..a695a1b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,11 @@ +# LibMseed.jl v0.3.0 release notes + +## libmseed library version + +- libmseed version v3.0.16 is required. This is the first stable + version of libmseed v3. + + # LibMseed.jl v0.2.1 release notes ## Notable bug fixes diff --git a/Project.toml b/Project.toml index 9ff9639..b58df0b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LibMseed" uuid = "1f77302d-495a-4b02-8d15-b81beb84162e" authors = ["Andy Nowacki "] -version = "0.2.1" +version = "0.3.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" @@ -9,7 +9,7 @@ libmseed_jll = "ccc2c699-b150-5417-88f2-a95a0d1581d9" [compat] julia = "1.6" -libmseed_jll = "3.0.10" +libmseed_jll = "3.0.16" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/README.md b/README.md index 2072812..b67bc11 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,12 @@ and writing data in the miniSEED format. You can install LibMseed.jl from Julia's package manager like so: ```julia -julia> using Pkg; Pkg.add(url="https://github.com/anowacki/LibMseed.jl") +julia> using Pkg; Pkg.add("LibMseed") ``` +You do not need to separately install the `libmseed` library. Instead, +LibMseed.jl installs its own version automatically. + ## Using the package `LibMseed` exports several functions with common names, such as `read_file` @@ -40,7 +43,7 @@ MseedTraceList: ``` ### Reading data from memory -Use the unexported `LibMseed.read_buffer` function to read miniSEED data +Use the `LibMseed.read_buffer` function to read miniSEED data from memory. This data should be a `Vector` of `UInt8`s. ```julia @@ -118,7 +121,7 @@ set to `nothing`. ### Writing data To write a continuous set of evenly-spaced samples to disk in miniSEED -format, use the unexported `LibMseed.write_file` function. +format, use the `LibMseed.write_file` function. Here we create some random data, set the necessary parameters (including the date of the first sample) and write it to a new file, `"example2.mseed"`. diff --git a/src/c_types.jl b/src/c_types.jl index be674a6..78cd28a 100644 --- a/src/c_types.jl +++ b/src/c_types.jl @@ -48,11 +48,11 @@ const MSF_MAINTAINMSTL = 0x0200 const nstime_t = Int64 # C structs used for libmseed -struct MS3Record +@eval struct MS3Record record::Cstring reclen::Int32 swapflag::UInt8 - sid::NTuple{64, UInt8} + sid::NTuple{$LM_SIDLEN, UInt8} formatversion::UInt8 flags::UInt8 starttime::nstime_t @@ -116,8 +116,10 @@ struct MS3TraceSeg next::Ptr{MS3TraceSeg} end -struct MS3TraceID - sid::NTuple{64, UInt8} +const MSTRACEID_SKIPLIST_HEIGHT = 8 + +@eval struct MS3TraceID + sid::NTuple{$LM_SIDLEN, UInt8} pubversion::UInt8 earliest::nstime_t latest::nstime_t @@ -125,13 +127,14 @@ struct MS3TraceID numsegments::UInt32 first::Ptr{MS3TraceSeg} last::Ptr{MS3TraceSeg} - next::Ptr{MS3TraceID} + next::NTuple{$MSTRACEID_SKIPLIST_HEIGHT, Ptr{MS3TraceID}} + height::UInt8 end struct MS3TraceList - numtraces::UInt32 - traces::Ptr{MS3TraceID} - last::Ptr{MS3TraceID} + numtraceids::UInt32 + traces::MS3TraceID + prngstate::UInt64 end struct MS3Tolerance diff --git a/src/io.jl b/src/io.jl index 973cc33..b0a02f5 100644 --- a/src/io.jl +++ b/src/io.jl @@ -402,7 +402,7 @@ _file_message(file) = file !== nothing ? " in file '$file'" : "" If `time_tolerance` is not `nothing`, create a closure over `time_tolerance` and return a `Base.CFunction` and an `MS3Tolerance` -containing a reference to +containing a reference to the function. `func_pointer` should be guarded in a `Base.@GC_preserve` block when `tolerance` is used to avoid the former being garbage collected. diff --git a/src/julia_types.jl b/src/julia_types.jl index 8b41110..fde43ed 100644 --- a/src/julia_types.jl +++ b/src/julia_types.jl @@ -112,24 +112,30 @@ This function builds a full `MseedTraceList` and copies the data from `mstl`. """ function MseedTraceList(mstl::Ref{Ptr{MS3TraceList}}) + @debug "Making MseedTraceList from $(mstl[])" + if mstl[] == C_NULL + throw(ArgumentError("cannot create a MseedTraceList from a null pointer")) + end + this_tracelist = unsafe_load(mstl[]) - numtraces = Int32(this_tracelist.numtraces) - tracelist = MseedTraceList(Vector{MseedTraceID}(undef, numtraces)) + numtraceids = Int32(this_tracelist.numtraceids) + tracelist = MseedTraceList(Vector{MseedTraceID}(undef, numtraceids)) - # Follow linked list through MS3TraceIDs - this_traceid = unsafe_load(this_tracelist.traces) # First - for itraceid in 1:numtraces + # Follow skip list through MS3TraceIDs + @debug "Attempting to load trace id $(this_tracelist.traces.next[1])" + this_traceid = unsafe_load(this_tracelist.traces.next[1]) # First + for itraceid in 1:numtraceids tracelist.traces[itraceid] = MseedTraceID(this_traceid) # Move to the next trace id - if itraceid != numtraces && this_traceid.next == C_NULL + if itraceid != numtraceids && this_traceid.next[1] == C_NULL error("unexpectedly reached end of trace id list") - elseif itraceid == numtraces && this_traceid.next != C_NULL + elseif itraceid == numtraceids && this_traceid.next[1] != C_NULL @warn("unexpected extra trace ids in list") break end - if itraceid != numtraces - this_traceid = unsafe_load(this_traceid.next) + if itraceid != numtraceids + this_traceid = unsafe_load(this_traceid.next[1]) end end @@ -183,7 +189,10 @@ from a call to one of `libmseed`'s functions. function MseedTraceSegment(T, this_traceseg::MS3TraceSeg) starttime = NanosecondDateTime(this_traceseg.starttime) endtime = NanosecondDateTime(this_traceseg.endtime) - sample_rate = this_traceseg.samprate + # Note that negative sampling rates mean a sampling interval + sample_rate = this_traceseg.samprate >= 0 ? + this_traceseg.samprate : + -1/this_traceseg.samprate sample_count = this_traceseg.samplecnt numsamples = Int(this_traceseg.numsamples) samples_ptr = convert(Ptr{T}, this_traceseg.datasamples) diff --git a/src/nanoseconddatetime.jl b/src/nanoseconddatetime.jl index 55fcf5c..f4f690e 100644 --- a/src/nanoseconddatetime.jl +++ b/src/nanoseconddatetime.jl @@ -17,6 +17,10 @@ to the millisecond resolution that `DateTime` offers. # Other functions - [`nearest_datetime`](@ref): Return the `Dates.DateTime` nearest to the `NanosecondDateTime`. + +# Extended `Dates` functions +- `Date`: Return the `Date` part of a `NanosecondDateTime`. +- `Time`: Return the `Time` part of a `NanosecondDateTime` to full ns precision. """ struct NanosecondDateTime "`DateTime`, to millisecond resolution" diff --git a/test/julia_types.jl b/test/julia_types.jl new file mode 100644 index 0000000..6bbd7cc --- /dev/null +++ b/test/julia_types.jl @@ -0,0 +1,12 @@ +using Test +using LibMseed + +@testset "MseedTraceList" begin + @testset "Construction" begin + @testset "Errors" begin + @test_throws ArgumentError MseedTraceList( + Ref(Ptr{LibMseed.MS3TraceList}(C_NULL)) + ) + end + end +end diff --git a/test/runtests.jl b/test/runtests.jl index e647973..29eaca1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,6 +2,7 @@ using Test @testset "All tests" begin include("nanoseconddatetime.jl") + include("julia_types.jl") include("io.jl") include("channel_codes.jl") end