module ClockParser export get_skew function _parse_line(line::AbstractString) time, high, _ = split(line) parse(Float64, time), parse(Float64, high) end """ get_skew(file::T) where {T <: AbstractString} -> Union{Float64, Missing} Get skew from clock result file `file`. It returns `missing` for invalid files. To see the detailed reason, increase log level to `DEBUG`. Invalid cases are: - first line has >0 counts => "Unexpected first line" - no measurement has >500 counts => "Clock skew out of range" """ function get_skew(file::T) where {T <: AbstractString} # @debug "file: $(file)" lines = Iterators.Stateful(eachline(file)) was_0_before = false # criteria is changed from QAQC for skew parsing let first_line = popfirst!(lines) time, high = _parse_line(first_line) if high == 0 was_0_before = true end end time_and_counts = Iterators.map(_parse_line, lines) for (time, high) in time_and_counts if high == 0 was_0_before = true elseif was_0_before && high >= 500 return time end end @debug "Clock skew out of range (file: $(file))" return missing end """ search_oscillation(file::T) where {T <: AbstractString} Search oscillation (two or more rise up) for clock measurement file. """ function count_riseup(file::T) where {T <: AbstractString} lines = Iterators.Stateful(eachline(file)) rising_count = 0 first_line = popfirst!(lines) is_high = let time, high = _parse_line(first_line) high >= 500 end time_and_counts = Iterators.map(_parse_line, lines) for (time, high) in time_and_counts if !is_high && high >= 500 is_high = true rising_count += 1 elseif is_high && high < 500 is_high = false end end return rising_count # lines = eachline(file) # time_and_counts = Iterators.map(_parse_line, lines) # is_high = Iterators.map(time_and_counts) do (time, counts) # counts >= 500 # end # edges = Iterators.map(accumulate((p, n) -> (n, !p[1] & n), is_high, init = (false, false))) do x # _prev, edge = x # edge # end # # return sum(edges) end """ Return Tuple of - skew (first time >500) - rise up full (last 0 to first 1000) If clock is abnormal (i.e., which returns `missing` when [`get_skew`](@ref) is applied), this returns Tuple of 2 `missing`s. """ function get_skew_and_riseup(file::T) where {T <: AbstractString} lines = Iterators.Stateful(eachline(file)) last_low_time = missing first_high_time = missing skew = missing is_rised = false let _time, high = _parse_line(popfirst!(lines)) if high == 0 last_low_time = time end end for line in lines time, high = _parse_line(line) if high == 0 last_low_time = time elseif !ismissing(last_low_time) && !is_rised && high >= 500 skew = time is_rised = true elseif !ismissing(skew) && high == 1000 first_high_time = time break end end if first_high_time === missing @debug "Clock skew out of range" return (missing, missing) end return (skew, first_high_time - last_low_time) end end # module ClockParser