Consolidating code, work on read_records!

main
Jacob Windle 2023-04-24 10:50:45 -04:00
parent 08964fdb53
commit 8665fd5bb4
3 changed files with 76 additions and 83 deletions

View File

@ -1,76 +0,0 @@
module body
# TODO: Why do this?
import Base.show
export DefinitionHeader, DataRecord, read_row
include("bytes.jl"); using.bytes
include("mesg_num.jl"); using .mesg_num
struct DefinitionHeader
endianness::AbstractString
number::Int64
fields::UInt8
end
# TODO: field_number has a string value, type has a Julia type.
struct DefinitionField
field_number::AbstractString
size::UInt8
type::UInt8
end
struct DataRecord
hdr::DefinitionHeader
end
"""
read_row(f::io)
Read a row of the file at a time. Parse the row into a data or def message.
TODO: Endianness matters here. Need to resolve endianness with the architecture bit.
"""
function read_row(f::IO)::DefinitionHeader
header_byte = read(f, 1; all=false)[1]
definition_message = Bool(bit_at(header_byte, 2))
# The message byte is 7
# hdr = RecordHeader(
# Bool(bit_at(header_byte, 2)),
# Bool(bit_at(header_byte, 1)))
# TODO: hdr if compressed timestamp needs to be handled in special way.
if definition_message
fixed_bytes = read(f, 5; all=false)
hdr = DefinitionHeader(
endianness(fixed_bytes[2]), byte_vec_to_int(fixed_bytes[3:4]), fixed_bytes[end]
)
end
hdr_fields = [hdr_field(read(f, 3; all=false)) for i 1:hdr.fields + 1]
println(hdr_fields)
hdr
end
function hdr_field(vec::Vector{UInt8})::DefinitionField
println(vec)
DefinitionField(
get_mesg_num_string(vec[1]), vec[2], vec[3]
)
end
function endianness(b::UInt8)::AbstractString
Bool(b) ? "BigEndian" : "LittleEndian"
end
function show(io::IO, header::DefinitionHeader)
print(io, "DefinitionHeader($(header.endianness), $(header.number), $(header.fields) messages)")
end
function show(io::IO, field::DefinitionField)
print(io, "DefinitionField($(field.field_number), $(field.size), $(field.type))")
end
end

View File

@ -1,6 +1,6 @@
module bytes
export byte_vec_to_int, byte_vec_to_string, bit_at
export byte_vec_to_int, byte_vec_to_string, bit_at, bit_vector
"""
read_data_size(size::Vector{UInt8})::Real
@ -36,4 +36,21 @@ function bit_at(byte::UInt8, idx::Int64; t::Type=Int64)::Int64
end
end
# byte_vec_to_string(UInt8.(collect("ABC")))
# byte_vec_to_string(UInt8.(collect("ABC")))
function bit_vector(byte::UInt8; little_endian=false)::Vector{UInt8}
range = if little_endian
8:-1:1
else
1:1:8
end
s = bitstring(byte)
[parse(UInt8, s[b]) for b in range]
end
function bit_vector(byte_vector::Vector{UInt8}; little_endian=false)::Vector{UInt8}
vecs = [bit_vector(byte; little_endian=little_endian) for byte byte_vector]
reduce(vcat, vecs)
end

View File

@ -2,7 +2,6 @@ module file
export FITFile, read_file
include("body.jl"); using .body
include("bytes.jl"); using .bytes
@ -17,16 +16,22 @@ struct FITHeader
crc::AbstractVector{<:Real}
end
mutable struct DataRecord
definition::Bool
data::Bool
end
mutable struct FITFileReader
filepath::AbstractString
fp::Union{IO, Nothing}
bytes_read::Int64
header::Union{FITHeader, Nothing}
body::Union{DefinitionHeader, Nothing}
body::Union{Vector{DataRecord}, Nothing}
end
blank_file(fp::AbstractString) = FITFileReader(fp, nothing, 0, nothing, nothing)
blank_row() = DataRecord(false, false)
"""
open_fit_file!(f::FITFileReader)
@ -47,6 +52,16 @@ function close_fit_file!(f::FITFileReader)
f.fp = nothing
end
"""
read_bytes!(f::FITFileReader, nb::Integer)::Vector{UInt8}
Read nb bytes from f, update f.bytes_read, return bytes
"""
function read_bytes!(f::FITFileReader, nb::Integer)::Vector{UInt8}
bytes = read(f.fp, nb; all=false)
f.bytes_read += max(length(bytes), nb)
bytes
end
"""
read_header(fit_file::IOStream)
@ -54,7 +69,7 @@ end
Read the header of the given fit file, and return a FITHeader struct
"""
function read_header!(f::FITFileReader)
header = read(f.fp, HEADER_SZ; all=false)
header = read_bytes!(f, HEADER_SZ)
f.header = FITHeader(
header[1],
header[2],
@ -63,7 +78,42 @@ function read_header!(f::FITFileReader)
byte_vec_to_string(header[9:12]),
header[13:14]
)
f.bytes_read += HEADER_SZ
end
"""
decode_header(v::Vector{UInt8})
Decode the header byte, determine if the record is a definition, data, or timestamp.
"""
function decode_header(v::Vector{UInt8})::DataRecord
record = blank_row()
record.definition = v[7] === 0x01
record.data = !record.definition
end
"""
read_records!(f::FITFileReader)
Read all the data record messages.
"""
function read_records!(f::FITFileReader)
if f.bytes_read < 12 || f.bytes_read > 14
throw("invalid header read, not within header size")
end
# Read header byte - decode
header_bits = bit_vector(read_bytes!(f, 1); little_endian=true)
record = decode_header(header_bits)
# Push record to the body.
if isnothing(f.body)
f.body = [record]
else
push!(f.body, record)
end
record
end
function read_file(filepath::AbstractString)::FITFileReader
@ -71,7 +121,9 @@ function read_file(filepath::AbstractString)::FITFileReader
open_fit_file!(f)
try
read_header!(f)
read_header!(f)
read_records!(f)
# read_rows!(f)
catch e
rethrow(e)
finally