3 # An RBN deduping filter
5 # Copyright (c) 2017 Dirk Koopman G1TLH
10 use IO::Socket::IP -register;
11 use Math::Round qw(nearest);
15 my $host = 'telnet.reversebeacon.net';
18 my $minspottime = 60*60; # minimum length of time between successive identical spots
19 my $showstats; # show RBN and Spot stats
35 #Getopt::Long::Configure( qw(auto_abbrev) );
36 GetOptions('host=s' => \$host,
40 'stats' => \$showstats,
42 'repeattime|rt=i' => sub { $minspottime = $_[1] * 60 },
44 my ($name, $value) = @_;
45 $wantcw = $wantrtty = $wantpsk = $wantbeacon = $wantdx = 0;
46 for (split /[:,\|]/, $value) {
48 ++$wantpsk if /^psk$/i;
49 ++$wantrtty if /^rtty$/i;
50 ++$wantbeacon if /^beacon$/i;
56 '<>' => sub { $mycall = shift },
61 pod2usage(1) if $help || !$mycall;
62 pod2usage(-exitval => 0, -verbose => 2) if $man;
65 for ($attempts = 1; $attempts <= 5; ++$attempts) {
66 say "ADMIN,connecting to $host $port.. (attempt $attempts) " if $dbg;
67 $sock = IO::Socket::IP->new(
75 die "ADMIN,Cannot connect to $host:$port after 5 attempts $!" unless $sock;
76 say "ADMIN,connected" if $dbg;
77 print $sock "$mycall\r\n";
78 say "ADMIN,call sent" if $dbg;
93 say "RAW,$_" if $wantraw;
95 my (undef, undef, $origin, $qrg, $call, $mode, $s, $m, $spd, $u, $sort, $t, $tx) = split /[:\s]+/;
98 # We have an RBN data line, dedupe it very simply on time, ignore QRG completely.
99 # This works because the skimmers are NTP controlled (or should be) and will receive
100 # the spot at the same time (velocity factor of the atmosphere taken into account :-)
105 # fix up times for things like 'NXDXF B' etc
106 if ($tx && $t != /^\d{4}Z$/) {
107 if ($tx =~ /^\d{4}Z$/) {
118 $qrg = sprintf('%.1f', nearest(.1, $qrg)); # to nearest 100Hz (to catch the odd multiple decpl QRG [eg '7002.07']).
119 say join(',', "RBN", $origin, $qrg, $call, $mode, $s, $m, $spd, $u, $sort, $t) if !$wantraw && ($dbg || $showrbn);
121 # Determine whether to "SPOT" it based on whether we have not seen it before (near this QRG) or,
122 # if we have, has it been a "while" since the last time we spotted it? If it has been spotted
123 # before then "RESPOT" it.
124 my $nqrg = nearest(1, $qrg); # normalised to nearest Khz
125 my $sp = "$call|$nqrg"; # hopefully the skimmers will be calibrated at least this well!
128 if (!$ts || ($minspottime > 0 && $tim - $ts >= $minspottime)) {
129 if ($wantbeacon && $sort =~ /^BEA/) {
132 # Haven't used a perl 'goto' like this ever!
133 # Clearly I need to use an event driven framework :-)
134 goto periodic if !$wantcw && $mode =~ /^CW/;
135 goto periodic if !$wantrtty && $mode =~ /^RTTY/;
136 goto periodic if !$wantpsk && $mode =~ /^PSK/;
137 goto periodic if !$wantdx && $mode =~ /^DX/;
141 my $tag = $ts ? "RESPOT" : "SPOT";
142 say join(',', $tag, $origin, $qrg, $call, $mode, $s, $m, $spd, $u, $sort, $t);
146 say "DATA,$_" if $dbg && !$wantraw;
150 # periodic clearing out of the two caches
151 if (($tim % 60 == 0 && $tim > $last) || ($last && $tim >= $last + 60)) {
155 while (my ($k,$v) = each %d) {
163 say "ADMIN,rbn cache: $removed removed $count remain" if $dbg;
164 $count = $removed = 0;
165 while (my ($k,$v) = each %spot) {
166 if ($tim-$v > $minspottime*2) {
173 say "ADMIN,spot cache: $removed removed $count remain" if $dbg;
175 say join(',', "STAT", $noraw, $norbn, $nospot) if $showstats;
176 $noraw = $norbn = $nospot = 0;
178 $last = int($tim / 60) * 60;
190 rbn.pl - an experimental RBN filter program that
194 rbn.pl [options] <your callsign>
202 Print a brief help message and exits.
206 Prints the manual page and exits.
208 =item B<-host>=telnet.reversebeacon.net
210 As default, this program will connect to C<telnet.reversebeacon.net>. Use this argument to change that.
214 As default, this program will connect to port 7000. Use this argument to change that to some other port.
216 =item B<-want>=cw,rtty,psk,beacon,dx
218 The program will print all spots in all classes in the 'mode' column [cw, rtty, psk, beacon, dx]. You can choose one or more of
219 these classes if you want specific types of spots.
223 Print a comma separated line of statistics once a minute which consists of:
225 STAT,E<lt>raw RBN spotsE<gt>,E<lt>de-duped RBN spotsE<gt>,E<lt>new spotsE<gt>
227 =item B<-repeattime=60>
229 A cache of callsigns and QRGs is kept. If a SPOT comes in after B<repeattime> minutes then it re-emitted
230 but with a RESPOT tag instead. Set this argument to 0 (or less) if you do not want any repeats.
234 Show the de-duplicated RBN lines as they come in.
238 Show the raw RBN lines as they come in.
244 B<This program> connects (as default) to RBN C<telnet.reversebeacon.net:7000> and parses the raw output
245 which it deduplicates and then outputs unique spots. It is possible to select one or more types of spot.
247 The output is the RBN spot line which has been separated out into a comma separated list. One line per spot.
251 SPOT,DK3UA-#,3560.0,DL6ZB,CW,27,dB,26,WPM,CQ,2152Z
252 SPOT,WB6BEE-#,14063.0,KD6SX,CW,24,dB,15,WPM,CQ,2152Z
253 RESPOT,S50ARX-#,1811.5,OM0CS,CW,37,dB,19,WPM,CQ,2152Z
254 SPOT,DF4UE-#,3505.0,TA1PT,CW,11,dB,23,WPM,CQ,2152Z
255 SPOT,AA4VV-#,14031.0,TF3Y,CW,16,dB,22,WPM,CQ,2152Z
256 SPOT,SK3W-#,3600.0,OK0EN,CW,13,dB,11,WPM,BEACON,2152Z
259 If the -raw flag is set then these lines will be interspersed with the raw line from the RBN source, prefixed
260 with "RAW,". For example:
262 RAW,DX de PJ2A-#: 14025.4 IP0TRC CW 16 dB 31 WPM CQ 1307Z
263 RAW,DX de PJ2A-#: 10118.9 K1JD CW 2 dB 28 WPM CQ 1307Z
264 RAW,DX de K2PO-#: 1823.4 HL5IV CW 8 dB 22 WPM CQ 1307Z
265 SPOT,K2PO-#,1823.4,HL5IV,CW,8,dB,22,WPM,CQ,1307Z
266 RAW,DX de LZ7AA-#: 14036.6 HA8GZ CW 7 dB 27 WPM CQ 1307Z
267 RAW,DX de DF4UE-#: 14012.0 R7KM CW 32 dB 33 WPM CQ 1307Z
268 RAW,DX de G7SOZ-#: 14012.2 R7KM CW 17 dB 31 WPM CQ 1307Z