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

Last change on this file since 294 was 277, checked in by smoser, 11 years ago

#155

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