- my @bytes = unpack("C*", $data);
-
- # print join(' ', map { sprintf(" %02x", $_) } @bytes), "\n";
- push @{ $self->{bytes} }, @bytes;
- @bytes = @{ $self->{bytes} };
-
- my @bad_bytes;
-
- while (@bytes > $PACKET_SIZE) {
- if ($bytes[0] != 0x55) {
- push @bad_bytes, shift @bytes;
- next;
- }
- my $cmd = $bytes[1];
-
- if ($bytes[$PACKET_SIZE] != 0x05
- || SCX::CRC::digest(@bytes[0..$PACKET_SIZE-2])
- != $bytes[$PACKET_SIZE-1]) {
- push @bad_bytes, shift @bytes;
- next;
- }
-
- if (@bad_bytes) { # Report previous bad bytes first
- $self->log_bytes(\@bad_bytes, "Cannot parse packet");
- @bad_bytes = ();
- }
-
- my @packet = splice @bytes, 0, $PACKET_SIZE+1;
- my $rv = $self->handle_packet(@packet);
- $self->log_bytes(\@packet, $rv);
- }
- if (@bad_bytes) {
- while (@bytes && $bytes[0] != 0x55) {
- push @bad_bytes, shift @bytes;
- }
- $self->log_bytes(\@bad_bytes, "cannot parse packet");
- }
-
- @{ $self->{bytes} } = @bytes;
-}
-
-sub log_bytes {
- my ($self, $bytes, $msg) = @_;
-
- return if !@$bytes;
-
- $msg = defined $msg ? ' # ' . $msg : '';
-
- my $now = gettimeofday;
-
- if ($now - $self->{log_start} >= $LOG_ROTATE) {
- close $self->{logfh};
- $self->{log_gen} = $self->{log_gen} ? 0 : 1;
- open my $fh, '>', $self->{logfile} . '.' . $self->{log_gen}
- or die "Can't open $self->{logfile}.$self->{log_gen}: $!";
- $self->{logfh} = $fh;
- $self->{log_start} = $now;
- }
-
- $self->{logfh}->print(sprintf('% 10.3f', $now - $self->{starttime}),
- (map { sprintf(" %02x", $_) } @$bytes),
- $msg, "\n");
- $self->{logfh}->flush;
-}
-
-our %COMMANDS = (
- 0xAA => \&bus_free_time_packet,
- 0xCC => \&car_programming_packet,
- 0xD0 => \&reset_packet,
- 0xD3 => \&standings_packet,
- 0xD4 => \&lap_time_packet,
- 0xD5 => \&race_setup_packet,
- 0xD6 => \&fuel_level_packet,
- 0xD7 => \&brake_set_packet,
- 0xDB => \&qualification_packet,
- 0xDC => \&end_of_race_packet,
- 0xDD => \&race_start_packet,
- 0xDE => \&display_change_packet,
- 0xEE => \&finish_line_packet,
- 0xFF => \&controller_status_packet,
-);
-
-sub handle_packet {
- my ($self, @data) = @_;
-
- my $cmd = $data[1];
- my @args = @data[2..7];
-
- my $sub = $COMMANDS{$cmd};
- return "Unknown packet"
- if !defined $sub;
-
- return &$sub($self, @args);
-}
-
-sub bus_free_time_packet {
- my ($self, @bytes) = @_;
-
- my $msg = 'Strange bus free time packet'
- if $bytes[2] != 0xF0
- || $bytes[3] != 0xF0
- || $bytes[4] != 0xF0
- || $bytes[5] != 0xF0;
-
- return $msg; # No need to handle this, I think
-}
-
-sub car_programming_packet {
- my ($self, @bytes) = @_;
-
- my $msg = 'Strange car programming packet'
- if ($bytes[0] & 0xF8) != 0 || ($bytes[0] & 0x07) > 5
- || $bytes[1] != 0xFE
- || $bytes[2] != 0xFF
- || $bytes[3] != 0xFF
- || $bytes[4] != 0xFF
- || $bytes[5] != 0xFF;
-
- return $msg;
-}
-
-sub reset_packet {
- my ($self, @bytes) = @_;
-
- my $msg = 'Strange reset packet'
- if $bytes[0] != 0xFF
- || $bytes[3] != 0xAA
- || $bytes[4] != 0xAA
- || $bytes[5] != 0xAA;
-
- return $msg; # FIXME - to be implemented
-}
-
-sub standings_packet {
- my ($self, @bytes) = @_;
-
- my $msg = 'Strange standings packet'
- if ($bytes[0] != 0xFF && ($bytes[0] & 0x07) > 5)
- || ($bytes[1] != 0xFF && ($bytes[1] & 0x07) > 5)
- || ($bytes[2] != 0xFF && ($bytes[2] & 0x07) > 5)
- || ($bytes[3] != 0xFF && ($bytes[3] & 0x07) > 5)
- || ($bytes[4] != 0xFF && ($bytes[4] & 0x07) > 5)
- || ($bytes[5] != 0xFF && ($bytes[5] & 0x07) > 5);
-
- my @standings;
-
- push @standings, map { $_ != 0xFF ? $_ & (0x07) : () } @bytes;
-
- return $msg; # FIXME - to be implemented
-}
-
-sub lap_time_packet {
- my ($self, @bytes) = @_;
-
- my $msg = 'Strange lap time packet'
- if $bytes[0] > 5
- || $bytes[1] & 0x01
- || $bytes[2] & 0x01
- || ($bytes[3] & 0xF0) != 0
- || $bytes[4] & 0x01
- || $bytes[5] & 0x01;
-
- my $nonzero = grep { $_ != 0 } @bytes;
-
- my $car = $bytes[0];
- my $round = 256*$bytes[1] + $bytes[2]
- + ($bytes[3] & 2 ? 256 : 0)
- + ($bytes[3] & 1 ? 1 : 0);
- my $time = 256*$bytes[4] + $bytes[5]
- + ($bytes[3] & 8 ? 256 : 0)
- + ($bytes[3] & 4 ? 1 : 0);
- if ($time == 65535) {
- $self->track->car($car)->enter_pit_lane;
- } else {
- $time *= 0.01024;
-
- if ($nonzero) {
- $self->track->car($car)->set_lap($round);
- $self->track->car($car)->set_laptime($time);
- } else {
- # FIXME - probably reset race time or whatever
- # all-zeros packet is sent after the race setup
- }
- }
-
- return $msg;
-}
-
-
-sub race_setup_packet {
- my ($self, @bytes) = @_;
-
- my $msg = 'Strange race setup packet'
- if ($bytes[0] != 0x00 && $bytes[0] != 0xFF)
- || $bytes[1] & 0xF0
- || $bytes[2] & 0xF0
- || $bytes[3] & 0xF0
- || $bytes[4] != 0xFF
- || $bytes[5] != 0xFF;