diff --git a/src/body.jl b/src/body.jl deleted file mode 100644 index 1a303e5..0000000 --- a/src/body.jl +++ /dev/null @@ -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 diff --git a/src/bytes.jl b/src/bytes.jl index 95073aa..4c2f27c 100644 --- a/src/bytes.jl +++ b/src/bytes.jl @@ -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"))) \ No newline at end of file +# 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 \ No newline at end of file diff --git a/src/file.jl b/src/file.jl index 1555a46..cbf583a 100644 --- a/src/file.jl +++ b/src/file.jl @@ -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