source: core/trunk/client/ads2flarm.pl @ 311

Last change on this file since 311 was 296, checked in by smoser, 11 years ago

Update Copyright, fix encoding issue

  • Property svn:mime-type set to text/plain
File size: 4.5 KB
Line 
1#-------------------------------------------------------------------------------
2# This file is part of the FLARM®-Radar Project.
3#   
4#   Copyright 2012-2014 Simon Moser
5#   Copyright 2013-2014 Dominic Spreitz
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11#   http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18#
19#   Project Website: www.flarmradar.ch
20#   Email: info@flarmradar.ch
21#-------------------------------------------------------------------------------
22#!/usr/bin/perl
23
24# see http://www.lll.lu/~edward/edward/adsb/DecodingADSBposition.html
25
26use strict;
27use warnings;
28use Time::HiRes qw ( setitimer ITIMER_VIRTUAL ITIMER_REAL time );;
29
30sub readMessage {
31        my $result = undef;
32        my %msg = ();
33        while (my $line = <>) {
34                # encoded message, like '*02e19837a89cb6;'
35                if ($line =~ /^\*(.*);/) {
36                        $msg{"enc"} = $1;
37                }
38               
39                # downlink format, like 'DF 17: ADS-B message.'
40                # we just take the numerical value
41                if ($line =~ /^DF (\d*): /) {
42                        $msg{"df"} = $1;
43                }
44               
45                # every line starting with blanks is a payload
46                if ($line =~ /^\s+/) {
47                        unless (exists($msg{"payload"})) {
48                                my @payload = ();
49                                $msg{"payload"} = \@payload;
50                        }
51                        push(@{$msg{"payload"}}, $line);
52                }
53               
54                # messages are sparated by an empty line
55                if ($line =~ /^$/) {
56                        # make sure that we don't return an incomplete message
57                        $result = \%msg;
58                        last;
59                }
60        }
61        return $result;
62}
63
64sub parseMessage {
65        my ($msg) = @_;
66       
67        # we are just interested in downlink format == 17
68        if ($msg->{"df"} == 17) {
69                parseADSBMessage($msg->{"payload"});
70        }
71}
72
73sub parseADSBMessage{
74        my ($payload) = @_;
75        my %data;
76        while (my $line = shift(@$payload)) {
77                chomp($line);
78               
79                # icao code
80                if ($line =~ /^\s*ICAO Address\s*:\s*(\w+)\s*$/) {
81                        $data{"icao"} = $1;
82                }
83               
84                # altitude
85                # TODO: be careful with "feet"
86                if ($line =~ /^\s*Altitude\s*:\s*(\d+)\s*feet\s*$/)     {
87                        $data{"alt"} = $1;
88                }
89               
90                # latitude
91                if ($line =~ /^\s*Latitude\s*:\s*(\S+)\s*$/)    {
92                        $data{"lat"} = $1;
93                }
94
95                # longitude
96                if ($line =~ /^\s*Longitude\s*:\s*(\S+)\s*$/)   {
97                        $data{"long"} = $1;
98                }
99               
100                # speed is divided into two vectors
101                if ($line =~ /^\s*EW velocity\s*:\s*(-?\d+)\s*$/)       {
102                        $data{"speed_ew"} = $1;
103                }
104               
105                if ($line =~ /^\s*NS velocity\s*:\s*(-?\d+)\s*$/)       {
106                        $data{"speed_ns"} = $1;
107                }
108               
109                # TODO: unsure about vertical rate, needs confirmation
110                if ($line =~ /^\s*Vertical rate\s*:\s*(-?\d+)\s*$/)     {
111                        $data{"vertical"} = $1;
112                }
113        }
114       
115        storeInCache(\%data);
116}
117
118my %cache;
119sub storeInCache {
120        my ($data) = @_;
121               
122        my $icao = $data->{"icao"};
123        foreach my $key (keys(%$data)) {
124                next if ($key eq "icao");
125                $cache{$icao}->{$key} = $data->{$key};
126        }
127       
128        # update the timestamp
129        $cache{$icao}->{"timestamp"} = time;
130               
131}
132
133sub purgeOutdated {
134        my @toDelete = ();
135        my $now = time;
136        foreach my $icao (keys(%cache)) {
137                if ($cache{$icao}->{"timestamp"} < $now - 30) {
138                        push @toDelete, $icao;
139                }
140        }
141       
142        foreach my $icao (@toDelete) {
143                $cache{$icao} = undef;
144        }
145}
146
147sub printPFLAA {
148        my ($icao, $data) = @_;
149        print "\$PFLAA,0";
150        print "," . $data->{"lat"};
151        print "," . $data->{"long"};
152        print "," . $data->{"alt"};
153        print ",1";
154        print "," . $icao;
155        print ",track_not_yet_done";
156        print ",turnrate_not_needed";
157        print "," . speed($data->{"speed_ew"}, $data->{"speed_ns"});
158        print "," . $data->{"vertical"};
159        print ",1";
160        print "*checksum_not_needed";
161        print "\n";
162}
163
164sub printCache {
165        purgeOutdated();
166       
167        foreach my $icao (keys(%cache)) {
168                printPFLAA($icao, $cache{$icao}) if (checkRequiredFields($icao, $cache{$icao}));
169        }
170}
171
172sub checkRequiredFields {
173        my ($icao, $data) = @_;
174        foreach my $key (requiredFields()) {
175                unless (exists($data->{$key})) {
176                        return 0;
177                }
178        }
179        return 1;
180}
181
182sub requiredFields { return qw( lat long alt speed_ns speed_ew vertical ) }
183
184sub speed {
185        my ($speed_ew, $speed_ns) = @_;
186        return sqrt($speed_ew*$speed_ew + $speed_ns+$speed_ns);
187}
188
189# we set a timer that fires every second a SIGALRM
190setitimer(ITIMER_REAL, 1, 1);
191$SIG{ALRM} = \&printCache;
192
193# main loop: read from stdin
194while (my $msg = readMessage()) {
195        last unless defined($msg);
196        parseMessage($msg);     
197}
198
199# make sure that we print out our cache at least once
200printCache();
201
Note: See TracBrowser for help on using the repository browser.