5 use Time::HiRes qw(gettimeofday tv_interval);
9 our $PACKET_SIZE = 9; # 9 bytes + 0x05
10 our $LOG_ROTATE = 600;
13 my ($class, $args) = @_;
15 my $callback = $args->{callback}
16 or die "callback arg not defined";
18 my $portname = $args->{portname}
19 or die "portname not specified";
21 system 'stty', '-F', $portname, '115200', 'raw';
23 die "stty died with code $? (no permissions?)";
26 open my $tty, '<:raw', $portname
27 or die "Can't open $portname: $!";
29 my $logfile = $args->{logfile};
32 open my $logfh, '>', "$logfile.$log_gen"
33 or die "Can't open $logfile.$log_gen: $!";
35 my $now = gettimeofday;
38 portname => $portname,
45 callback => $callback,
54 sub fh { return shift->{fh}; }
60 my $bytes_read = sysread $self->fh, $data, $PACKET_SIZE;
61 die "Read error on $self->{portname}: $!"
64 my @bytes = unpack("C*", $data);
66 push @{ $self->{bytes} }, @bytes;
67 @bytes = @{ $self->{bytes} };
71 while (@bytes > $PACKET_SIZE) {
72 if ($bytes[0] != 0x55) {
73 push @bad_bytes, shift @bytes;
78 if ($bytes[$PACKET_SIZE] != 0x05
79 || SCX::CRC::digest(@bytes[0..$PACKET_SIZE-2])
80 != $bytes[$PACKET_SIZE-1]) {
81 push @bad_bytes, shift @bytes;
85 if (@bad_bytes) { # Report previous bad bytes first
86 $self->log_bytes(\@bad_bytes, "Cannot parse packet");
90 my @packet = splice @bytes, 0, $PACKET_SIZE+1;
91 my $rv = &{ $self->{callback} }(@packet);
92 $self->log_bytes(@packet, $rv);
94 $self->log_bad_bytes(\@bad_bytes, "Cannot parse packet");
96 @{ $self->{bytes} } = @bytes;
100 my ($self, $bytes, $msg) = @_;
104 $msg = defined $msg ? ' # ' . $msg : '';
106 my $now = gettimeofday;
108 if ($now - $self->{log_start} >= $LOG_ROTATE) {
109 close $self->{logfh};
110 $self->{log_gen} = $self->{log_gen} ? 0 : 1;
111 open my $fh, '>', $logfile . '.' . $self->{log_gen}
112 or die "Can't open $logfile.$self->{log_gen}: $!";
113 $self->{logfh} = $fh;
114 $self->{log_start} = $now;
117 $self->{logfh}->print(sprintf('% 10.3f', $now - $self->{starttime}),
118 (map { sprintf(" %02x", $_) } @$bytes),
123 0xAA => \&bus_free_time_packet,
124 0xCC => \&car_programming_packet,
125 0xD0 => \&reset_packet,
126 0xD3 => \&standings_packet,
127 0xD4 => \&lap_time_packet,
128 0xD5 => \&race_setup_packet,
129 0xD6 => \&fuel_level_packet,
130 0xD7 => \&brake_set_packet,
131 0xDB => \&qualification_packet,
132 0xDC => \&end_of_race_packet,
133 0xDD => \&race_start_packet,
134 0xDE => \&display_change_packet,
135 0xEE => \&finish_line_packet,
136 0xFF => \&controller_status_packet,
140 my ($self, @data) = @_;
143 my @args = $data[2..7];
145 my $sub = $COMMANDS{$cmd};
146 return "Unknown packet"
149 return &$sub($self, @args);
152 sub bus_free_time_packet {
153 my ($self, @bytes) = @_;
155 my $msg = 'Strange bus free time packet'
159 || $bytes[5] != 0xF0;
161 return $msg; # No need to handle this, I think
164 sub car_programming_packet {
165 my ($self, @bytes) = @_;
167 my $msg = 'Strange car programming packet'
168 if $bytes[0] & 0xF8 != 0 || $bytes[0] & 0x07 > 5
173 || $bytes[5] != 0xFF;
179 my ($self, @bytes) = @_;
181 my $msg = 'Strange reset packet'
185 || $bytes[5] != 0xAA;
187 return $msg; # FIXME - to be implemented
190 sub standings_packet {
191 my ($self, @bytes) = @_;
193 my $msg = 'Strange standings packet'
194 if $bytes[0] & 0x07 > 5
195 || $bytes[1] & 0x07 > 5
196 || $bytes[2] & 0x07 > 5
197 || $bytes[3] & 0x07 > 5
198 || $bytes[4] & 0x07 > 5
199 || $bytes[5] & 0x07 > 5;
201 return $msg; # FIXME - to be implemented
204 sub lap_time_packet {
205 my ($self, @bytes) = @_;
207 my $msg = 'Strange lap time packet'
211 || $bytes[3] & 0xF8 != 0
215 return $msg; # FIXME - to be implemented
219 sub race_setup_packet {
220 my ($self, @bytes) = @_;
222 my $msg = 'Strange race setup packet'
223 if ($bytes[0] != 0x00 && $bytes[0] != 0xFF)
228 || $bytes[5] != 0xFF;
230 return $msg; # FIXME - to be implemented
234 sub fuel_level_packet {
235 my ($self, @bytes) = @_;
237 my $msg = 'Strange fuel_level packet'
238 if ($bytes[0] >> 4) > 8
239 || $bytes[0] & 0x0F > 8
240 || ($bytes[1] >> 4) > 8
241 || $bytes[1] & 0x0F > 8
242 || ($bytes[2] >> 4) > 8
243 || $bytes[2] & 0x0F > 8
244 || ($bytes[5] != 0xAA && $bytes[5] != 0xFF);
248 $data[1] >> 4, $data[1] & 0x0f,
249 $data[2] >> 4, $data[2] & 0x0f,
250 $data[3] >> 4, $data[3] & 0x0f,
253 next if defined $controllers[$car-1]
254 &&$controllers[$car-1] == $fuel[$car];
256 my $progressbar = $builder->get_object(
257 'progressbar_fuel'.$car);
258 $progressbar->set_fraction($fuel[$car]/8);
262 return $msg; # FIXME - to be implemented
266 sub brake_set_packet {
267 my ($self, @bytes) = @_;
269 return 'Unexpected brake_set packet (should be in the pit lane only)';
273 sub qualification_packet {
274 my ($self, @bytes) = @_;
276 my $msg = 'Strange qualification packet'
282 || $bytes[5] != 0xFF;
284 return $msg; # FIXME - to be implemented
288 sub end_of_race_packet {
289 my ($self, @bytes) = @_;
291 my $msg = 'Strange end_of_race packet'
297 || $bytes[5] != 0xFF;
299 return $msg; # FIXME - to be implemented
303 sub race_start_packet {
304 my ($self, @bytes) = @_;
306 my $msg = 'Strange race_start packet'
312 || $bytes[5] != 0xAA;
314 return $msg; # FIXME - to be implemented
318 sub display_change_packet {
319 my ($self, @bytes) = @_;
321 my $msg = 'Strange display_change packet'
327 || $bytes[5] != 0xFF;
329 return $msg; # FIXME - to be implemented
333 sub finish_line_packet {
334 my ($self, @bytes) = @_;
337 for my $byte (@bytes) {
345 my $msg = 'Strange finish_line packet'
348 return $msg; # FIXME - to be implemented
352 sub controller_status_packet {
353 my ($self, @bytes) = @_;
356 for my $byte (@bytes) {
358 if $byte & 0xC0 != 0xC0
362 my $msg = 'Strange controller_status packet'
366 for my $controller (1..6) {
367 my $byte = $data[$controller];
368 next if defined $controllers[$controller-1]
369 && $controllers[$controller-1] == $byte;
370 $controllers[$controller-1] = $byte;
372 my $progressbar = $builder->get_object(
373 'progressbar_controller'.$controller);
375 $progressbar->set_text('inactive');
376 $progressbar->set_fraction(0);
379 my $light = !($byte & 0x20);
380 my $backbutton = !($byte & 0x10);
381 my $speed = $byte & 0x0f;
383 my $text = ($backbutton ? '+' : '') . $speed;
384 $progressbar->set_text($text);
385 $progressbar->set_fraction($speed / 12);
389 return $msg; # FIXME - to be implemented