1 | #------------------------------------------------------------------------------- |
---|
2 | # This file is part of the FLARM®-Radar Project. |
---|
3 | # |
---|
4 | # Copyright by the Authors |
---|
5 | # |
---|
6 | # Licensed under the Apache License, Version 2.0 (the "License"); |
---|
7 | # you may not use this file except in compliance with the License. |
---|
8 | # You may obtain a copy of the License at |
---|
9 | # |
---|
10 | # http://www.apache.org/licenses/LICENSE-2.0 |
---|
11 | # |
---|
12 | # Unless required by applicable law or agreed to in writing, software |
---|
13 | # distributed under the License is distributed on an "AS IS" BASIS, |
---|
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
15 | # See the License for the specific language governing permissions and |
---|
16 | # limitations under the License. |
---|
17 | # |
---|
18 | # Project Website: www.flarmradar.ch |
---|
19 | # Email: info@flarmradar.ch |
---|
20 | # Authors: |
---|
21 | # 2012-2015 Simon Moser |
---|
22 | # 2013-2015 Dominic Spreitz |
---|
23 | # 2014-2015 Giorgio Tresoldi |
---|
24 | #------------------------------------------------------------------------------- |
---|
25 | #!/usr/bin/perl |
---|
26 | |
---|
27 | use strict; |
---|
28 | use Math::Trig; |
---|
29 | |
---|
30 | my $r = 6371000.785; |
---|
31 | my $maptype = "satellite"; |
---|
32 | my $weight = 3; |
---|
33 | my $zoom = 14; |
---|
34 | my $size = "600x600"; |
---|
35 | my $sensor = "false"; |
---|
36 | my $url = "https://maps.googleapis.com/maps/api/staticmap"; |
---|
37 | my $known_flarms = { |
---|
38 | "4B0CF5" => "Robin HB-EXP", |
---|
39 | "4B1307" => "Bravo HB-HFJ" |
---|
40 | }; |
---|
41 | my $step_time = 3; |
---|
42 | my $timeout = 45; |
---|
43 | |
---|
44 | my ($from, $until, $before, $now) = (undef, undef, undef, undef); |
---|
45 | my ($own_lat, $own_long); |
---|
46 | my $flarm = undef; |
---|
47 | my $seen; |
---|
48 | |
---|
49 | sub fstr { |
---|
50 | my ($value,$precision) = @_; |
---|
51 | $precision ||= 5; |
---|
52 | my $s = sprintf("%.${precision}f", $value); |
---|
53 | $s =~ s/\.?0*$//; |
---|
54 | return $s; |
---|
55 | } |
---|
56 | |
---|
57 | |
---|
58 | sub parse_GPGGA { |
---|
59 | my ($line) = @_; |
---|
60 | my ($msg,$time,$lat,$northsouth,$long,$eastwest,$quality,$satelites,$dhop,$alt) = split(/,/, $line); |
---|
61 | my ($g_lat, $g_long) = nmeaToGoogle($lat,$northsouth,$long,$eastwest); |
---|
62 | print "nmea: " . $lat . $northsouth . "," . $long . $eastwest . "\n"; |
---|
63 | print "google: " . $g_lat . "," . $g_long . "\n"; |
---|
64 | $now = $time; |
---|
65 | $own_lat = $g_lat; |
---|
66 | $own_long = $g_long; |
---|
67 | } |
---|
68 | |
---|
69 | sub parse_PFLAA { |
---|
70 | my ($line) = @_; |
---|
71 | my ($msg,$alarm,$rel_north,$rel_east,$rel_vert,$id_type,$id,$track,$turnrate,$groundspeed,$climb,$type) = split(/,/, $line); |
---|
72 | return unless (defined($now)); |
---|
73 | return if (defined($from) && $now < $from); |
---|
74 | return if (defined($until) && $now > $until); |
---|
75 | return if (defined($flarm) && $id ne $flarm); |
---|
76 | return unless (defined($own_lat)); |
---|
77 | return unless (defined($own_long)); |
---|
78 | return unless ($groundspeed > 10 || $rel_vert > 20); |
---|
79 | |
---|
80 | print $now . ": " . $line . " " . ($own_lat+distToLat($rel_north)) . "," . ($own_long+distToLong($rel_east)) . "\n"; |
---|
81 | store($now, $id, $own_lat + distToLat($rel_north), $own_long + distToLong($rel_east)); |
---|
82 | } |
---|
83 | |
---|
84 | sub store { |
---|
85 | my ($time, $id, $g_lat, $g_long) = @_; |
---|
86 | |
---|
87 | if (!exists($seen->{$id})) { |
---|
88 | $seen->{$id} = (); |
---|
89 | } |
---|
90 | if (!defined($before) || $now >= $before+$step_time) { |
---|
91 | $before = $now; |
---|
92 | push(@{$seen->{$id}}, [$time, $g_lat, $g_long]); |
---|
93 | } |
---|
94 | } |
---|
95 | |
---|
96 | sub distToLat { |
---|
97 | my ($dist) = @_; |
---|
98 | return 180*$dist/($r*pi); |
---|
99 | } |
---|
100 | |
---|
101 | sub distToLong { |
---|
102 | my ($dist) = @_; |
---|
103 | return 180*$dist/(cos($own_lat*pi/180)*$r*pi); |
---|
104 | } |
---|
105 | |
---|
106 | sub nmeaToGoogle { |
---|
107 | my ($lat,$northsouth,$long,$eastwest) = @_; |
---|
108 | my $lat_sign = ($northsouth =~ /N/) ? 1 : -1; |
---|
109 | $lat =~ /^(\d{2})(\d{2})\.(\d{5})$/; |
---|
110 | my $g_lat = ($1 + ($2 + $3*1e-5)/60) * $lat_sign; |
---|
111 | |
---|
112 | my $long_sign = ($eastwest =~ /E/) ? 1 : -1; |
---|
113 | $long =~ /^(\d{3})(\d{2})\.(\d{5})$/; |
---|
114 | my $g_long = ($1 + ($2 + $3*1e-5)/60) * $long_sign; |
---|
115 | return ($g_lat, $g_long); |
---|
116 | } |
---|
117 | |
---|
118 | while (my $line = <>) { |
---|
119 | chomp($line); |
---|
120 | ($line =~ /^\$GPGGA/) && parse_GPGGA($line); |
---|
121 | ($line =~ /^\$PFLAA/) && parse_PFLAA($line); |
---|
122 | } |
---|
123 | |
---|
124 | foreach my $flarm_id (keys(%{$seen})) { |
---|
125 | my $plane = exists($known_flarms->{$flarm_id}) ? $known_flarms->{$flarm_id} : "???"; |
---|
126 | print "==== Flarm-ID: $flarm_id ($plane) ====\n"; |
---|
127 | |
---|
128 | my $last_record; |
---|
129 | foreach my $record (@{$seen->{$flarm_id}}) { |
---|
130 | my ($time, $g_lat, $g_long) = @{$record}; |
---|
131 | |
---|
132 | if (!defined($last_record) || $time >= $last_record + $timeout) { |
---|
133 | print "\n"; |
---|
134 | print $url |
---|
135 | . "?maptype=" . $maptype |
---|
136 | . "&zoom=" . $zoom |
---|
137 | . "&size=" . $size |
---|
138 | . "&sensor=" . $sensor |
---|
139 | . "¢er=" . fstr($own_lat, 5) . "," . fstr($own_long, 5) |
---|
140 | . "&path=color:red|weight:3"; |
---|
141 | } |
---|
142 | $last_record = $time; |
---|
143 | print "|".fstr($g_lat,5) . "," . fstr($g_long, 5); |
---|
144 | } |
---|
145 | $last_record = undef; |
---|
146 | print "\n\n"; |
---|
147 | } |
---|
148 | |
---|
149 | |
---|