This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Wanted: A programming library for writing .fit files (e.g. a Perl package)

Dear all

This is no urgent issue. My question might be on some other minds in this forum, as well, not on mine, only. As far as I know, the Garmin FIT file format is closed source, i. e., we don't know which keywords exist and how they are evaluated. The Garmin::FIT package allows us to read .fit files from within Perl to a certain extend and is therefore a reputable step towards light in the Garmin secrets. But is there also a package available to write .fit files? For example I maintain a slowly growing list of locations in text format, with entries like

46.454451; 11.116251; Agritur Melango; Via Dante 7; 38020 Castelfondo, Italy; +393409191240
47.683420; 16.592047; Pannonia-Hotel; Varkerulet 75; 9400 Sopron, Hungary; +3699312180

I'd like to transform this list in a FIT formatted saved locations file and upload this file to the Edge, because maintenance via the PCs keyboard in text format is much easier and less error prone than via the touch screen, as everybody will confirm who tried to cleanup the saved locations on the Edge using the build-in tools. If not in Perl, there might be another library for another programming language around which enables us to fill this gap. Hints welcome!
  • The FIT file format is not a closed source. There is public SDK for it. See www.thisisant.com.
  • Thanks for your reply, Alan. The Java library might help to get forward. When I get this thing up an running, I'll write a follow-up for this thread.
  • I'd like to transform this list in a FIT formatted saved locations file and upload this file to the Edge, because maintenance via the PCs keyboard in text format is much easier and less error prone than via the touch screen, as everybody will confirm who tried to cleanup the saved locations on the Edge using the build-in tools. If not in Perl, there might be another library for another programming language around which enables us to fill this gap. Hints welcome!

    Why can't you use a gpx file for the locations? (That's what I do.)
  • Thanks for your reply, dpawlyk. I didn't know that .gpx files can be used for this task. I thought, I'd have to upload a .fit file. Of course, .gpx files are the preferable solution. The following Perl script contains the input from my opening post in its DATA section and writes a one-line .gpx file for upload and a human readable second version with the same content (the forum software didn't accept the script for upload, perhaps it's the .pl suffix). The script should run on current Linux, MacOSX and Windows systems, when the need packages are installed. The script is boiled down from a larger program I've embedded in my own framework. It therefore might contain a few unused things.

    #!/usr/bin/perl

    use warnings;
    use strict;

    use English;
    use Geo::Gpx;
    use Geo::Coordinates::DecimalDegrees;
    use XML::LibXML;
    use XML::LibXML::PrettyPrint;

    my $DEGREE_SIGN = "\N{U+00B0}";

    my @data = ();
    while (<DATA>) {
    next if (/^\s*$/ || /^\#/);
    my ($latitude_decimal, $longitude_decimal, $display_name, $name, $address, $city, $phone) = split "\;";
    my $comment = " ";
    $latitude_decimal = strip_whitespace($latitude_decimal);
    $longitude_decimal = strip_whitespace($longitude_decimal);
    $display_name = strip_whitespace($display_name);
    $name = strip_whitespace($name);
    $address = strip_whitespace($address);
    $city = strip_whitespace($city);
    $phone = strip_whitespace($phone);
    push @data, [$latitude_decimal, $longitude_decimal, $display_name, $name, $address, $city, $phone, $comment];
    }

    my $gpx = Geo::Gpx->new();
    foreach my $entry (sort { $a->[2] cmp $b->[2] } @data) {
    my $latitude_decimal = $entry->[0];
    my $longitude_decimal = $entry->[1];
    my $display_name = $entry->[2];
    my $name = $entry->[3];
    my $address = $entry->[4];
    my $city = $entry->[5];
    my $phone = $entry->[6];
    my $comment = $entry->[7];
    if ($phone =~ /(#)+/) {
    $phone = strip_whitespace($PREMATCH);
    $comment = strip_whitespace($POSTMATCH);
    }
    my ($degree, $minutes) = decimal2dm($latitude_decimal);
    $degree = float_format($degree, 0);
    $minutes = float_format($minutes, 3);
    my $latitude_txt = "Lattitude: ".print_dm_coordinate_txt($degree, $minutes)." (north)";
    ($degree, $minutes) = decimal2dm($longitude_decimal);
    $degree = float_format($degree, 0);
    $minutes = float_format($minutes, 3);
    my $longitude_txt = "Longitude: ".print_dm_coordinate_txt($degree, $minutes)." (south)";
    $gpx->add_waypoint({
    lat => $latitude_decimal,
    lon => $longitude_decimal,
    name => strip_whitespace($display_name),
    });
    }

    ### write and format .gpx file: xml document one long line (adjust display name to left border)
    my $gpx_file = "Locations.gpx";
    my $gpx_document = "";
    foreach my $line (split "\n", $gpx->gpx("1.1")) {
    $gpx_document .= $line;
    }
    open GPX, ">$gpx_file" || die "Cannot open "$gpx_file" for writing: $!\n";
    print GPX "$gpx_document";
    close GPX;

    ### write and format .gpx file: pretty print the xml document
    $gpx_file = "Locations.pretty-print.gpx"; ### file name as the Edge expects
    my $document = XML::LibXML->load_xml(string => $gpx_document);
    my $pp = XML::LibXML::PrettyPrint->new(indent_string => " ");
    $pp->pretty_print($document);
    open GPX, ">$gpx_file" || die "Cannot open "$gpx_file" for writing: $!\n";
    print GPX $document->toString;
    close GPX;


    sub print_decimal_coordinate {
    my $decimal = shift;
    return $decimal.$DEGREE_SIGN;
    }

    sub print_dm_coordinate_txt {
    my $degree = shift;
    my $minutes = shift;
    return $degree.$DEGREE_SIGN." ".$minutes."\'";
    }

    sub float_format {
    my $number = shift;
    my $digits = shift;
    return sprintf "%.${digits}f", $number;
    }

    sub strip_whitespace {
    my $input = shift;
    $input =~ s/^\s+//g;
    $input =~ s/\s+$//g;
    return $input;
    }


    __DATA__
    46.454451; 11.116251; Castelf., Agr. Melango; Agritur Melango; Via Dante 7; 38020 Castelfondo; +393409191240 ### June 20/21th, 2017
    47.683420; 16.592047; Sopron, Pannonia-Hotel; Pannonia-Hotel; Varkerulet 75; 9400 Sopron (Ödenburg); +3699312180 ###
  • Use Basecamp....


    Basecamp cannot use the newer .fit files....