1 unstable release
0.1.0 | Jul 13, 2019 |
---|
#2377 in Parser implementations
4.5MB
1K
SLoC
Fit (no IO)
A WebAssembly-friendly adaptation of fit by Richard Brodie. The original crate depended on the existence of a file system, meaning it could not be used in environments like WebAssembly that lack file system support. This crate requires you to pass the data directly to the parser instead of passing the file path to the parser, therefore eliminating the need for a file system.
Original description (by Brodie):
Fit is a small crate used for reading and decoding FIT files generated by various sports devices. Currently it has only been designed specifically to read files produced by Garmin Edges 1000 and 520, and a Wahoo Elemnt. It will probably mostly work out of the box with other file sources, but will probably not work 100% perfectly unless it's a Garmin cycling computer. It currently does not support FIT files using custom developer fields.
For more information about FIT, refer to the SDK from ANT (a zip archive is included in this repository).
Installation
[dependencies]
fit_no_io = "0.1"
Usage
extern crate env_logger;
extern crate fit_no_io;
use std::path::PathBuf;
use fit::{self as fit, Message};
fn main() {
let file = File::open("fits/2913547417.fit").expect("should be able to open file");
let mut buf = Vec::new();
file.read(&mut buf).expect("should be able to read file");
let f: Vec<Message> = fit::run(&buf);
println!("{:#?}", f);
}
A typical Message
will look something like this:
Message {
kind: Record,
values: [
DataField { field_num: 253, value: Time(1480856114) },
DataField { field_num: 0, value: F32(57.710945) },
DataField { field_num: 1, value: F32(11.9945755) },
DataField { field_num: 5, value: U32(1151) },
DataField { field_num: 29, value: U32(0) },
DataField { field_num: 2, value: U16(2394) },
DataField { field_num: 6, value: U16(0) },
DataField { field_num: 7, value: U16(0) },
DataField { field_num: 61, value: U16(2234) },
DataField { field_num: 66, value: I16(442) },
DataField { field_num: 3, value: U8(113) },
DataField { field_num: 13, value: I8(21) }
],
dev_values: []
}
FIT Crash Course
If you are already intimately familiar with the FIT file format, you should probably skip this section. Otherwise, read on.
Caveat
This is a crash course (i.e., a dramatic over-simplification), not a comprehensive guide to FIT. For a more thorough guide, refer to the ANT FIT SDK.
Now that you've been warned...
A FIT file is basically a list of Message
s. Each Message
is basically just an object/hash map/dictionary/whatever you call something that associates keys to values.
There are many kind
s of Message
s. Each kind
has a different purpose, and each has its own shape (i.e., what properties they have). For example, a UserProfile
Message
will have different properties than a Record
Message
. That is, UserProfile
Message
probably contains information such as the user's height and weight, while the Record
Message
probably contains information about the user's heart rate and speed at a given point in time.
Ideally, Message
in Rust would look something like this:
struct Message {
kind: MessageType,
values: HashMap<Attribute, Value>,
}
enum Attribute {
Timestamp,
Distance,
Speed,
HeartRate,
Cadence,
// ...
}
// `Value` will be explained later
In reality, because of the way FIT works, it looks something more like this:
struct Message {
kind: MessageType,
values: Vec<DataField>,
}
A DataField
is a key-value pair. It's similar to the key-value pair you use to build a HashMap
(i.e., when you build a HashMap from an iterator of tuples vec![(key1, value1), (key2, value2), ...].into_iter().collect()
), but the difference is that instead of having the actual key, DataField
has a field_num
member that can be used in conjuction with the kind
of the Message
to determine the actual key. This is done because different kind
s of Message
s have different rules for what key a given field_num
refers to. For instance, field 0
of a Record
Message
is the user's latitude, while field 0
of a DeviceInfo
Message
is the device index. For a table mapping field_num
s and Message
kind
s to properties, refer to the ANT FIT SDK.
A Value
enum is a simple wrapper around most rust primitive types, such as u16 or i64 or f32.
Some things to watch out for:
- Speed is recorded as m/s, rather than kph.
- For running, cadence is recorded as cycles per minute, as opposed to strides per minute, where one cycle is defined as a stride with the left foot plus a stride with the right foot. If your cadence is listed as
90
, it means it is 90 cycles per minute, which equals 180 strides per minute.
Contributing
Repository of original crate: https://github.com/richardbrodie/fit-rs.
Repository of this crate: https://github.com/kylejlin/fit_no_io.
Thanks
Thanks to Richard Brodie for developing the original crate. 99% of this crate was taken from his fit.