Skip to content

Commit

Permalink
Added json output to fitdump (issue #7)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrihtar committed Jan 18, 2017
1 parent 62fa34b commit c4adad6
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 35 deletions.
93 changes: 91 additions & 2 deletions Garmin/FIT.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package Garmin::FIT;
use FileHandle;
use POSIX qw(BUFSIZ);
use Time::Local;
use Scalar::Util qw(looks_like_number);

BEGIN {
$uint64_invalid = undef;
Expand Down Expand Up @@ -42,7 +43,7 @@ require Exporter;
FIT_HEADER_LENGTH
);

$version = 0.25;
$version = 0.26;
$version_major_scale = 100;

sub version_major {
Expand Down Expand Up @@ -3958,7 +3959,7 @@ sub named_type_value {
7 => +{'name' => 'cum_operating_time', 'unit' => 's'},
8 => +{'name' => 'unknown8'}, # unknown UINT32
9 => +{'name' => 'unknown9'}, # unknown UINT8
10 => +{'name' => 'battery_voltage', 'scale' => 256, 'unit' => 'v'},
10 => +{'name' => 'battery_voltage', 'scale' => 256, 'unit' => 'V'},
11 => +{'name' => 'battery_status', 'type_name' => 'battery_status'},
15 => +{'name' => 'unknown15'}, # unknown UINT32
16 => +{'name' => 'unknown16'}, # unknown UINT32
Expand Down Expand Up @@ -6062,6 +6063,94 @@ sub print_all_fields {
1;
}

sub print_all_json {
my ($self, $desc, $v, %opt) = @_;
my ($indent, $FH, $skip_invalid) = @opt{qw(indent FH skip_invalid)};

my $out = 0;

$FH=\*STDOUT if !defined $FH;
if ($desc->{array_length} == $#$v) {
$FH->print($indent, '"compressed_timestamp": "', $self->named_type_value('date_time', $v->[$#$v]), '"');
$out = $out + 1;
}

my $i_name;

foreach $i_name (sort {$desc->{$a} <=> $desc->{$b}} grep {/^i_/} keys %$desc) {
my $name = $i_name;

$name =~ s/^i_//;

my $attr = $desc->{'a_' . $name};
my $tname = $desc->{'t_' . $name};
my $pname = $name;

if (ref $attr->{switch} eq 'HASH') {
my $t_attr = $self->switched($desc, $v, $attr->{switch});

if (ref $t_attr eq 'HASH') {
$attr = $t_attr;
$tname = $attr->{type_name};
$pname = $attr->{name};
}
}

my $i = $desc->{$i_name};
my $c = $desc->{'c_' . $name};
my $type = $desc->{'T_' . $name};
my $invalid = $desc->{'I_' . $name};
my $j;

for ($j = 0 ; $j < $c ; ++$j) {
isnan($v->[$i + $j]) && next;
$v->[$i + $j] != $invalid && last;
}

if ($j < $c || !$skip_invalid) {
$self->last_timestamp($v->[$i]) if $type == FIT_UINT32 && $tname eq 'date_time' && $pname eq 'timestamp';
$FH->print(",\n") if $out;
$FH->print($indent, '"', $pname, '": ');

if ($type == FIT_STRING) {
$FH->print("\"", $self->string_value($v, $i, $c), "\"");
}
else {
$FH->print('[') if $c > 1;

my $pval = $self->value_cooked($tname, $attr, $invalid, $v->[$i]);

if (looks_like_number($pval)) {
$FH->print($pval);
}
else {
$FH->print("\"$pval\"");
}

if ($c > 1) {
my ($j, $k);

for ($j = $i + 1, $k = $i + $c ; $j < $k ; ++$j) {
$pval = $self->value_cooked($tname, $attr, $invalid, $v->[$j]);
$FH->print(', ');
if (looks_like_number($pval)) {
$FH->print($pval);
}
else {
$FH->print("\"$pval\"");
}
}

$FH->print(']');
}
}
$out = $out + 1;
}
}

1;
}

sub semicircles_to_degree {
my ($self, $on) = @_;

Expand Down
121 changes: 88 additions & 33 deletions fitdump.pl
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@
$numeric_date_time = 0 if !defined $numeric_date_time;
$semicircles_to_deg = 1 if !defined $semicircles_to_deg;
$mps_to_kph = 1 if !defined $mps_to_kph;
$without_unit = 0 if !defined $without_unit;
$show_version = 0 if !defined $show_version;
$maybe_chained = 0 if !defined $maybe_chained;
$print_json = 0 if !defined $print_json;
if ($print_json) {
$without_unit = 1 if !defined $without_unit;
} else {
$without_unit = 0 if !defined $without_unit;
}

my $version = "0.06x";
my $version = "0.07";
my $outr = 0;

if ($show_version) {
print $version, "\n";
printf STDERR "fitdump $version Copyright (c) 2017 Kiyokazu Suto, Matjaz Rihtar (Jan 18, 2017)\n";
printf STDERR "Garmin::FIT Copyright (c) 2010-2016 Kiyokazu Suto\n";
printf STDERR "FIT protocol ver: %s, profile ver: %s\n",
Garmin::FIT->protocol_version_string, Garmin::FIT->profile_version_string;
exit;
}

Expand All @@ -26,13 +35,26 @@ sub dump_it {
ref $o_cb eq 'ARRAY' and ref $o_cb->[0] eq 'CODE' and $o_cb->[0]->($self, $desc, $v, @$o_cb[1 .. $#$o_cb]);
}

if ($desc->{message_name} ne '') {
print "$desc->{message_name}";
} else {
print "unknown";
if ($print_json) {
print ",\n" if $outr;
if ($desc->{message_name} ne '') {
print " {\"$desc->{message_name}\": {\n";
} else {
print " {\"unknown$desc->{message_number}\": {\n";
}
$self->print_all_json($desc, $v, indent => ' ', skip_invalid => 1);
print "\n }}";
$outr = $outr + 1;
}
else {
if ($desc->{message_name} ne '') {
print "$desc->{message_name}";
} else {
print "unknown";
}
print " (", $desc->{message_number}, ", type: ", $desc->{local_message_type}, ", length: ", $desc->{message_length}, " bytes):\n";
$self->print_all_fields($desc, $v, indent => ' ');
}
print " (", $desc->{message_number}, ", type: ", $desc->{local_message_type}, ", length: ", $desc->{message_length}, " bytes):\n";
$self->print_all_fields($desc, $v, indent => ' ');
}

sub fetch_from {
Expand Down Expand Up @@ -62,6 +84,9 @@ sub fetch_from {
}

my $chained;
my $outf = 0;

print "{\n" if $print_json;

for (;;) {
my ($fsize, $proto_ver, $prof_ver, $h_extra, $h_crc_expected, $h_crc_calculated) = $obj->fetch_header;
Expand All @@ -76,52 +101,81 @@ sub fetch_from {
my ($proto_major, $proto_minor) = $obj->protocol_version_major($proto_ver);
my ($prof_major, $prof_minor) = $obj->profile_version_major($prof_ver);

print "\n" if $chained;
printf "File size: %lu bytes, protocol ver: %u.%02u, profile ver: %u.%02u\n", $fsize, $proto_major, $proto_minor, $prof_major, $prof_minor;
if ($print_json) {
if ($chained) {
print ", {\n";
} else {
print "\"file\": [{\n";
}
printf " \"crc\": \"0x%04X\",\n", $obj->crc;
print " \"header\": {\n";
if (defined $h_crc_calculated) {
printf " \"crc\": \"0x%04X\",\n", $h_crc_calculated;
}
print " \"file_size\": $fsize,\n";
printf " \"protocol_version\": \"%u.%02u\",\n", $proto_major, $proto_minor;
printf " \"profile_version\": \"%u.%02u\"\n", $prof_major, $prof_minor;
print " },\n";
print " \"records\": [\n";
}
else {
print "\n" if $chained;
printf "File size: %lu bytes, protocol ver: %u.%02u, profile ver: %u.%02u\n", $fsize, $proto_major, $proto_minor, $prof_major, $prof_minor;

if ($h_extra ne '') {
print "Extra bytes in file header";
if ($h_extra ne '') {
print "Extra bytes in file header";

my ($i, $n);
my ($i, $n);

for ($i = 0, $n = length($h_extra) ; $i < $n ; ++$i) {
print "\n" if !($i % 16);
print ' ' if !($i % 4);
printf " %02x", ord(substr($h_extra, $i, 1));
}
for ($i = 0, $n = length($h_extra) ; $i < $n ; ++$i) {
print "\n" if !($i % 16);
print ' ' if !($i % 4);
printf " %02x", ord(substr($h_extra, $i, 1));
}

print "\n";
}
print "\n";
}

if (defined $h_crc_calculated) {
if ($h_crc_expected != $h_crc_calculated) {
printf "File header CRC: expected=0x%04X, calculated=0x%04X\n", $h_crc_expected, $h_crc_calculated;
} else {
printf "File header CRC: 0x%04X\n", $h_crc_calculated;
if (defined $h_crc_calculated) {
if ($h_crc_expected != $h_crc_calculated) {
printf "File header CRC: expected=0x%04X, calculated=0x%04X\n", $h_crc_expected, $h_crc_calculated;
} else {
printf "File header CRC: 0x%04X\n", $h_crc_calculated;
}
}
}

1 while $obj->fetch;

print STDERR $obj->error, "\n" if !$obj->end_of_chunk && !$obj->EOF;
if ($obj->crc_expected != $obj->crc) {
printf "CRC: expected=0x%04X, calculated=0x%04X\n", $obj->crc_expected, $obj->crc;
} else {
printf "CRC: 0x%04X\n", $obj->crc_expected;
if ($print_json) {
print "\n ]"; # records
print "\n}"; # file
$outf = $outf + 1;
}
else {
if ($obj->crc_expected != $obj->crc) {
printf "CRC: expected=0x%04X, calculated=0x%04X\n", $obj->crc_expected, $obj->crc;
} else {
printf "CRC: 0x%04X\n", $obj->crc_expected;
}
}

if ($maybe_chained) {
$obj->reset;
$chained = 1;
}
else {
print STDERR $obj->error, "\n" if !$obj->end_of_chunk && !$obj->EOF;
my $garbage_size = $obj->trailing_garbages;

print "Trailing $garbage_size bytes of garbage skipped\n" if $garbage_size > 0;
print STDERR "Trailing $garbage_size bytes of garbage skipped\n" if $garbage_size > 0;
last;
}
}

print "]" if $outf;
print "\n}\n" if $print_json;

$obj->close;
}

Expand All @@ -131,8 +185,9 @@ sub fetch_from {

if (@ARGV > 1) {
do {
print "***** $ARGV[0] *****\n";
print "***** $ARGV[0] *****\n" if !$print_json;
&fetch_from(shift @ARGV);
$outr = 0;
} while (@ARGV);
}
elsif (@ARGV) {
Expand Down

0 comments on commit c4adad6

Please sign in to comment.