Welcome Guest,Register Now
Log In

ANT Forum

Welcome guest, please Login or Register

   

.FIT file format specification

Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

Hi,

I'm looking and I can't find the file specification for the .fit file format
All I can't find is information of transfer protocol and stuff like that, this is not what i'm interested in.
I just want to create a simple .fit file after my users have done an activity so they can upload it to various site.

Similar to .tcx file format from Garmin that is available here :
http://www8.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd

Thanks!      

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

RankRankRank

Total Posts: 91

Joined 2012-10-12

PM

The FIT documentation is included in the FIT SDK archive (http://www.thisisant.com/resources/fit/).

The FIT Protocol document describes the binary file format. The FIT File Types document describes the content of standard FIT file types such as 'activity'. To get started creating FIT files using the FIT SDK I suggest studying the included Encode example app in your preferred language (C/C++/C#/Java).

HTH
ShaneP      
Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

Thanks for the response,

I'll have a look at the FIT SDK archive.
I thought .fit was just an .xml file, seems like I was wrong.
I'll see if implementing is worth it...

Note to self:
(Activity File, p47 - D00001309 FIT File Types Description Rev 1.5.pdf)
     

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

ShaneP - 14 March 2014 10:42 AM
The FIT documentation is included in the FIT SDK archive (http://www.thisisant.com/resources/fit/).
The FIT Protocol document describes the binary file format. The FIT File Types document describes the content of standard FIT file types such as 'activity'. To get started creating FIT files using the FIT SDK I suggest studying the included Encode example app in your preferred language (C/C++/C#/Java).
HTH
ShaneP



Hey Shane,

I finally got the time to implement the .fit Activity file.
I look inside the "FitSDKRelease_12.20" kit and the included example is minimal. I'm following the D00001309.pdf but sometime it says "refer to SDK", what does that mean exactly? i'm looking at the source code to figure out what the arguments of the function mean. For example, for "activity" void SetEvent(FIT_EVENT event), I can't figure out what "FIT_EVENT" refers too. Is there some example of a activity file code that is a little more complete? Thanks in advance!

All I want is a simple activity file containing 1 activity (1 bike activity, with record every 1 second for Hr, Power, Cadence, Speed).

     

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

Avatar
RankRankRankRank

Total Posts: 296

Joined 0

PM

All message formats and data types (like FIT_EVENT) are specified in Profile.xls (part of the FIT SDK zip file).
Note that this Excel file has two tabs "Types" and "Messages".
That'll explain the syntax and mostly (by "speaking" names and comments) the semantics.

Besides, I can only recomment to take some activity .FIT files from Garmin devices and use these as examples. Both for parsing .FIT files and for creating .FIT files.
There's no 110% comprehensive spec. of the different .FIT file types (semantics, spec. of what's mandatory), so taking Garmin's files as a de facto standard should assure a good level of compatibility.

Cheers,
OMB      
Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

I checked the FitSDKRelease 14.20 and there is some more example now (for FIT_FILE_SETTINGS and FIT_FILE_MONITORING_B)

I can build the example Monitoring file with the function "EncodeMonitoringFile()", but when I try to upload it to garmin connect, it says "Some activities could not be created" or "An error occurred with your upload. Please try again." I checked with the decoding function and there is no error so the file looks good. The Profile.xls helps, but it doesn't say which fields are mandatory or not.

Best thing would be to have a complete example in "encode.cpp" that shows how to create a simple Activity File of 5min with 1 lap for example. I can't even do that -_-

Edit
Weird because the file seems to be parsed correctly in GoldenCheetah or fitfiletools.com, may be a garmin connect issue.. investigating
https://www.dropbox.com/s/3xc1tpr61gi7742/fitTools.png?dl=0

void FitActivityCreator::build_FIT_file() {

    fit
::Encode encode;
    
std::fstream file;


    
file.open("C:/test2.fit"std::ios::in std::ios::out std::ios::binary std::ios::trunc);
    if (!
file.is_open()) {
        qDebug
() << "Error opening file test.fit\n";
    
}
    encode
.Open(file);


    
// TimeCreated - seconds since UTC 00:00 Dec 31 1989
    
QDateTime now =  QDateTime::currentDateTime().toUTC();
    
QDateTime ref QDateTime(QDate(1989,12,31), QTime(0,0), Qt::UTC);
    
qint64 diffSecs ref.secsTo(now);


    
// --------------- FileIdMesg ------------------
    
fit::FileIdMesg fileIdMesg;
    
fileIdMesg.SetType(FIT_FILE_ACTIVITY);
    
fileIdMesg.SetManufacturer(FIT_MANUFACTURER_DYNASTREAM);
    
fileIdMesg.SetProduct(1);
    
fileIdMesg.SetSerialNumber(123456);
    
fileIdMesg.SetTimeCreated(diffSecs);
    
encode.Write(fileIdMesg);

    
fit::FileCreatorMesg fileCreatorMesg;
    
fileCreatorMesg.SetSoftwareVersion(29);
    
encode.Write(fileCreatorMesg);

    
fit::EventMesg eventMesg3;
    
eventMesg3.SetTimestamp(diffSecs);
    
eventMesg3.SetTimerTrigger(FIT_TIMER_TRIGGER_MANUAL);
    
encode.Write(eventMesg3);



    
// --------------- RecordMesg ------------------
    //add some filler data for 0-5min
    
for (int i=0i<300i++) {
        fit
::RecordMesg recordMesg;
        
recordMesg.SetTimestamp(diffSecs+i);
        
recordMesg.SetHeartRate(140);
        
recordMesg.SetCadence(80);
        
recordMesg.SetPower(290);
        
recordMesg.SetSpeed(30*1000.0/3600.0);
        
encode.Write(recordMesg);
    
}


    
// --------------- LapMesg ------------------
    
fit::LapMesg lapMesg2;
    
lapMesg2.SetIntensity(FIT_INTENSITY_WARMUP);
    
lapMesg2.SetStartTime(diffSecs);
    
lapMesg2.SetTimestamp(diffSecs+299);
    
lapMesg2.SetTotalElapsedTime(300);
    
lapMesg2.SetTotalTimerTime(300);
    
lapMesg2.SetEvent(FIT_EVENT_WORKOUT);
    
lapMesg2.SetEventType(FIT_EVENT_TYPE_START);
    
lapMesg2.SetLapTrigger(FIT_LAP_TRIGGER_TIME);
    
lapMesg2.SetSport(FIT_SPORT_CYCLING);
    
lapMesg2.SetEvent(FIT_EVENT_LAP);
    
lapMesg2.SetEventType(FIT_EVENT_TYPE_STOP);
    
encode.Write(lapMesg2);



    
// --------------- RecordMesg ------------------
    //add some filler data for 5-10min
    
for (int i=300i<600i++) {
        fit
::RecordMesg recordMesg;
        
recordMesg.SetTimestamp(diffSecs+i);
        
recordMesg.SetHeartRate(150);
        
recordMesg.SetCadence(90);
        
recordMesg.SetPower(300);
        
recordMesg.SetSpeed(40*1000.0/3600.0);
        
encode.Write(recordMesg);
    
}

    
// --------------- LapMesg ------------------
    
lapMesg2.SetIntensity(FIT_INTENSITY_REST);
    
lapMesg2.SetStartTime(diffSecs+300);
    
lapMesg2.SetTimestamp(diffSecs+599);
    
lapMesg2.SetTotalElapsedTime(300);
    
lapMesg2.SetTotalTimerTime(300);
    
lapMesg2.SetEvent(FIT_EVENT_WORKOUT);
    
lapMesg2.SetEventType(FIT_EVENT_TYPE_START);
    
lapMesg2.SetLapTrigger(FIT_LAP_TRIGGER_SESSION_END);
    
lapMesg2.SetSport(FIT_SPORT_CYCLING);
    
lapMesg2.SetEvent(FIT_EVENT_LAP);
    
lapMesg2.SetEventType(FIT_EVENT_TYPE_STOP);
    
encode.Write(lapMesg2);


    
fit::EventMesg eventMesg;
    
eventMesg.SetTimestamp(diffSecs+599);
    
eventMesg.SetEvent(FIT_EVENT_SESSION);
    
eventMesg.SetEventType(FIT_EVENT_TYPE_STOP_DISABLE_ALL);
    
encode.Write(eventMesg);



    
// --------------- SessionMesg ------------------
    
fit::SessionMesg sessionMesg;
    
sessionMesg.SetTimestamp(diffSecs+599);
    
sessionMesg.SetStartTime(diffSecs);
    
sessionMesg.SetTotalTimerTime(600); //Timer Time (excludes pauses)
    
sessionMesg.SetTotalElapsedTime(600); //Total number of msec since timer started (includes pauses) - Todo: calculate paused time
    
sessionMesg.SetSport(FIT_SPORT_CYCLING);
    
sessionMesg.SetEvent(FIT_EVENT_SESSION);
    
sessionMesg.SetEventType(FIT_EVENT_TYPE_STOP);
    
sessionMesg.SetTotalCalories(150); //kcal
    
sessionMesg.SetFirstLapIndex(0);
    
sessionMesg.SetNumLaps(2);
    
sessionMesg.SetTrigger(FIT_SESSION_TRIGGER_ACTIVITY_END);
    
sessionMesg.SetMessageIndex(FIT_MESSAGE_INDEX_RESERVED);
    
encode.Write(sessionMesg);


    
// --------------- ActivityMesg ------------------
    
fit::ActivityMesg activityMesg;
    
activityMesg.SetTimestamp(diffSecs+599);
    
activityMesg.SetTotalTimerTime(600);  //10min
    
activityMesg.SetNumSessions(1);  // Always 1 session (1 workout per file)
    
activityMesg.SetType(FIT_ACTIVITY_MANUAL);
    
activityMesg.SetEvent(FIT_EVENT_WORKOUT);
    
activityMesg.SetEventType(FIT_EVENT_TYPE_START);
    
activityMesg.SetLocalTimestamp(diffSecs);  //seconds since 00:00 Dec d31 1989 in local time zone
    
activityMesg.SetEvent(FIT_EVENT_ACTIVITY);
    
activityMesg.SetEventType(FIT_EVENT_TYPE_STOP);
    
encode.Write(activityMesg);



    if (!
encode.Close()) {
        qDebug
() << "Error closing encode.\n";
    
}
    file
.close();
    
qDebug() << "Encoded FIT file test.fit.\n";


Thanks for your help      

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

Avatar
RankRankRankRank

Total Posts: 296

Joined 0

PM

I feel that a major weakness of the .FIT file specs is: there'n no spec of which fields are mandatory and which not.

Some remarks on your code:
Message order shouldn't matter, but Garmin devices output activity and session messages AFTER records and laps.
Most non-accepted files that I came across had missing fields in the activity and session messages.
--> take a Garmin created .FIT file as the gold standard and start with fields in activity and session messages present in the Garmin file. You could omit the zoo of recently added exotic fields in session msgs. (these with higher numbers) for a first attempt, to save some coding time.

Cheers,
OMB      
Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

Yes it is a lot of trial and error to discover what is needed, i'd love a small working example bundled with the SDK.

Thanks for your comments on the code (updated it up here with latest)!
I am now able to create a simple Activity with 2 laps and import it with Golden Cheetah:
https://www.dropbox.com/s/k30dwa7gwgcxslq/workoutImportGC.png?dl=0
Golden Cheetah will give you warning and error message so it's easier to debug. Garmin connect gives you 0 feedback on why the file is refused. Even the supplied example "Activity.fit" bundled with the SDK doesn't upload to Garmin connect. I could just tell my users not to use Garmin Connect but I know some already use it and will be frustrated.

I would love to be able to dissect a working Garmin .FIT file so I can copy it, but i'm unable to open the file and see the data inside. I used the "Activity.csv" and try to replicate the "data" rows. Only other thing I can do is decode the file with the decode example "decode.cpp" that doesn't actually decode anything, it just says if the file as an error or not.

Thanks for your help, hopefully I can find the Garmin Connect problem before continuing implementing .FIT saving
Edit:
Confirmed, file works on Strava, Golden Cheetah, SportTracks.. won't waste time with Garmin Connect, thanks!
Thread on Garmin Connect Forums:
https://forums.garmin.com/showthread.php?235566-FIT-file-upload-spec&p=569499#post569499      

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

RankRankRank

Total Posts: 91

Joined 2012-10-12

PM

-Your Activity file seems to meet all the requirements in the File Types Document. I might add lap.message_index and store something else in session.message_index. As for Garmin Connect, I don't think it accepts arbitrary uploads.

ShaneP      
Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

ShaneP - 14 April 2015 11:10 AM
-Your Activity file seems to meet all the requirements in the File Types Document. I might add lap.message_index and store something else in session.message_index. As for Garmin Connect, I don't think it accepts arbitrary uploads.

ShaneP


Hey Shane, Yeah the file works fine on other platforms.
I'll try one last shot with Garmin Forums to see if a solution is possible.
Some people mentioned checking an accepted Garmin fit file created with a garmin head unit and try to replicate the data. Only thing is, I don't have a garmin head unit or an example file to compare to.
.tcx file used to work on Garmin connect even if the device that was recording was not a Garmin, I think it's possible if I find what they check for.
Thanks, happy to have switched to .FIT, creating a file on the fly is much easier with FIT!      

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

Seems like Garmin Connect needs a "DeviceInfoMesg" to let you upload file.
Reference
You can mark this thread as solved, thanks      

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

Rank

Total Posts: 9

Joined 0

PM

Can you please clarify how you decided for event type start and stop, i somehow don't understand this quoted part :S

Thanks.

blaisminator - 09 April 2015 04:50 PM


// --------------- ActivityMesg ------------------
   
...

    
activityMesg.SetEvent(FIT_EVENT_WORKOUT);
    
activityMesg.SetEventType(FIT_EVENT_TYPE_START);
  ..
    
activityMesg.SetEvent(FIT_EVENT_ACTIVITY);
    
activityMesg.SetEventType(FIT_EVENT_TYPE_STOP);
    
encode.Write(activityMesg);

... 


Thanks for your help
     
Avatar
RankRankRankRank

Total Posts: 123

Joined 2013-10-07

PM

Not sure theses EventType are needed.
I just copied a Garmin FIT file and they used that.

Let me know if you received my response in private message for your FIT file problem.
Thanks      

Signature

——————————————————
Free Indoor Cycling Software - https://maximumtrainer.com

Rank

Total Posts: 9

Joined 0

PM

Anybody knows what EVENT_TYPE constant is pause during my ride? thanks