fit_no_io 0.1.0

A small crate used for reading and decoding FIT files generated by sports devices that works without a file system.
Documentation
# Fit (no IO)

A WebAssembly-friendly adaptation of [fit](https://github.com/richardbrodie/fit-rs) by [Richard Brodie](https://github.com/richardbrodie). 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

```toml
[dependencies]
fit_no_io = "0.1"
```

## Usage

```rust
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:

```rust
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:

```rust
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:

```rust
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](https://github.com/richardbrodie) for developing the original crate. 99% of this crate was taken from his [fit](https://github.com/richardbrodie/fit-rs).