LoginSignup
2
0

More than 3 years have passed since last update.

FIT SDKのMacStaticLibで大きなメッセージを書き込んだときにデコードに失敗する不具合を回避する

Last updated at Posted at 2021-01-23

TL;DR

FitMesg.hFitMesg.mm を修正してビルドした libFitSdkCppiOS.a とヘッダーファイルを差し替える。
修正内容は記事の末尾。

不具合詳細

GARMIN FIT SDKはC言語/C++/Java/C#で提供されているが、同梱されているMacStaticLibを使用することでObjective-Cから使用することが出来、macOSやiOSのアプリから使用することができる。

しかし、このMacStaticLibにはバグがあり、メッセージのサイズが256Byte以上になるとヘッダーに書き込まれるデータ長とファイル末尾のCRCの値がおかしくなり、デコードできないFITファイルが生成されてしまう。

Objective-C Wrapper generate broken header when include long message - Discussion - FIT SDK - Garmin Forums

再現コード

FIT SDKに同梱されているサンプルプロジェクトにコードを追加したもの。
https://github.com/rseki-sonix/fit-ios-broken-header

device_infoメッセージのproduct_nameとdescriptorに長い文字列を追加するとデコード処理に失敗するようになる。

原因

Objective-CからC++ FIT SDKを使用するためのラッパークラス FitEncode はヘッダに書き込むデータ長を書き込んだメッセージ長から積算している。

このメッセージ長の型が FIT_UINT8 (UINT8のtypedef)になっており、256Byte以上の長さだとオーバーフローしてしまう。

そのため、256Byte以上のメッセージが書き込まれるたびにヘッダーのデータ長が255Byte分短くなる。
また、ファイル末尾のCRCもそのデータ長をもとに計算されているためCRCもおかしくなってしまう。

生成済みのFITファイルを修復する

生成されたFITファイルはデータ長とCRCだけがおかしいため、適切なデータ長とCRCを書き込めばデコードすることができる。

ファイルサイズからヘッダ長(14Byte)と末尾CRCの長さ(2Byte)を引いた値を計算する。
ヘッダーの内容についてはFit Protocolを参照。

今回生成されたファイルは453Byteのためデータ長は

453 - 14 - 2 = 437 = 0x01B5
となる。
filesize.png
datasize.png
CRCは自分で計算してもよいが、FitCSVToolに-dオプションを追加すると計算した数値が表示されるためそれを用いる。
今回は 0x03A9 だった。
crc.png
書き換えるとFitCSVToolでデコードできるようになる。

MacStaticLibを修正する

GARMIN Forumsでは"your own risk"でFitMesgを修正してもいいかもとのこと。
単純にメッセージサイズの型をUINT16に変更することで正しいデータ長とCRCを持つFITファイルを生成できる。
以下の二箇所の変更が必要。

cpp/FitMesg.h
#include "fit_mesg_definition.hpp"

@interface FitMesg : NSObject
// - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg;
// - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef;
- (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg;
- (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef;
@end

#endif /* FIT_MESG_H */
cpp/FitMesg.mm
@implementation FitMesg

// - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg
- (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg
{
    return [self Write:file forMesg:mesg withDef:FIT_NULL];
}

// - (FIT_UINT8) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef
- (FIT_UINT16) Write:(FILE *) file forMesg:(const fit::Mesg *)mesg withDef:(const fit::MesgDefinition *)mesgDef
{
    fit::MesgDefinition mesgDefOnNull;
    // FIT_UINT8 mesgSize = 1;
    FIT_UINT16 mesgSize = 1;
    FIT_UINT8 fieldSize = 0;
    FIT_UINT8 byte;

修正した静的ライブラリは以下の方法で行った。

FIT SDKのC++の静的ライブラリをビルドする - Qiita

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0