NAME

Garmin::FIT - A Perl class to decode Garmin .FIT files


SYNOPSIS

  use Garmin::FIT;
  Garmin::FIT->version_string;
  $fit = new Garmin::FIT;
  $fit->unit_table(<unit> => <unit conversion table>);
  $fit->semicircles_to_degree(<boolean>);
  $fit->mps_to_kph(<boolean>);
  $fit->use_gmtime(<boolean>);
  $fit->file(<file name>)
  $fit->open;
  $fit->fetch_header;
  $fit->fetch;
  $fit->protocol_version_string;
  $fit->protocol_version_string(<version number>);
  $fit->profile_version_string;
  $fit->profile_version_string(<version number>);
  $fit->data_message_callback_by_name(<message name>, <callback function>[, <callback data>, ...]);
  $fit->data_message_callback_by_num(<message number>, <callback function>[, <callback data>, ...]);
  $fit->switched(<data message descriptor>, <array of values>, <data type table>);
  $fit->string_value(<array of values>, <offset in the array>, <counts>);
  $fit->value_cooked(<type name>, <field attributes table>, <invalid data>, <value>);
  $fit->error;
  $fit->crc_expected;
  $fit->crc;
  $fit->trailing_garbages;
  $fit->close;
  ...


DESCRIPTION

Garmin::FIT is a Perl class to provide interfaces to decode Garmin .FIT files.

The latest version is obtained via
GarminFIT-0.28.tar.gz (41KB, 2017-08-22 19:08:19).

There are three applications

fitdump,

fitsed,

and

fit2tcx

using this class.

Constants

Following constants are automatically exported.

FIT_ENUM
FIT_SINT8
FIT_UINT8
FIT_SINT16
FIT_UINT16
FIT_SINT32
FIT_UINT32
FIT_SINT64
FIT_UINT64
FIT_STRING
FIT_FLOAT16
FIT_FLOAT32
FIT_UINT8Z
FIT_UINT16Z
FIT_UINT32Z
FIT_UINT64Z
FIT_BYTE
numbers representing base types of field values in data messages.

FIT_BASE_TYPE_MAX
the maximal number representing base types of field values in data messages.

FIT_HEADER_LENGTH
length of a .FIT file header.

Class methods

Garmin::FIT->version_string
returns a string representing the version of this class.

new Garmin::FIT
creates a new object and returns it.

Garmin::FIT->message_name(<message spec>)
returns the message name for <message spec> or undef.

Garmin::FIT->message_number(<message spec>)
returns the message number for <message spec> or undef.

Garmin::FIT->field_name(<message spec>, <field spec>)
returns the field name for <field spec> in <message spec> or undef.

Garmin::FIT->field_number(<message spec>, <field spec>)
returns the field index for <field spec> in <message spec> or undef.

Garmin::FIT->cat_header(<protocol version>, <profile version>, <file length>[, <refrencne to a scalar>])
composes the binary form of a .FIT file header, concatenates the scalar and it, and returns the reference to the scalar. If the 4th argument is omitted, it returns the reference to the binary form. <file length> is assumed not to include the file header and trailing CRC.

Garmin::FIT->crc_of_string(<old CRC>, <reference to a scalar>, <offset in scalar>, <counts>)
calculate CRC-16 of the specified part of the scalar.

Garmin::FIT->my_endian
returns the endian (0 for little endian and 1 for big endian) of the machine on which this program is running.

Object methods

<object>->unit_table(<unit> => <unit conversion table>)
sets <unit conversion table> for <unit>.

<object>->semicircles_to_degree(<boolean>)
a wrapper method of unit_table() method.

<object>->mps_to_kph(<boolean>)
ditto.

<object>->use_gmtime(<boolean>)
sets the flag which of GMT or local timezone is used for date_time type value conversion.

<object>->file(<file name>)
sets the name <file name> of a .FIT file.

<object>->open
opens the .FIT file.

<object>->fetch_header
reads .FIT file header, and returns an array of the file size (excluding the trailing CRC-16), the protocol version, the profile version, extra octets in the header other than documented 4 values, the header CRC-16 recorded in the header, and the calculated header CRC-16.

<object>->fetch
reads a message in the .FIT file, and returns 1 on success, or undef on failure or EOF.

<object>->protocol_version_string
returns a string representing the .FIT protocol version on which this class based.

<object>->protocol_version_string(<version number>)
returns a string representing the .FIT protocol version <version number>.

<object>->profile_version_string
returns a string representing the .FIT protocol version on which this class based.

<object>->profile_version_string(<version number>)
returns a string representing the .FIT profile version <version number>.

<object>->data_message_callback_by_name(<message name>, <callback function>[, <callback data>, ...])
register a function <callback function> which is called when a data message with the name <message name> is fetched.

<object>->data_message_callback_by_num(<message number>, <callback function>[, <callback data>, ...])
register a function <callback function> which is called when a data message with the messag number <message number> is fetched.

<object>->switched(<data message descriptor>, <array of values>, <data type table>)
returns real data type attributes for a C's union like field.

<object>->string_value(<array of values>, <offset in the array>, <counts>)
converts an array of character codes to a Perl string.

<object>->value_cooked(<type name>, <field attributes table>, <invalid>, <value>)
converts <value> to a (hopefully) human readable form.

<object>->value_uncooked(<type name>, <field attributes table>, <invalid>, <value representation>)
converts a human readable representation of a datum to an original form.

<object>->error
returns an error message recorded by a method.

<object>->crc_expected
CRC-16 attached to the end of a .FIT file. Only available after all contents of the file has been read.

<object>->crc
CRC-16 calculated from the contents of a .FIT file.

<object>->trailing_garbages
number of octets after CRC-16, 0 usually.

<object>->close
closes opened file handles.

<object>->cat_definition_message(<data message descriptor>[, <reference to a scalar>])
composes the binary form of a definition message after <data message descriptor>, concatenates the scalar and it, and returns the reference to the scalar. If the 2nd argument is omitted, returns the reference to the binary form.

<object>->endian_convert(<endian converter>, <reference to a scalar>, <offset in the scalar>)
apply <endian converter> to the specified part of the scalar.

Data message descriptor

When fetch method meets a definition message, it creates a hash which includes various information about the corresponding data message. We call the hash a data message descriptor. It includes the following key value pairs.

<field index> => <field name>
in a global .FIT profile.

local_message_type => <local message type>
necessarily.

message_number => <message number>
necessarily.

message_name => <message name>
only if the message is documented.

callback => <reference to an array>
of a callback function and callback data, only if a callback is registered.

endian => <endian>
of multi-octets data in this message, where 0 for littel-endian and 1 for big-endian.

template => <template for unpack>
used to convert the binary data to an array of Perl representations.

i_<field name> => <offset in data array>
of the value(s) of the field named <field name>.

o_<field_name> => <offset in binary data>
of the value(s) of the field named <field name>.

c_<field_name> => <the number of values>
of the field named <field name>.

s_<field_name> => <size in octets>
of whole the field named <field name> in binary data.

a_<field name> => <reference to a hash>
of attributes of the field named <field name>.

t_<field name> => <type name>
only if the type of the value of the field named <field name> has a name.

T_<field name> => <a number>
representing base type of the value of the field named <field name>.

N_<field name> => <a number>
representing index of the filed named <field name> in the global .FIT profile.

I_<field name> => <a number>
representing the invalid value of the field named <field name>, that is, if the value of the field in a binary datum equals to this number, the field must be treated as though it does not exist in the datum.

endian_converter => <reference to an array>
used for endian conversion.

message_length => <length of binary data>
in octets.

array_length => <length of data array>
of Perl representations.

Callback function

When fetch method meets a data message, it calls a <callback function> registered with data_message_callback_by_name or data_message_callback_by_num, in the form
<callback function>->(<object>, <data message descriptor>, <array of field values>, <callback data>, ...).

The return value of the function becomes the return value of fetch. It is expected to be 1 on success, or undef on failure status.

Developer data

Fields in devloper data are given names of the form <developer data index>_<field definition number>_<converted field name>, and related informations are included <data message descriptors> in the same way as the fields defined in the global .FIT profile.

Each <converted field name> is made from the value of field_name field in the corresponding field description message, after the following conversion rules:

(1) Each sequence of space characters is converted to single _.
(2) Each of remaining non-word-constituend characters is converted to _ + 2 column hex representation of ord() of the character + _.

64bit data

If your perl lacks 64bit integer support, you need the module Math::BigInt.


AUTHOR

Kiyokazu SUTO <suto@ks-and-ks.ne.jp>


DISCLAIMER etc.

This program is distributed with ABSOLUTELY NO WARRANTY.

Anyone can use, modify, and re-distibute this program without any restriction if version <= 0.20.

The version 0.21 and newers are based on

Matjaz Rihtar's git repository

version. So, regardless of the above disclaimer, uses, modifications, and re-distributions of this version are restricted by the contents of the file LICENSE_LGPL_v2.1.txt in the git repository.


ACKNOWLEDGEMENT

The author is very grateful to Garmin for supplying us free software programers with .FIT SDK which includes detailed documetation about its proprietary file format.


CHANGES

0.27 --> 0.28

syscallback_devdata_id()
application_id field is not mandatory.

Thanks to the analysis by Matjaz Rihtar.

syscallback_devdata_field_desc()
field_name field is not mandatory.

Thanks to the analysis by Matjaz Rihtar.

0.26 --> 0.27

cat_definition_message()
pack_data_message()
use the new method drop_developer_data().

drop_developer_data()
new method to specify wether or not to drop developer data from output.

initialize()
initialize the new field drop_developer_data.

Top level
fix typos ($typename --> $typenam and $typdesc --> $typedesc).

0.23 --> 0.24

fetch_definition_message()
inserts <field definition number> to names of fields of developer data.

There is a developer who assigns the same field name to different fields. Such fields could not be distinguished with the old naming way.

0.22 --> 0.23

reset()
maybe_chained()
end_of_chunk()
new methods to support chained FIT files.

fetch()
use new methods maybe_chained() and end_of_chunk() to support chained FIT files.

0.21 --> 0.22

fixes of the issues:

Problems with big endian.

$defmsg_min_template
the conversion specifier for <message number> must be 'S', not 'v'.

endian_converter
endian_convert()
broken for arrays of multi-octets data.

0.20 --> 0.21

support for developer data and 64bit integers introduced in FIT 2.0.

64bit integers support is not tested at all.

This version is based on

Matjaz Rihtar's git repository

version. So, regardless of the above disclaimer, uses, modifications, and re-distributions of this version are restricted by the contents of the file LICENSE_LGPL_v2.1.txt in the git repository.

0.14 --> 0.15

fetch_header()
should do initial setup of CRC explicitly.

fetch()
code clean-up.

0.13 --> 0.14

protocol_version
protocol_version_header_crc_started
were wrong.

cat_definition_message()
should take care of endianness of message number.

0.12 --> 0.13

profile_version
%named_type
%msgtype_by_name
follow global profile version 16.10.

fetch_data_message()
file positions of undefined local message numbers are included in error messages.

0.11 --> 0.12

safe_isa()
New subroutine to avoid importing isa method from UNIVERSAL class. Thanks to Blaine Schmidt who kindly informed that such importation is deprecated.

xxx45_ftp
The field numbered 45 in a session message seems FTP.

0.10 --> 0.11

profile_version
%named_type
%msgtype_by_name
follow global profile version 4.10.

0.09 --> 0.10

profile_version
%named_type
%msgtype_by_name
follow global profile version 2.00.

0.08 --> 0.09

profile_version
was calculated from wrong string expression.

profile_version_from_string()
should use profile_version_scale instead of profile_version_major_shift.

fetch_header()
calculate and return header CRCs only for proper protocol version.

cat_header()
support header CRCs and extra data in a file header.

msgtype_by_name->{session}->{35}
scale attribute was missing.

msgtype_by_name->{session}->{36}
ditto.

0.07 --> 0.08

protocol_version
profile_version
fetch_header()
%named_type
%msgtype_by_name
%msgtype_by_num
follow protocol version 1.2 and global profile version 1.50.

0.06 --> 0.07

profile_version
major and minor parts should be computed by division with scale 100, not bit shift.

error()
.FIT file name is included in each error message.

fetch_header()
header length of .FIT files of newer profile version, may differ from 12. Thanks to report from Nils Knieling.

0.05 --> 0.06

initialize()
the member buffer of an object must be initialzied with a reference to a scalar, not the scalar itself. Thanks to report from Nils Knieling.

0.04 --> 0.05

$version
$version_major_scale
@version
$my_endian
$protocol_version_major_shift
$protocol_version_minor_mask
$protocol_version
@protocol_version
$profile_version_major_shift
$profile_version_minor_mask
$profile_version
@profile_version
@crc_table
$header_template
$header_length
$FIT_signature_string
$FIT_signature
$rechd_offset_compressed_timestamp_header
$rechd_mask_compressed_timestamp_header
$rechd_offset_cth_local_message_type
$rechd_length_cth_local_message_type
$rechd_mask_cth_local_message_type
$rechd_length_cth_timestamp
$rechd_mask_cth_timestamp
$rechd_offset_definition_message
$rechd_mask_definition_message
$rechd_length_local_message_type
$rechd_mask_local_message_type
$cthd_offset_local_message_type
$cthd_length_local_message_type
$cthd_mask_local_message_type
$cthd_length_time_offset
$cthd_mask_time_offset
$defmsg_min_template
$defmsg_min_length
$deffld_template
$deffld_length
$deffld_mask_endian_p
$deffld_mask_type
@invalid
@size
@template
%named_type
$use_gmtime
%msgtype_by_name
$mesg_name_vs_num
%msgtype_by_num
$msgnum_anon
$msgname_anon
@type_name
must be global scope, otherwise they can be collected as garbages after long time run. Thanks to reports and tests by Nils Knieling.

fetch_header()
backslashs in error messages should be quoted.

0.03 --> 0.04

use_gmtime()
works as a class method too.

msgtype_by_name->{file_id}->{2}
new member type_name with value garmin_product.

msgtype_by_name->{device_info}->{4}
ditto.

msgtype_by_name->{schedule}->{1}
ditto.

msgtype_by_name->{event}->{data16}->{2}->{switch}->{course_point}
fix wrong member name when --> name.

msgtype_by_name->{event}->{data}->{2}->{switch}->{course_point}
ditto.

data_message_callback_by_num()
save callback data in the form of new array reference instead of reference to @_.

data_message_callback_by_name()
ditto.

open()
make $FH binary mode. Thanks to reports and tests on Windows platform by Nils Knieling.

0.02 --> 0.03

@EXPORT
fix wrong name (FIT_FLOAT16 --> FIT_FLOAT64).

my_endian()
new method.

crc_initialize()
removed. CRC table initialized at top level instead.

error()
error message tag is simplified.

crc_of_string()
new method.

crc_calc()
use crc_of_string().

fill_buffer()
CRC was not calculated.

cat_header()
new method.

named_type->{mesg_num}
members undocumented_message_6 and undocumented_message_22 are removed.

date_string()
new method.

named_type_value()
change presentation of mask type type.

support reverse-conversion of 'date_time' type.

msgtype_by_name
members undocumented_message_6 and undocumented_message_22 are removed.

msgtype_by_num
undocumented message types are included only in this hash.

message_name()
new method.

message_number()
new method.

field_name()
new method.

field_number()
new method.

undocumented_field_name()
new method.

fetch_definition_message()
usage of offset() method was wrong.

use undocumented_field_name().

new key-value pairs of the form $index => $name in %desc.

new key-value pair array_length => $i_array in %desc.

cat_definition_message()
new method.

endian_convert()
require more arguments ($buffer and $i).

last_timestamp
new method.

fetch_data_message()
add support for compressed timestamp headers.

switched()
add support for multi-switching keys.

value_processed()
change format of scaled value without unit.

value_unprocessed()
new method.

value_cooked()
new method.

value_uncooked()
new method.

fetch()
add support for compressed timestamp headers.

type_name
array of names of types.

print_all_fields()
add support for compressed timestamp headers.

change output format.

use single method value_cooked() instead of methods named_type_value() and value_processed().

0.01 --> 0.02

EOF
new method.

fill_buffer()
calls clear_buffer method and EOF method.

FIT_HEADER_LENGTH()
new constant automatically exported.

numeric_date_time()
new method.

named_type_value()
sprintf format string was wrong.

calls numeric_date_time method.

message_type_by_name->{lap}
fix typo (totoal_distnace --> total_distance).

message_type_by_name->{session}
ditto.

data_message_callback_by_name()
fix wrong member name of $msgtype (num --> _number).

unit_table()
accept non hash value.

without_unit()
new method.

value_processed()
check whether or not $attr is a hash.

calls without_unit method.

initialize()
no user defined options.

member crc should not be initialized.

print_all_fields()
semicircles_to_degree()
mps_to_kph()
close
new methods.