- この記事は 2015年08月01日 にQiitaへ投稿した内容を転記したものです。
- 本記事は執筆から1年以上が経過しています。
- 関連記事
はじめに
Garminのフィットネスデバイスなどで使用されているFIT *1 ファイルのデータフォーマット概要とFIT SDKを使用してエンコード/デコードを行うサンプルコードに関する記事です。
例えば、Garmin Edgeで記録した自転車の走行データを表示・解析・編集(補正)するようなアプリ開発に興味がある方向けの記事です。 *2
目次
- FITファイルフォーマット
- FIT SDK & サンプルコード
FITファイルフォーマット
FITファイルのデータフォーマット概要です。 ほぼSDKのドキュメントから引用したものですので、より詳細な仕様はFIT SDKに同梱されているドキュメントを参照してください。
概要図
D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7.pdf (P.11)
Header
Byte | Parameter | Description |
---|---|---|
0 | Header Size | Headerのサイズで、通常14(0x0E) が入ります。レガシーなデータは12(0x0C) で、HeaderのCRCが存在しないデータになります。 |
1 | Protocol Version | Protocol version |
2 | Profile Version LSB | Profile Version |
3 | Profile Version MSB | |
4 | Data Size LSB | Headerとファイル終端のCRCを除いたデータのサイズ。 |
5 | Data Size | |
6 | Data Size | |
7 | Data Size MSB | |
8 | Data Type Byte[0] | ASCII文字コードで".FIT" を格納する。つまり Data Type Byte[0] から順に{0x2E, 0x46, 0x49, 0x54} を格納します。 |
9 | Data Type Byte[1] | |
10 | Data Type Byte[2] | |
11 | Data Type Byte[3] | |
12 | CRC LSB | HeaderのCRCで、0~11Byteのデータから算出して格納する。このCRCはOptionalで、0x0000 が設定されていることがあります。 *3 |
13 | CRC MSB |
Data Records
1ByteのRecord Headerとそれに続くRecord Contentで構成されます。
Record Header
Record Headerは2種類あり、最上位bitでどちらかが特定できます。
1. Normal Header
Headerの最上位bitが 0。
以下の仕様を見れば分かりますが、バイナリエディタで見た時に0x4X
で始まってるのがDefinition Message
で、0x0X
で始まってるのがData Message
と、ある程度見当をつけることはできます。 *4
bit | Value | Description |
---|---|---|
7 | 0 | Normal Header |
6 | 0 or 1 | Message Type 1: Definition Message 0: Data Message |
5 | 0 | Reserved |
4 | 0 | Reserved |
0 - 3 | 0 - 15 | Local Message Type |
2. Compressed Timestamp Header
Headerの最上位bitが 1。 今回は説明を省略します。
Definition Message
D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7.pdf (P.19)
以降に続く実際のデータであるData Message
の種類やデータサイズの定義です。
この定義とData Message
の紐付けはLocal Message Type
で行なわれます。
1つのFITファイルで同じLocal Message Type
のDefinition Message
が複数回出現することがありますが、これは定義の更新(再定義)です。定義の更新はData Message
のフィールド数増減などで発生し、以降のData Message
は更新後の定義をもとにエンコードする必要があります。
Byte | Parameter | Description |
---|---|---|
0 | Normal Header | 0x40 ~0x4F のいずれかの値が格納されます。下位bitの 0 ~F がLocal Message Type です。 |
1 | Reserved | |
2 | Architecture | Data Message に格納されているデータのエンディアン(バイトオーダ)です。0: Little Endian 1: Big Endian |
3 - 4 | Global Message Number | Data Message の種別。例えば、 Recode の場合は20(0x14) が格納されています。エンディアンは Architecture 依存です。 |
5 | Fields | Data Message に含まれるフィールド数。 |
6 - END | Field Definition | Data Message に含まれる各フィールドの定義。フィールド1つにつき3Byteで、それがフィールド数分あります。 |
Field Definition
Data Messageに含まれている各フィールドに対する定義です。
Byte | Parameter | Description |
---|---|---|
0 | Field Definition Number | データの種別。例えばRecode のMessageであれば、スピード、ケイデンス、パワー等を表す数値が格納されています。 |
1 | Size | フィールドのデータサイズ。単位はByte。 |
2 | Base Type | フィールドのデータ型。byte 、enum 、string 、sint8 など14種あります。 |
Data Message
D00001275 Flexible & Interoperable Data Transfer (FIT) Protocol Rev 1.7.pdf (P.21)
実際のデータに相当する部分で、フィールドごとのデータが格納されています。
Normal Header
のLocal Message Type
から対応するDefinition Message
を特定してデータをデコードします。
Byte | Parameter | Description |
---|---|---|
0 | Normal Header |
0x00 ~0x0F のいずれかの値が格納されます。下位bitの 0 ~F がLocal Message Type です。 |
1 - END | Data Fields | Definition Message で定義されたフィールド数分データが続きます。各フィールドのデータサイズは Field Definition で定義されている通りです。 |
CRC
HeaderとData Recordsのデータから算出したCRCを2Byte(Little Endian)で記録します。 実際の算出処理などはSDKのソース・ドキュメント・サンプルコードを参照してください。
FIT SDK
ANTのサイトでFITデータを利用したアプリケーション開発の為のSDKが配布されています。 最新版は16.00です。 *5
SDKの主な内容物は以下の通りです。
SDKのAPIドキュメントについては、XMLドキュメントコメント(C#)やJavadoc(Java)が存在する程度なので、APIの詳細や使用方法についてはソースコードやサンプルコードを読むことになるかと思います。
サンプルコード
SDKに同梱されてるサンプルコードはFITファイルをデコードし、データをコンソールやCSVファイルに出力するものです。
個人的にFITファイルをデコードし、FITファイルとして出力(エンコード)するサンプルが欲しかったので・・・自分で作りました(C#版とJava版)。
https://github.com/harry0000/FitDataDuplicator
デコードした結果をファイルに出力してバイナリレベルで同一のファイルを新規作成するだけのサンプルですが、FITファイルのデータを書き換えて新たなFITファイルを作成するアプリ開発などの参考になるかと思います。
ハマリどころ
最後に、元のFITファイルとバイナリレベルで全く同じファイルを作成(エンコード)しようとした時のハマリどころを紹介します。
C# / Java版共通
- デコードで、元データに存在しない
Field
がMesg
クラスに追加されていることがある- 詳細
デコード処理において、情報が圧縮して格納されているようなField
があった場合、Mesg.ExpandComponents()
により情報が展開され、別のField
として追加されます。
例えば、Recode
メッセージにCompressedSpeedDistance
フィールドがあった場合、Speed
とDistance
の2つのフィールドに展開し、それぞれField
へ追加します。Speed
やDistance
のフィールドが既に存在する場合は、それらのフィールドの値を上書きします。 *6
展開して追加されたフィールドは元のFITデータには存在しないため、このままエンコードすると余計なデータが追加されたFITファイルができあがってしまいます。 - 対処方法
- C#・Java共に
Field
は順序つきリストなので、MesgDef
で定義されたフィールド数より多い要素(追加された要素)を削除してエンコードすれば元データと同じバイナリを出力できます。 - より丁寧に処理する場合、
Field Definition
のField Definition Number
に存在しないフィールドを削除するのがよいと思います。
- C#・Java共に
- 詳細
- SDKの
Encode
(FileEncoder
)クラスを使用してエンコードすると、HeaderのCRCが更新されてしまう - SDKに同梱されている
Activity.fit
やMonitoringFile.fit
を正常にデコードできない