--- /dev/null
+#!/usr/bin/perl -w
+
+package SCX::LogPrinter;
+
+use strict;
+
+use base qw(SCX::Parser);
+
+our $UNIQ_TIMEOUT = 2.0;
+
+sub new {
+ my ($class, $args) = @_;
+
+ my $self = SCX::Parser->new();
+ bless $self, $class;
+
+ $self->{dump_bad_bytes} = 1 if $args->{dump_bad_bytes};
+ $self->{dump_strange} = 1 if $args->{dump_strage};
+ $self->{uniq_only} = 1 if $args->{uniq_only};
+ $self->{skip_types} = $args->{skip_types};
+
+ return $self;
+}
+
+sub cond_print {
+ my ($self, $key, @vals) = @_;
+
+ return if $self->{skip_types}->{$key};
+
+ if ($key !~ /finish_line/ || @vals) {
+ my $val = join('|', @vals);
+ return if $self->{uniq_only}
+ && defined $self->{uniq}->{$key}
+ && $self->{uniq}->{$key} eq $val;
+
+ $self->{uniq}->{$key} = $val;
+ } else {
+ my $time = $self->now;
+ return if $self->{uniq_only}
+ && defined $self->{uniq}->{$key}
+ && $time - $self->{uniq}->{$key} < $UNIQ_TIMEOUT;
+ $self->{uniq}->{$key} = $time;
+ }
+
+ $self->do_print($key, @vals);
+}
+
+sub stringify_data {
+ my (@data) = @_;
+
+ return join(' ', map { sprintf("%02X", $_) } @data);
+}
+
+sub do_print {
+ my ($self, @data) = @_;
+
+ print join(' ', $self->now, @data), "\n";
+}
+
+sub bad_bytes {
+ my ($self, @data) = @_;
+
+ return if !$self->{dump_bad_bytes};
+ $self->do_print('bad_bytes', stringify_data(@data));
+}
+
+sub strange_packet {
+ my ($self, $name, @data) = @_;
+
+ return if !$self->{dump_strage};
+ $self->do_print('strange', $name, stringify_data(@data));
+}
+
+sub unknown_packet {
+ my ($self, @data) = @_;
+
+ $self->do_print('unknown_packet', stringify_data(@data));
+}
+
+sub bus_free_time {
+ my ($self, @data) = @_;
+
+ $self->cond_print('bus_free_time', @data);
+}
+
+sub car_programming {
+ my ($self, @data) = @_;
+
+ $self->cond_print('car_programming', @data);
+}
+
+sub reset {
+ my ($self, @data) = @_;
+
+ $self->cond_print('reset', @data);
+}
+
+sub standings {
+ my ($self, @data) = @_;
+
+ $self->cond_print('standings', @data);
+}
+
+sub car_lap_time {
+ my ($self, $car, @data) = @_;
+
+ $self->cond_print('car_lap_time_' . $car, @data);
+}
+
+sub race_setup {
+ my ($self, @data) = @_;
+
+ $self->cond_print('race_setup', @data);
+}
+
+sub fuel_level {
+ my ($self, @data) = @_;
+
+ my @newdata;
+ if ($self->{prev_fuel_levels}) {
+ for my $i (0..5) {
+ if ($self->{prev_fuel_levels}->[$i] < $data[$i]) {
+ push @newdata, $data[$i] . '+';
+ } else {
+ push @newdata, $data[$i] . ' ';
+ }
+ }
+ }
+ $self->{prev_fuel_levels} = \@data;
+
+ $self->cond_print('fuel_level', @newdata);
+}
+
+sub brake_set {
+ my ($self, @data) = @_;
+
+ $self->cond_print('brake_set', @data);
+}
+
+sub qualification {
+ my ($self, @data) = @_;
+
+ $self->cond_print('qualification', @data);
+}
+
+sub end_of_race {
+ my ($self, @data) = @_;
+
+ $self->cond_print('end_of_race', @data);
+}
+
+sub race_start {
+ my ($self, @data) = @_;
+
+ $self->cond_print('race_start', @data);
+}
+
+sub display_change {
+ my ($self, @data) = @_;
+
+ $self->cond_print('display_change', @data);
+}
+
+sub finish_line {
+ my ($self, $regular, @cars) = @_;
+
+ for my $car (@cars) {
+ $self->cond_print('finish_line_' . $car, $regular);
+ }
+}
+
+sub controller_status {
+ my ($self, @ctrls) = @_;
+
+ my @data;
+ for my $c (@ctrls) {
+ if (!defined $c) {
+ push @data, '-';
+ next;
+ }
+
+ push @data, sprintf('% 2d', $c->{throttle})
+ . ($c->{button} ? '/' : '.');
+ # Ignore lights for now
+ }
+
+ $self->cond_print('controller', @data);
+}
+
+1;
--- /dev/null
+#!/usr/bin/perl -w
+
+use strict;
+
+use Getopt::Std;
+use SCX::LogPrinter;
+
+my %opt;
+if (!getopts('abi:su', \%opt) || !$ARGV[0]) {
+ die "Usage: $0 [-a] [-b] [-s] [-u] [-i type1,type2,...] logfile\n"
+ . "-a ... print all packet types, not only default types\n"
+ . "-b ... print also bad bytes (wrong CRC, non-packets, etc.)\n"
+ . "-i ... also ignore packets of given types\n"
+ . "-s ... print also strange packets\n"
+ . "-u ... print unique packets only (filter out duplicates)\n";
+}
+
+my $logfile = shift @ARGV;
+
+open my $logfh, '<', $logfile
+ or die "Can't open $logfile: $!";
+
+my %args;
+
+$args{dump_bad_bytes} = 1 if $opt{b};
+$args{dump_strange} = 1 if $opt{s};
+$args{uniq_only} = 1 if $opt{u};
+
+my %default_skip_types = map { $_ => 1 } qw(bus_free_time controller);
+my %skip_types = ($opt{a} ? () : %default_skip_types);
+
+if ($opt{i}) {
+ %skip_types = (%skip_types, map { $_ => 1 } split(/,/, $opt{i}));
+}
+
+$args{skip_types} = \%skip_types;
+
+my $printer = SCX::LogPrinter->new(\%args);
+
+while (my $line = <$logfh>) {
+ chomp $line;
+ $line =~ s/\A\s+//xms;
+ my ($l_time, @data) = split(/\s+/, $line);
+
+ $printer->add_data($l_time, map { hex $_ } @data);
+}
+