#!/usr/bin/perl use strict; use Math::Trig; my $r = 6371000.785; my $maptype = "satellite"; my $weight = 3; my $zoom = 14; my $size = "600x600"; my $sensor = "false"; my $url = "https://maps.googleapis.com/maps/api/staticmap"; my $known_flarms = { "4B0CF5" => "Robin HB-EXP", "4B1307" => "Bravo HB-HFJ" }; my $step_time = 3; my $timeout = 45; my ($from, $until, $before, $now) = (undef, undef, undef, undef); my ($own_lat, $own_long); my $flarm = undef; my $seen; sub fstr { my ($value,$precision) = @_; $precision ||= 5; my $s = sprintf("%.${precision}f", $value); $s =~ s/\.?0*$//; return $s; } sub parse_GPGGA { my ($line) = @_; my ($msg,$time,$lat,$northsouth,$long,$eastwest,$quality,$satelites,$dhop,$alt) = split(/,/, $line); my ($g_lat, $g_long) = nmeaToGoogle($lat,$northsouth,$long,$eastwest); print "nmea: " . $lat . $northsouth . "," . $long . $eastwest . "\n"; print "google: " . $g_lat . "," . $g_long . "\n"; $now = $time; $own_lat = $g_lat; $own_long = $g_long; } sub parse_PFLAA { my ($line) = @_; my ($msg,$alarm,$rel_north,$rel_east,$rel_vert,$id_type,$id,$track,$turnrate,$groundspeed,$climb,$type) = split(/,/, $line); return unless (defined($now)); return if (defined($from) && $now < $from); return if (defined($until) && $now > $until); return if (defined($flarm) && $id ne $flarm); return unless (defined($own_lat)); return unless (defined($own_long)); return unless ($groundspeed > 10 || $rel_vert > 20); print $now . ": " . $line . " " . ($own_lat+distToLat($rel_north)) . "," . ($own_long+distToLong($rel_east)) . "\n"; store($now, $id, $own_lat + distToLat($rel_north), $own_long + distToLong($rel_east)); } sub store { my ($time, $id, $g_lat, $g_long) = @_; if (!exists($seen->{$id})) { $seen->{$id} = (); } if (!defined($before) || $now >= $before+$step_time) { $before = $now; push(@{$seen->{$id}}, [$time, $g_lat, $g_long]); } } sub distToLat { my ($dist) = @_; return 180*$dist/($r*pi); } sub distToLong { my ($dist) = @_; return 180*$dist/(cos($own_lat*pi/180)*$r*pi); } sub nmeaToGoogle { my ($lat,$northsouth,$long,$eastwest) = @_; my $lat_sign = ($northsouth =~ /N/) ? 1 : -1; $lat =~ /^(\d{2})(\d{2})\.(\d{5})$/; my $g_lat = ($1 + ($2 + $3*1e-5)/60) * $lat_sign; my $long_sign = ($eastwest =~ /E/) ? 1 : -1; $long =~ /^(\d{3})(\d{2})\.(\d{5})$/; my $g_long = ($1 + ($2 + $3*1e-5)/60) * $long_sign; return ($g_lat, $g_long); } while (my $line = <>) { chomp($line); ($line =~ /^\$GPGGA/) && parse_GPGGA($line); ($line =~ /^\$PFLAA/) && parse_PFLAA($line); } foreach my $flarm_id (keys(%{$seen})) { my $plane = exists($known_flarms->{$flarm_id}) ? $known_flarms->{$flarm_id} : "???"; print "==== Flarm-ID: $flarm_id ($plane) ====\n"; my $last_record; foreach my $record (@{$seen->{$flarm_id}}) { my ($time, $g_lat, $g_long) = @{$record}; if (!defined($last_record) || $time >= $last_record + $timeout) { print "\n"; print $url . "?maptype=" . $maptype . "&zoom=" . $zoom . "&size=" . $size . "&sensor=" . $sensor . "¢er=" . fstr($own_lat, 5) . "," . fstr($own_long, 5) . "&path=color:red|weight:3"; } $last_record = $time; print "|".fstr($g_lat,5) . "," . fstr($g_long, 5); } $last_record = undef; print "\n\n"; }