From 972687391b212153ee34a6ecf616fd1c1a53d01b Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Wed, 8 Dec 2010 23:26:56 +0100 Subject: [PATCH] Timekeeping and GUI development. --- SCX/Car.pm | 95 ++++++++++--- SCX/GUI.pm | 34 ++++- SCX/Reader.pm | 24 ++-- SCX/Track.pm | 97 +++++++++++-- gui.pl | 6 +- protocol.txt | 1 + slotcarman.glade | 348 ++++++++++++++++++++++++++++++++++------------- 7 files changed, 456 insertions(+), 149 deletions(-) diff --git a/SCX/Car.pm b/SCX/Car.pm index c6e2aaa..9f58b5b 100644 --- a/SCX/Car.pm +++ b/SCX/Car.pm @@ -18,6 +18,7 @@ sub new { avg_lap => 0, car_img => $args->{car_img}, id => $args->{id}, + order => $args->{id}, track => $args->{track}, }; @@ -42,17 +43,20 @@ sub same { } sub set_throttle { - my ($self, $val) = @_; + my ($self, $val, $time) = @_; return if $self->same('throttle', $val); if ($self->track->{start_in_progress} && $val) { $self->{early_start} = 1; - $self->gui->set_driver('Early start!'); + $self->gui->set_name($self->{order}, 'Early start!'); } - if ($self->{in_pit_lane} && defined $val && $val > 3) { - $self->leave_pit_lane; + if ($self->{in_pit_lane} && defined $val) { + $self->{last_finish_time} = $time; + if ($val > 3) { + $self->leave_pit_lane; + } } $self->gui->set_throttle($self->{order}, $val); @@ -84,28 +88,40 @@ sub set_model { sub set_lap { my ($self, $lap_nr) = @_; + if (!$lap_nr) { + $self->{avg_lap} = undef; + $self->{lap} = $lap_nr; + $self->gui->set_avg_lap($self->{order}, undef); + $self->gui->set_lap($self->{order}, $lap_nr); + return; + } + return if $self->same('lap', $lap_nr); - $self->gui->set_lap($self->{order}, defined $lap_nr ? $lap_nr : '--'); + $self->gui->set_lap($self->{order}, $lap_nr); if ($self->track->{race_running} && $self->{lap} > 1) { my $now = $self->{last_finish_time}; my $avg = ($now - $self->track->{race_running_since}) / ($self->{lap} - 1); $self->{avg_lap} = $avg; - $self->gui->set_avg_lap($self->{order}, $avg); - } else { - $self->gui->set_avg_lap($self->{order}, undef); + $self->gui->set_avg_lap($self->{order}, $self->{avg_lap}); } } sub set_laptime { my ($self, $lap_time) = @_; + if (!defined $lap_time) { + $self->gui->set_best_lap($self->{order}, undef); + $self->{best_lap} = undef; + } + return if $self->same('laptime', $lap_time); $self->gui->set_laptime($self->{order}, $lap_time); if (defined $lap_time) { if ($lap_time > 1.0 && !$self->{in_pit_lane} + && $self->track->{race_running} && (!defined $self->{best_lap} || $self->{best_lap} > $lap_time )) { @@ -117,9 +133,6 @@ sub set_laptime { $self->gui->set_best_lap($self->{order}, $lap_time, $global); } - } else { - $self->gui->set_best_lap($self->{order}, $lap_time); - $self->{best_lap} = undef; } } @@ -136,7 +149,7 @@ sub enter_pit_lane { return if $self->{in_pit_lane}; $self->{in_pit_lane} = 1; - $self->gui->enter_pit_lane; + $self->gui->enter_pit_lane($self->{order}); } sub leave_pit_lane { @@ -145,7 +158,7 @@ sub leave_pit_lane { return if !$self->{in_pit_lane}; $self->{in_pit_lane} = 0; - $self->gui->leave_pit_lane; + $self->gui->leave_pit_lane($self->{order}); } sub set_order { @@ -154,13 +167,16 @@ sub set_order { $self->{order} = $pos; $self->gui->set_name($self->{order}, $self->{driver}); - $self->gui->set_car_icon($self->{order}, $self->{car_icon}); + $self->gui->set_car_icon($self->{order}, $self->{car_img}); $self->gui->set_throttle($self->{order}, $self->{throttle}); $self->gui->set_lap($self->{order}, $self->{lap}); $self->gui->set_laptime($self->{order}, $self->{laptime}); $self->gui->set_best_lap($self->{order}, $self->{best_lap}); $self->gui->set_avg_lap($self->{order}, $self->{avg_lap}); $self->gui->set_fuel($self->{order}, $self->{fuel}); + $self->gui->set_car_id($self->{order}, $self->{id} + 1); + $self->gui->set_distance($self->{order}, + $self->{time_diff}, $self->{lap_diff}); if ($self->{in_pit_lane}) { $self->gui->enter_pit_lane; } @@ -173,28 +189,65 @@ sub reset { $self->set_laptime(undef); $self->{in_pit_lane} = 0; $self->{early_start} = undef; + $self->{last_finish_time} = undef; + $self->{first_finish_time} = undef; + $self->{time_diff} = undef; + $self->{lap_diff} = undef; } sub finish_line { my ($self, $time, $regular) = @_; - return undef - if defined $self->{last_finish_time} - && $time - $self->{last_finish_time} < 2; + if (defined $self->{last_finish_time} + && $time - $self->{last_finish_time} < 2) { + + $self->{last_finish_time} = $time; + if ($regular && $self->{in_pit_lane}) { + $self->leave_pit_lane; + } + return undef; + } if ($regular) { - if (defined $self->{last_finish_time}) { - $self->set_laptime($time - $self->{last_finish_time}); + if (defined $self->{first_finish_time}) { + $self->set_laptime($time - $self->{first_finish_time}); } } else { $self->enter_pit_lane; } - $self->{last_finish_time} = $time; - $self->set_lap(++$self->{lap}); + $self->{first_finish_time} = $self->{last_finish_time} = $time; + + if ($self->track->{race_running}) { + $self->set_lap($self->{lap} + 1); + } return 1; } +sub recalc_distance { + my ($self, $lap_first, $time_first) = @_; + + return if !defined $lap_first || !defined $self->{lap} + || !defined $time_first || !defined $self->{first_finish_time}; + + my $time; + + if ($self->{lap} == $lap_first) { + if ($self->{first_finish_time} == $time_first) { + $time = $self->{first_finish_time} + - $self->track->{race_running_since}; + } else { + $self->{time_diff} = $self->{first_finish_time} + - $time_first; + } + } else { + $self->{lap_diff} = $lap_first - $self->{lap}; + } + + $self->gui->set_distance($self->{order}, $time, + $self->{lap_diff}, $self->{time_diff}); +} + 1; diff --git a/SCX/GUI.pm b/SCX/GUI.pm index c073560..2f1aa5a 100755 --- a/SCX/GUI.pm +++ b/SCX/GUI.pm @@ -113,9 +113,9 @@ sub load_all_images { $self->{fuel_images} = [ load_image_set('img/fuel%d.svg', 8, int(0.6 * $h)) ]; - $self->{car_images} = load_image_dir('img/SCXCars', $h), - $self->{semaphore_images} => [ - load_image_set('img/semaphore%d.svg', 5, 2 * $h) + $self->{car_images} = load_image_dir('img/SCXCars', $h); + $self->{semaphore_images} = [ + load_image_set('img/semaphore%d.svg', 5, 1.5 * $h) ]; }; @@ -214,9 +214,27 @@ sub set_car_icon { sub set_lap { my ($self, $row, $text) = @_; + $text = '--' if !defined $text; + $self->set_label('label_lap', $row, $text, 'lap'); } +sub set_distance { + my ($self, $row, $time, $lap_diff, $time_diff) = @_; + + my $text = '--'; + + if (defined $time) { + $text = format_race_time($time); + } elsif (defined $time_diff) { + $text = '−' . format_lap_time($time_diff); + } elsif (defined $lap_diff) { + $text = '−' . $lap_diff . ' laps'; + } + + $self->set_label('label_distance', $row, $text); +} + sub set_laptime { my ($self, $row, $text) = @_; @@ -241,6 +259,12 @@ sub set_name { $self->set_label('label_name', $row, $text); } +sub set_car_id { + my ($self, $row, $text) = @_; + + $self->set_label('label_car_id', $row, $text); +} + sub enter_pit_lane { my ($self, $row) = @_; $self->set_label('label_laptime', $row, 'PIT'); @@ -299,8 +323,8 @@ sub format_race_time { $seconds -= 60 * $mins; return $hours - ? sprintf('%d:%02d:%05.2f', $hours, $mins, $seconds) - : sprintf('%d:%05.2f', $mins, $seconds); + ? sprintf('%d:%02d:%04.1f', $hours, $mins, $seconds) + : sprintf('%d:%04.1f', $mins, $seconds); } sub format_lap_time { diff --git a/SCX/Reader.pm b/SCX/Reader.pm index 7498e0a..ff5894d 100644 --- a/SCX/Reader.pm +++ b/SCX/Reader.pm @@ -276,9 +276,9 @@ sub race_setup_packet { $self->track->race_setup($bytes[0] == 0x00 ? 0 - : $bytes[1] & 0x0F * 256 - + $bytes[2] & 0x0F * 16 - + $bytes[3] & 0x0F); + : ($bytes[1] & 0x0F) * 256 + + ($bytes[2] & 0x0F) * 16 + + ($bytes[3] & 0x0F)); return $msg; } @@ -409,16 +409,11 @@ sub finish_line_packet { push @cars_finished, $i if $byte == 0xE7; } - my $processed; - for my $car (@cars_finished) { - $processed ||= $self->track->car($car)->finish_line( - $self->{last_read_time}, $regular - ); - } - - if ($processed) { - $self->track->recalc_order; - } + $self->track->finish_line( + $self->{last_read_time}, + $regular, + @cars_finished + ); return $msg; } @@ -455,7 +450,8 @@ sub controller_status_packet { my $backbutton = !($byte & 0x10); my $throttle = $byte & 0x0f; - $self->track->car($car)->set_throttle($throttle); + $self->track->car($car)->set_throttle($throttle, + $self->{last_read_time}); $self->track->car($car)->set_light($light); $self->track->car($car)->set_backbutton($backbutton); } diff --git a/SCX/Track.pm b/SCX/Track.pm index 09db4b7..2feed61 100644 --- a/SCX/Track.pm +++ b/SCX/Track.pm @@ -39,7 +39,8 @@ sub car { return shift->{cars}->[shift]; } sub race_start { my ($self) = @_; - return if $self->{race_running} || $self->{start_in_progress}; + return if $self->{race_running} || $self->{start_in_progress} + || $self->{qualification_running}; $self->{race_running} = 0; $self->{start_in_progress} = 1; $self->{semaphore} = 0; @@ -64,14 +65,13 @@ sub semaphore_step { $self->{race_running_since} = gettimeofday; $self->{start_in_progress} = undef; $self->{gui}->show_semaphore(0); - Glib::Timeout->add(3*$SEMAPHORE_STEP, \&semaphore_step, $self); + Glib::Timeout->add($SEMAPHORE_STEP, \&semaphore_step, $self); } else { $self->{gui}->show_semaphore(undef); $self->{semaphore} = undef; } return FALSE; } - sub race_end { my ($self) = @_; @@ -81,13 +81,14 @@ sub race_end { sub race_setup { my ($self, $rounds) = @_; + $self->{round} = 0; if ($rounds) { - $self->{gui}->rounds('0/' . $rounds); $self->{race_rounds} = $rounds; } else { - $self->{gui}->rounds('0'); $self->{race_rounds} = 0; } + + $self->print_rounds; $self->{best_lap} = undef; $self->{gui}->show_semaphore(undef); @@ -96,18 +97,44 @@ sub race_setup { $self->{gui}->time(undef); $self->{gui}->best_lap(undef); +} + +sub reset { + my ($self) = @_; + + $self->{race_running} = 0; + $self->{start_in_progress} = 0; + $self->{best_lap} = undef; + $self->{round} = 0; + + $self->print_rounds; + $self->{gui}->best_lap(undef); + $self->{gui}->time(undef); for my $car (0..5) { $self->car($car)->reset; - $self->car($car)->set_order($car); } } +sub print_rounds { + my ($self) = @_; + + $self->{gui}->rounds($self->{qualification_running} + ? 'Qualification' + : $self->{race_rounds} + ? $self->{round} . '/' . $self->{race_rounds} + : $self->{round} + ); +} + sub check_best_lap { my ($self, $time, $who) = @_; return if !defined $time || $time == 0; +# print "Check_best_lap $time $who vs ", +# defined $self->{best_lap} ? $self->{best_lap} : 'undef', +# "\n"; if (!defined $self->{best_lap} || $time < $self->{best_lap}) { $self->{best_lap} = $time; @@ -127,7 +154,7 @@ sub qualification_start { } $self->{qualification_running} = 1; - $self->{gui}->lap('Qualification'); + $self->{gui}->rounds('Qualification'); $self->{gui}->time(undef); $self->{gui}->best_lap(undef); } @@ -136,14 +163,64 @@ sub packet_received { my ($self, $time) = @_; if ($self->{race_running}) { - $self->gui->time($time - $self->{race_running_since}); + $self->{gui}->time($time - $self->{race_running_since}); } } sub recalc_order { - my ($self) = @_; + my ($self, $now) = @_; + + return if !$self->{race_running}; + + my @laps; + my @times; + for my $id (0..5) { + $laps[$id] = $self->car($id)->{lap} // -1; + $times[$id] = $self->car($id)->{first_finish_time} // $now; + } + + my @new_order = sort { + $laps[$b] <=> $laps[$a] + || + $times[$a] <=> $times[$b] + || + $a <=> $b; + } (0..5); + + my $lap_max = $laps[$new_order[0]]; + if (defined $lap_max && $lap_max != $self->{round} + && (!$self->{race_rounds} + || $lap_max <= $self->{race_rounds})) { + $self->{round} = $lap_max; + $self->print_rounds; + } - # FIXME: Implement me + for my $id (0..5) { + my $car = $new_order[$id]; + if ($self->car($car)->{order} != $id) { + $self->car($car)->set_order($id); + } + } + return ($new_order[0], $lap_max, $times[$new_order[0]]); +} + +sub finish_line { + my ($self, $time, $regular, @cars) = @_; + + my @processed; + for my $car (@cars) { + push @processed, $car + if $self->car($car)->finish_line($time, $regular); + } + + if (@processed) { + my ($first_car, $lap_max, $time_min) + = $self->recalc_order($time); + + for my $car (@processed) { + $self->car($car)->recalc_distance($lap_max, $time_min); + } + } } 1; diff --git a/gui.pl b/gui.pl index 6d3295e..acdb94f 100755 --- a/gui.pl +++ b/gui.pl @@ -10,7 +10,7 @@ use SCX::GUI; use SCX::Track; use SCX::Reader; -my $gui = SCX::GUI->new({ img_height => 80 }); +my $gui = SCX::GUI->new({ img_height => 100 }); my $track = SCX::Track->new({ gui => $gui }); my $reader; @@ -22,6 +22,10 @@ eval { }); }; +if ($@) { + print STDERR "Demo mode only: $@"; +} + $track->car(0)->set_model('F1 Ferrari'); $track->car(1)->set_model('F1 McLaren'); $track->car(2)->set_model('F1 Williams'); diff --git a/protocol.txt b/protocol.txt index 80c3778..f9bca11 100644 --- a/protocol.txt +++ b/protocol.txt @@ -228,6 +228,7 @@ Example: 55 EE 02 00 E7 01 00 00 CF # Car 2 drives through pit lane 55 EE 82 FF E7 FF FF Ff 90 # Car 2 enters pit lane too fast 55 EE F0 F0 E7 AA AA AA B1 # Car 2 enters pit lane +55 EE 83 78 E7 14 50 AA 04 # Car 2 enters pit lane too fast? diff --git a/slotcarman.glade b/slotcarman.glade index cccbcf6..2f002d7 100644 --- a/slotcarman.glade +++ b/slotcarman.glade @@ -267,7 +267,7 @@ 13 8 - + True <span weight="ultrabold" size="large">1</span> True @@ -281,7 +281,7 @@ - + True <span weight="ultrabold" size="large">2</span> True @@ -295,7 +295,7 @@ - + True 0.50999999046325684 <span weight="ultrabold" size="large">3</span> @@ -310,7 +310,7 @@ - + True <span weight="ultrabold" size="large">4</span> True @@ -324,7 +324,7 @@ - + True <span weight="ultrabold" size="large">5</span> True @@ -338,7 +338,7 @@ - + True <span weight="ultrabold" size="large">6</span> True @@ -600,91 +600,6 @@ GTK_EXPAND | GTK_SHRINK | GTK_FILL - - - True - label - True - right - 12 - - - 4 - 5 - 2 - 3 - - - - - True - label - right - 12 - - - 4 - 5 - 4 - 5 - - - - - True - label - right - 12 - - - 4 - 5 - 6 - 7 - - - - - True - label - right - 12 - - - 4 - 5 - 8 - 9 - - - - - True - label - right - 12 - - - 4 - 5 - 10 - 11 - - - - - True - label - right - 12 - - - 4 - 5 - 12 - 13 - - True @@ -1099,25 +1014,112 @@ - + + True + gtk-missing-image + + + 1 + 2 + 2 + 3 + - + + True + gtk-missing-image + + + 1 + 2 + 4 + 5 + - + + True + gtk-missing-image + + + 1 + 2 + 6 + 7 + - + + True + gtk-missing-image + + + 1 + 2 + 8 + 9 + - + + True + gtk-missing-image + + + 1 + 2 + 10 + 11 + - + + True + gtk-missing-image + + + 1 + 2 + 12 + 13 + - + + True + Id + + + + + True + + + True + label + + + 0 + + + + + True + label + 24 + + + 1 + + + + + 4 + 5 + 2 + 3 + @@ -1125,6 +1127,156 @@ + + + True + + + True + label + + + 0 + + + + + True + label + 24 + + + 1 + + + + + 4 + 5 + 4 + 5 + + + + + True + + + True + label + + + 0 + + + + + True + label + 24 + + + 1 + + + + + 4 + 5 + 6 + 7 + + + + + True + + + True + label + + + 0 + + + + + True + label + 24 + + + 1 + + + + + 4 + 5 + 8 + 9 + + + + + True + + + True + label + + + 0 + + + + + True + label + 24 + + + 1 + + + + + 4 + 5 + 10 + 11 + + + + + True + + + True + label + + + 0 + + + + + True + label + 24 + + + 1 + + + + + 4 + 5 + 12 + 13 + + 3 -- 2.43.0