adjust startup descriptions a bit
[spider.git] / perl / Geomag.pm
1 #!/usr/bin/perl
2
3 # The geomagnetic information and calculation module
4 # a chanfe
5 #
6 # Copyright (c) 1998 - Dirk Koopman G1TLH
7 #
8 #
9 #
10
11 package Geomag;
12
13 use DXVars;
14 use DXUtil;
15 use DXLog;
16 use Julian;
17 use IO::File;
18 use DXDebug;
19 use DXDupe;
20 use Time::HiRes qw(gettimeofday tv_interval);
21
22 use strict;
23
24 use vars qw($date $sfi $k $a $r $forecast @allowed @denied $fp $node $from 
25             $dirprefix $param
26             $duplth $dupage $filterdef);
27
28 $fp = 0;                                                # the DXLog fcb
29 $date = 0;                                              # the unix time of the WWV (notional)
30 $sfi = 0;                                               # the current SFI value
31 $k = 0;                                                 # the current K value
32 $a = 0;                                                 # the current A value
33 $r = 0;                                                 # the current R value
34 $forecast = "";                                 # the current geomagnetic forecast
35 $node = "";                                             # originating node
36 $from = "";                                             # who this came from
37 @allowed = ();                                  # if present only these callsigns are regarded as valid WWV updators
38 @denied = ();                                   # if present ignore any wwv from these callsigns
39 $duplth = 20;                                   # the length of text to use in the deduping
40 $dupage = 12*3600;                              # the length of time to hold spot dups
41
42 $dirprefix = "$main::local_data/wwv";
43 $param = "$dirprefix/param";
44
45 our $maxcache = 10;
46 our @cache;
47
48
49 $filterdef = bless ([
50                           # tag, sort, field, priv, special parser 
51                           ['by', 'c', 0],
52                           ['origin', 'c', 1],
53                           ['channel', 'c', 2],
54                           ['by_dxcc', 'nc', 3],
55                           ['by_itu', 'ni', 4],
56                           ['by_zone', 'nz', 5],
57                           ['origin_dxcc', 'nc', 6],
58                           ['origin_itu', 'ni', 7],
59                           ['origin_zone', 'nz', 8],
60                          ], 'Filter::Cmd');
61
62 sub init
63 {
64         $fp = DXLog::new('wwv', 'dat', 'm');
65         do "$param" if -e "$param";
66         # read in existing data
67         my $t0 = [gettimeofday];
68         @cache = readfile($main::systime);
69         shift @cache while @cache > $maxcache;  
70         dbg(sprintf "WWV read in last %d records into cache in %dmS", scalar @cache, _diffms($t0));     
71         confess $@ if $@;
72 }
73
74 # write the current data away
75 sub store
76 {
77         my $fh = new IO::File;
78         open $fh, "> $param" or confess "can't open $param $!";
79         print $fh "# Geomagnetic data parameter file last mod:", scalar gmtime, "\n";
80         print $fh "\$date = $date;\n";
81         print $fh "\$sfi = $sfi;\n";
82         print $fh "\$a = $a;\n";
83         print $fh "\$k = $k;\n";
84         print $fh "\$r = $r;\n";
85         print $fh "\$from = '$from';\n";
86         print $fh "\$node = '$node';\n";
87         print $fh "\@denied = qw(", join(' ', @denied), ");\n" if @denied > 0;
88         print $fh "\@allowed = qw(", join(' ', @allowed), ");\n" if @allowed > 0;
89         close $fh;
90         
91         # log it
92         my $s ="$from^$date^$sfi^$a^$k^$forecast^$node^$r";
93         $fp->writeunix($date, $s);
94         push @cache, [ split /\^/, $s ];
95         shift @cache while @cache > $maxcache; 
96 }
97
98 # update WWV info in one go (usually from a PC23)
99 sub update
100 {
101         my ($mydate, $mytime, $mysfi, $mya, $myk, $myforecast, $myfrom, $mynode, $myr) = @_;
102         $myfrom =~ s/-\d+$//;
103         if ((@allowed && grep {$_ eq $myfrom} @allowed) || 
104                 (@denied && !grep {$_ eq $myfrom} @denied) ||
105                 (@allowed == 0 && @denied == 0)) {
106                 
107                 #       my $trydate = cltounix($mydate, sprintf("%02d18Z", $mytime));
108                 if ($mydate > $date) {
109                         if ($myr) {
110                                 $r = 0 + $myr;
111                         } else {
112                                 $r = 0 unless abs ($mysfi - $sfi) > 3;
113                         }
114                         $sfi = 0 + $mysfi;
115                         $k = 0 + $myk;
116                         $a = 0 + $mya;
117                         $forecast = $myforecast;
118                         $date = $mydate;
119                         $from = $myfrom;
120                         $node = $mynode;
121                         
122                         store();
123                 }
124         }
125 }
126
127 # add or substract an allowed callsign
128 sub allowed
129 {
130         my $flag = shift;
131         if ($flag eq '+') {
132                 push @allowed, map {uc $_} @_;
133         } else {
134                 my $c;
135                 foreach $c (@_) {
136                         @allowed = map {$_ ne uc $c} @allowed; 
137                 } 
138         }
139         store();
140 }
141
142 # add or substract a denied callsign
143 sub denied
144 {
145         my $flag = shift;
146         if ($flag eq '+') {
147                 push @denied, map {uc $_} @_;
148         } else {
149                 my $c;
150                 foreach $c (@_) {
151                         @denied = map {$_ ne uc $c} @denied; 
152                 } 
153         }
154         store();
155 }
156
157 # accessor routines (when I work how symbolic refs work I might use one of those!)
158 sub sfi
159 {
160         @_ ? $sfi = shift : $sfi ;
161 }
162
163 sub k
164 {
165         @_ ? $k = shift : $k ;
166 }
167
168 sub r
169 {
170         @_ ? $r = shift : $r ;
171 }
172
173 sub a
174 {
175         @_ ? $a = shift : $a ;
176 }
177
178 sub forecast
179 {
180         @_ ? $forecast = shift : $forecast ;
181 }
182
183
184 #
185 # print some items from the log backwards in time
186 #
187 # This command outputs a list of n lines starting from line $from to $to
188 #
189 sub search
190 {
191         my $from = shift;
192         my $to = shift;
193         my $t = shift;
194         my $date = $fp->unixtoj($t);
195         my $pattern = shift;
196         my $search;
197         my @out;
198         my $eval;
199         my $count;
200
201         if ($t == $main::systime && ($to <= $maxcache)) {
202                 dbg("using wwv cache") if isdbg('wwv');
203                 @out = reverse @cache;
204                 pop @out while @out > $to;
205         } else {
206                 dbg("using wwv file(s))") if isdbg('wwv');
207                 $search = 1;
208                 $eval = qq(
209                            my \$c;
210                            my \$ref;
211                            for (\$c = \$#in; \$c >= 0; \$c--) {
212                                         \$ref = \$in[\$c];
213                                         if ($search) {
214                                                 \$count++;
215                                                 next if \$count < \$from;
216                                                 push \@out, \$ref;
217                                                 last if \$count >= \$to; # stop after n
218                                         }
219                                 }
220                           );
221         
222                 $fp->close;                                     # close any open files
223                 
224                 my $fh = $fp->open($date); 
225                 for ($count = 0; $count < $to; ) {
226                         my @in = ();
227                         if ($fh) {
228                                 while (<$fh>) {
229                                         chomp;
230                                         push @in, [ split '\^' ] if length > 2;
231                                 }
232                                 eval $eval;                     # do the search on this file
233                                 return ("Geomag search error", $@) if $@;
234                                 last if $count >= $to; # stop after n
235                         }
236                         $fh = $fp->openprev();  # get the next file
237                         last if !$fh;
238                 }
239         }
240         
241         return @out;
242 }
243
244 #
245 # the standard log printing interpreting routine.
246 #
247 # every line that is printed should call this routine to be actually visualised
248 #
249 # Don't really know whether this is the correct place to put this stuff, but where
250 # else is correct?
251 #
252 # I get a reference to an array of items
253 #
254 sub print_item
255 {
256         my $r = shift;
257         my @ref = @$r;
258         my $d = cldate($ref[1]);
259         my ($t) = (gmtime($ref[1]))[2];
260         
261         return sprintf("$d   %02d %5d %3d %3d %-37s <%s>", $t, $ref[2], $ref[3], $ref[4], $ref[5], $ref[0]);
262 }
263
264 #
265 # read in this month's data
266 #
267 sub readfile
268 {
269         my $date = $fp->unixtoj(shift);
270         my $fh = $fp->open($date); 
271         my @spots = ();
272         my @in;
273         
274         if ($fh) {
275                 while (<$fh>) {
276                         chomp;
277                         push @in, [ split '\^' ] if length > 2;
278                 }
279         }
280         return @in;
281 }
282
283 # enter the spot for dup checking and return true if it is already a dup
284 sub dup
285 {
286         my ($d, $sfi, $k, $a, $text, $call) = @_; 
287
288         # dump if too old
289         return 2 if $d < $main::systime - $dupage;
290  
291         my $dupkey = "W$d|$sfi|$k|$a|$call";
292         return DXDupe::check($dupkey, $main::systime+$dupage);
293 }
294
295 sub listdups
296 {
297         return DXDupe::listdups('W', $dupage, @_);
298 }
299 1;
300 __END__;
301