#!/usr/bin/perl # direxant-aprsis-rec - record APRS-IS data feed for a list of callsigns # generates live GeoRSS feed of the data which can be displayed on Google Maps # written by Ian Kluft KO6YQ for Direxant # released under GNU General Public License version 3 use strict; use warnings; use Getopt::Long; use IO::Socket::INET; use Ham::APRS::FAP qw( parseaprs ); use XML::RSS; # configuration my $VERSION = "0.02"; my $debug = 0; my $int_received = 0; # globals my ( $logfile, $mycall, $rssfile, $filter, %tracks, $defpoint, $regex ); # print debugging statements sub debug { $debug and print STDERR "$0: debug: ".join( " ", @_ )."\n" }; # function: update RSS sub update_rss { my $rss = new XML::RSS( version => '2.0' ); $rss->add_module( uri => "http://www.georss.org/georss", prefix => "georss" ); $rss->channel( title => "Direxant APRS track plot", description => "APRS track plot for " .join( ", ", keys %tracks ), ); my ( $call, $point, @points ); foreach $call ( sort keys %tracks ) { @points = (); foreach $point ( @{$tracks{$call}}) { push @points, $point->{latitude}, $point->{longitude}; } my $last = $tracks{$call}[( scalar @{$tracks{$call}})-1 ]; my $last_point = $last->{latitude}." ".$last->{longitude}; debug "last point:", $last_point; my $desc; if ( exists $last->{altitude}) { $desc = sprintf "%s last reported at " ."%8.5f, %9.5f altitude %dm/%d'", $call, $last->{latitude}, $last->{longitude}, $last->{altitude}, $last->{altitude}*3.2808399; } else { $desc = sprintf "%s last reported at " ."%8.5f, %9.5f", $call, $last->{latitude}, $last->{longitude}; } my @geo; if (( scalar @points ) > 2 ) { push @geo, ( line => join( " ", @points )); } push @geo, ( point => $last_point ); $rss->add_item ( title => $call, description => $desc, georss => { @geo }, ); } # check if empty if ( ! @{$rss->{'items'}} and ( defined $defpoint )) { # use default coordinates $defpoint =~ s/,/ /g; $rss->add_item ( title => "near launch site", georss => { point => $defpoint }, ); } # save $rss->save( $rssfile ); } # parse a manually-added record sub parserec { my $logline = shift; my $dataref = shift; debug "parserec:", $logline; ( $logline =~ /^\+rec\s+/ ) or return 0; my @var_assigns = ( $logline =~ /([a-z0-9]+="[^"]*")/ig ); my $var_assign; foreach $var_assign ( @var_assigns ) { if ( $var_assign =~ /([a-z0-9]+)="([^"]*)"/i ) { my $name = $1; my $value = $2; debug "parserec: $name = $value"; $dataref->{$name} = $value; } } return 1; } # function: parse and save data from one or more log entries sub log2track { my $logline; while ( $logline = shift ) { my %pdata; if ( parserec ( $logline, \%pdata ) or parseaprs( $logline, \%pdata )) { if ( exists $pdata{srccallsign}) { if ( ! exists $tracks{$pdata{srccallsign}}) { $tracks{$pdata{srccallsign}} = []; } push @{$tracks{$pdata{srccallsign}}}, \%pdata; } } } update_rss; } # signal handler sub inthandler { $int_received = 1; } # process command line my $result = GetOptions ( "debug" => \$debug, "call=s" => \$mycall, "log=s" => \$logfile, "rss=s" => \$rssfile, "filter=s" => \$filter, "default:s" => \$defpoint, "regex:s" => \$regex, ) or die "usage: $0 --call=your-callsign --log=logfile --rss=rssfile " ."--filter=callsign/callsign/...\n"; # gulp logfile if it already exists my @log; if ( -e $logfile ) { open LOG, $logfile or die "$0: failed to open logfile for read: $!\n"; my @log = ; chomp @log; close LOG; log2track @log; } # open logfile for append open LOG, ">>$logfile" or die "$0: failed to open logfile for append: $!\n"; # open socket my $sock = IO::Socket::INET->new( PeerAddr => 'sjc.aprs2.net', PeerPort => 14580, Proto => 'tcp', ) or die "$0: failed to open socket: $!\n"; $sock->autoflush(1); # read a line from the server to wait for it to be ready my $line = <$sock>; print $line; # set filter parameters print $sock "user $mycall pass -1 vers direxant-aprsis-rec $VERSION " .(( defined $filter ) ? "filter $filter" : "" ) ."\n"; # read from server while ( ! $int_received and ( $line = <$sock>)) { ( $line =~ /^\#/ ) and next; chomp $line; debug "line:", $line; if (( defined $regex ) and ( !( $line =~ /$regex/i ))) { debug "discarded"; next; } print LOG $line."\n"; log2track $line; } close LOG;