OSM Tools

FIT files for dummies...

Tips for Creating a GPX file from ANT+/Wahoo FIT files & Strava Segments

Fit-Tools
  Fit ConVerter 4 showing all blocks & data
converting FIT to GPX , TCX , CSV & KML

The following should give you some understanding of the basic 'FIT protocols and structure'.

We assume that you are familiar with hex readers.

Yes, there are documents available which give a deeper understanding of the FIT structures but they are not written for beginners and the information is often hidden deep in a small file.

Use our Free Fit ConVerter 4 to print out the definitions and data of your FIT file ;it also contains hex pointers to help you.

Header

We shall ignore the header for the time being; for our purpose it does not contain important information except the length of the data contained in the file.

0 x 0 length of header (&e) , meaning our main data starts at 0x0e .

0 x 4 size of data (4 bytes) , ie the block taken from &h0E .

Unlike Garmin files, there are (currently) no pointers to specific blocks in the header.

'Let's begin'

The structure is a stream of 'definition blocks' and 'data blocks', nothing more, nothing less.

A definition defines the structure of a data block ;

it defines the types of data (longitude, latitude, temperature and the exact order such data is to be found!

The most important data type is 'time', then the coordinates followed by altitude etc - however the order can perversely be different.

Data always follows a definition, not the other way around!

Blocks do not have fixed sizes so it's essential to learn how to retrieve the length of a block.

The definition block also contains the size of a data block - if it didn't, we would have real difficulty knowing where the data block starts and where it ends!

The definition tells you what type of data to expect and in what order , ie temperature, height, coordinates.

You cannot assume that a data block immediately follows a definition . For that reason definitions are numbered and each data block starts with a number pointing to an earlier definition.

A data block starts with the first byte referring to the definition number (often zero).

So it looks a bit like this:

Def1 Data1 Def 2 Data2 Def 3 Data 3        

You could also have a untidy mix of definitions and data:

Def1 Def2 Data1 Def3 Data3 Data 1 Data 2

Data can contain values for longitude, latitude, allude, temperature, cadence etc.

It can also contain details of a new LAP ie time, distance, calories etc ; these are shown as L in FITConverter'.

It can also tell you where you pressed the STOP and CONTINUE 'button' ; these are shown as R in FITConverter.

It can also give you a specific Course Instruction (Point) , ie Turn Left at the next gate; these are shown as C in FIT Converter.

Definition block

Message IDs

It has 6 bytes , always 6 bytes - we call this the 40 block, because its the most common type.

Definition block starts with a 6 byte information header which for our purposes tells you if data contains coordinates or not.

Some data blocks contain just information about a device or a sport , nothing else - we skip those definitions..

Picture shows how FITConVerter 4 lists in order of occurrence all the '40 blocks', ie Message IDs.

Notice, most start with a 4 though some start with a 6 - see below.

FIT ConVerter adds R to show it is a Record with a Message ID of 20 (&h14)

Example 40 00 01 00 00 4

ANT+ FIT header

Highlighted in RED are the '40' blocks.

Highlighted in Yellow are the Fields.

Highlighted in GREEN : Data.

Encircled in RED , number of fields.

 

  • The last of the 6 bytes tells you how many fields (sub headings) there are; in our case 4
  • The first byte mod 0x20 gives us the definition number, known as the File Type ID

In our case the File TYPE id=0 .

Example:

4D 00 01 etc is the start of File Type 13 (&d) etc.

  • The third byte of this block, ie 01, tells us how data is to be read, ie left to right or right to left (Little or Big Endian).

In fact, if you examine the picture above , immediately after the header ,one of those 40 blocks can be seen.

  • The 4th & 5th byte tells us what kind of data the block represents - this is referred to as the Message ID.

This has two bytes - so in theory you could have 256*256 Msg IDs . In practice ,Msg IDs are < 256 and even then only a few are used, ie documented. Garmin uses many which are not documented, so we have to guess what they represent . FITConverter 4 helps you with this as it can plot the unknown values giving you a hint as to what they represent.

In our case we are chiefly interested in a Msg ID which contains latitude and longitude values , distances,height and speed. These are all located in Msg ID 20 (0x14)

40 00 01 00 14

or

40 00 00 14 00 (3rd byte is set to 00 so we read the two bytes from left to right)

For more information see below.

Fields are always 3 bytes long!

Fields
Fields have 3 bytes

example : 01 02 84 , 02 04 86 , fd 04 86 , 00 01 00

middle byte

The middle byte tells you how many bytes are needed ,ie 2 , 4 , 4 , 1

last byte

The last byte tells you what type of variable you are dealing with, ie could it included negatives or it could be letters.

02 23 07 (07 means string )

first byte

The first number refers to what is named the Field Definition Number, ie Speed, Latitude, Longitude, Temperature etc.

However the meaning depends on 2 bytes in the 40 block - see below.

Fields are arranged numerically according to the first byte.

If the 40 block contains 14 (see below 40 00 01 00 14) ) then the numbers relate to Speed, Latitude, Longitude, Temperature .

Data

A Data block starts with a type id which links it to a definition:

Example:

A definition beginning 42 (00 01 00 00) has a data block which starts with 02 .

A definition beginning 45 (00 01 00 00) has a data block which starts with 05 .

The FIT file consists of a series of defining blocks for various File ID Types , ie 1 ,2 6,12 - some numbers are not known

The length of the definition block is the header v+ the number of fields x 3 .

The length of a data block is the first byte telling you which definition it refers to + number of fields x sizes of the variables used.

ANT / Garmin FIT files

FIT files look very complicated, it being difficult to see a structure of any kind.

However, it just contains a series of blocks strung together.

How do I know a block is a definition and not Data?

Answer : if the beginning of the block starts with a byte < 0x40 then its a data block else its a definition.

We can always determine the length of a definition because of the number of fields.

We can always determine the length of a data block by checking the first byte , as this points to a definition given earlier & the variables types:

  • definitions are given a number
  • data starts with a definition number
  • If a definition includes altitude,power then the data must include altitude and power values AND in that order.
  • Definitions always precede data (surprise surprise)
  • Data does not have to immediately follow a definition. For this reason data always starts with a byte giving you the definition number.

Where are the Coordinates, Latitude & Longitude?

If the definition block contains coordinates then they are generally/always 4 bytes (0x84)

Coordinates are represented in various ways.

Here are the main ones:

00 04 85 Position Lat - Latitude requires 4 bytes
01 04 85 Position Long - Longitude requires 4 bytes

The bytes are stored as semicircles and not Garmin units; they may be little or Big endian, meaning you may have to reverse the order.they are stored ( a bit is set in the 40 header box - see above) .

so 00 9d dc 23 may need to be read as 23 dc 9d 00 .

Data becomes 7F FF FF FF if no gps fix could be established.

Which block contains crucial GPX data?

Coordinates are defined in a 40 block which contain the number (ANT speak : global message) for a 'record' - This number is 20 or &h14 (Some fit files contain (Strava) route segments - they have a different number - see below).

The 40 block include 2 bytes to define the global messages highlighted below:

40 00 01 00 00 ...

If there are several 40 blocks defined which ones contain the Latitude/Longitude data for our gpx file?

 

40 00 01 14

 

0x14 stands for 'record' - one of many so called message-ID s.

Below the results using our FIT - GPX for Windows.

Fields (6)

00 '04' 85 PositionLat
01 '04' 85 PositionLong = 1
02 '02' 84 Altitude = 2
FD '04' 86 Timestamp
06 '02' 84 Speed = 6
05 '04' 86 Distance = 5

1) Latitude 2) Longitude 3) Height 4) Timestamp 5) speed 6) distance

gpx data

Most FIT files also include temperature readings, heart rate & cadence (steps per minute).

These can also be added to your gpx file.

Tip : Import your FIT file into Basecamp then export it as a gpx and check the code.

When you create your GPX file ignore any 7FFFFFFF data . This means the GPX hasn't kicked in; so, check if the Latitude is not 7FFFFFFF.

Check your gpx file in Basecamp/Mapsource for possible 'unknown' errors - Garmin's archaic parsers are known to be intolerant and unfriendly!

More on Global Messages in 40 blocks

The following explains the headings given in the FITtoCSV converter given our example in picture above.

FileID (message ID) :4th byte=0

&E ******************************** FILE_ID (0) 40 00 00 00 00
Fields (7)
03 04 8C
04 04 86
07 04 86
01 02 84
02 02 84
05 02 84
00 01 00
&29 Data 00 06 BF AE C5 | 66 6E F4 38 | FF FF FF FF | 01 00 | 2C 0A | FF FF | 04 |

FILE_CREATOR : 4th byte = &31 ( dec 49) so its message ID = &43

&3D ******************************** FILE_CREATOR (49) 41 00 00 31 00
Fields (3)
02 14 07
00 02 84
01 01 02
&4C Data 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | 76 07 | FF |

EVENT 4th byte=&h15 (dec 21)

&64 ******************************** EVENT (21) 42 00 00 15 00
Fields (7)
FD 04 86
03 04 86

RECORD : fourth/fifth byte = &14 (dec 20)

******************************** RECORD (20) 4C 00 00 14 00 or 4C 00 01 00 14
Fields (9)
FD 04 86 Timestamp
00 04 85 PositionLat
01 04 85 PositionLong = 1
05 04 86 Distance = 5
02 02 84 Altitude = 2
06 02 84 Speed = 6
03 01 02 HeartRate = 3
04 01 02 Cadence = 4
0D 01 01 Temperature = &D (dec13)

60 Blocks

These occur in some FIT files ;they allow you to add extra fields using an almost Garminesk algorithm - The start of the data field ,therefore, has to be calculated differently.Our FIT Converter caters for such blocks.

Strava Segments

:RECORD (150) 40 00 00 96 00 or 40 00 01 00 96

Fields (6)

01 04 85 Position Lat
02 04 85 Position Long
04 02 84 Altitude
03 04 86| Distance
FE 02 84 message
05 08 86| Timestamp

Strava segments show &96 in the fourth byte.

These segments are mostly short linear routes.

Course Points

:RECORD (32) 40 00 00 20 00 or 40 00 01 00 20

01 04 86 Timestamp
02 04 85 Position Lat
03 04 85 Position Long
04 04 86 Distance
06 10 07 Instruction
FE 02 84 message
05 01 00| type

They behave more like waypoints and are fundamentally used for a turn by turn direction.

The data blocks contain the coordinates for the point, a distance,time , a description and an instruction number.

These points represent parts of a track where a new instruction is given. From a gpx point of view such points are not very useful. TCX files , however, can include course points.

Often used on  Garmin Edge Devices.

These can be best described as instructions, ie turn left, turn sharp right , keep going, drink water etc.

The instructions are numbered 0 to 255, each number representing particular instruction.

Here are some:

0 = "Generic"
1= "Summit"
2 = "Valley"
3 = "Water"
4= "Food"
5 = "Danger"
6 = "Turn Left"
7 = "Turn Right"
8 = "Straight Ahead"
9 = "First Aid"
15= "Sprint"
16 = "Left Fork"
17 = "Right Fork"
18 = "Middle Fork"
19 = "Continue Bear Left"
20) = "Sharp Left"
21) = "Continue Bear Right"
22) = "Sharp Right"
23) = "UTurn"
24 = "Segment Start"
25 = "Segment End"
course points in a fit file

Picture shows course with coursepoints.

The length of a description depends on the firmware of a device , often limited to 10 bytes.

However, FIT files, can cope with any description length . FIT ConVerter 3 allows you to set your length 0 - 16.

More on Data Blocks

The start of a data block can be higher than the number given in the definition.

If the definition number is 3 then the start of a data block can be 0xF3 or even 0xE7, 0xEB (multiples of 4 added).

The F in F3 seems to not only set the data block to 0x3 but appears to stipulate that any data record >128 following this refers to 0x3 .

We have not been able to test this fully but it seems to work.

Byte saving device

There is no need to always start a data block with a byte identifying the definition number. However, we need to ensure that we somehow inform the parser that we are skipping the definition identifier:

We do this by setting the 7th bit of a stream of numbers.

example:

43 00 00 14 00 01 03 01 02 ea a0 ef a0 f4 a1 etc etc

1 field 2 bytes type = 3 starting with ea a0 then ef a0 ; next f4 a1 etc

For each pair we have saved 1 byte ; sofar we have saved 3 bytes.

 

Swimming Data (&65)

Some data like 'distance' can be held in RECORDS but most swim related information like strokes & SWOLF is found in 'LENGTH'. The data type is 101 (&h65).

In Pool swimming the swolf score for a length is calculated by adding the number of strokes in a length and the time it took to swim that length . The lower the score the more efficient you are as a swimmer.

The pool length ( 25m , 50m etc ) can be obtained from the record distance value / 100 .

The next version of Fit Converter supports the charting of swimming data.

example:

4A 00 00 65 00

FD 04 86| Time stamp
02 04 86| Start Time
03 04 86| Total elapsed Time
04 04 86| Total Timer
05 02 84| Strokes / minute
06 02 84| Average Speed / 1000
0B 02 84| Average calories
07 01 00| Swim stroke (Type)
09 01 02| Swim cadence

Swim stroke TYPE

Freestyle = 0
Backstroke = 1
Breaststroke = 2
Butterfly = 3
Drill = 4
Mixed = 5
Im = 6
Invalid = 0xFF

Length Type

Idle = 0
Active = 1
Invalid = 0xFF

HRV Data (&4E)

HR R-R

HRV is a very good measure of the efficiency and performance of your cardiovascular system .

There is only 1 field 10 bytes long .

Included are R-R and HR values.

Future versions of FIT Converter should include the plotting of these values.

example:

49 00 00 4E 00

00 0A 84 | #time

Data:

7B 02 78 02 FF FF FF FF FF FF , ie 7B 02 | 78 02

User Profile (&3)

This gives you additional information about the user and its often included in a FIT containing HRV.

This includes information about the user, its gender, age, height , weight !

1C 04 86| # time you wake up
1D 04 86| # time you drop off to sleep
04 02 84| # weight
1F 02 84| # user_running_step_length
20 02 84| # user_walking_step_length
01 01 00| # gender
03 01 02| # height
05 01 00| # language
18 01 02| #BirthYear

There are many more fields which deal with the technicalities of the setup.

Data Streams

Compare the following Fields

01 04 86 - this means 4 bytes long (0x86 means uint32)

01 1C 86 - this means 0x1c ,ie 28 bytes long . The variable can't be 28 bytes long so we need to partition it into groups of 4 (ie 0x 86 uses 4 bytes for each variable

The stream is as follows:

85 32 0F 00 A1 86 01 00 58 15 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

When partitioned you get 7 bytes, first byte is 85 32 0F 00

85 32 0F 00 | A1 86 01 00 | 58 15 01 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00

Consider: 01 1C 83 - 0x83 implies a 2 byte variable. In our case , you would have 14 variables each 2 bytes long.

Streams are generally used to process different types of data , rather that different data for one type.

Compressed Timestamps

Compressed Timestamps are 1 byte long and always > 127 , ie with 8th bit set.

The timestamp is not included in the field. They are found in Records (MsgID=20)

example 1:

43 00 00 14 00 01 03 01 02 E1 84 E6 80 EB 80

This is a record definition (14) with 1 field:

03 01 02| #3:HeartRate

It is followed by groups of bytes E1 84 E6 80 EB 80 etc.

We normally expect a new definition after the field or a reference to a previous definition.

43 00 00 14 00 01 03 01 02 NxtByte

In our case the next byte (E1) cannot be the beginning of a new definition as we expect 00 not 84 as our second byte.

E1 could be a reference to an earlier definition but none was found.

However, the answer is simple.

If next number > 127 then we know its a compressed time stamp!

All we need to know next is how many bytes follow our compressed timestamp. Fortunately, it is given by the definition , which told us to expect 1 field, with length 1 - marked out in bold above.

Example 2

43 00 00 14 00 02 03 01 02 04 01 02

Here we add 2 fields , each one byte, so if we add a compressed time byte the second compressed time byte starts later:

43 00 00 14 00 02 03 01 02 04 01 02 E1 84 37 E6 80 38 EB 80 37

The difference between each interval is determined by the bytes set: ie in E1 6th and 7th bit ar set (8th bit is always set)

This allows us a max time difference of of 1+2+4+8 +16 =31 seconds

Only 4 bits are used to set the difference between each interval ; max difference = 32 seconds.

The 6th and 7th bit determines which definition it belongs to: 2 bits give you a definition range between 0 - 3.

This means compressed time cannot apply to definition 4,5 etc.

 

In our example the difference is 5.

E1 E6 EB EF so expect F0 F5 FA FE ... ?? ?? ??

It returns to starting from E0 :

( so each byte tells us its a compressed timestamp (+128)), belonging to a definition 0 - 3 )

If the interval was 5 ,count 5 from FE ( FE FF E0 E1 E2 ) so the next number would be E2 then E5 etc.

The number of fields is determined by the field(s) defined in the last Record.

FITConVerter 4 shows the data blocks separated by a comma:

EB|0F02B|75|0 , F0|37D02E|74|0 , F5|4BC13F|7A|4A .....

Each block contains 4 types of data , first type in red is always the compressed timestamp.

Compressed Speed Distance

Some FIT files with MsgID 20 and field type 8 merge the speed and distance values.

Only 3 bytes are required: the bits of the middle byte are divided up equally between them to create 2 separate values.

But surely, though speed can be confined to 1.5 bytes ,distance can't!.
How can you compress a very large distance into 1.5 bytes, ie when someone has travelled 'hundreds of miles' ?

You can, as distances are accumulative.

Notice how distance levels off when speed = 0

as shown in FITConVerter 4.15 .

compressed speed & distance