3 # This module impliments the protocal mode for a dx cluster
5 # Copyright (c) 1998 Dirk Koopman G1TLH
25 # obtain a new connection this is derived from dxchannel
30 my $self = DXChannel::alloc(@_);
31 $self->{sort} = 'A'; # in absence of how to find out what sort of an object I am
35 # this is how a pc connection starts (for an incoming connection)
36 # issue a PC38 followed by a PC18, then wait for a PC20 (remembering
37 # all the crap that comes between).
40 my ($self, $line) = shift;
41 my $call = $self->call;
43 # remember type of connection
44 $self->{consort} = $line;
47 $self->send_now('B',"0");
49 # send initialisation string
50 $self->send($self->pc38()) if DXNode->get_all();
51 $self->send($self->pc18());
52 $self->state('normal');
57 # This is the normal pcxx despatcher
61 my ($self, $line) = @_;
62 my @field = split /[\^\~]/, $line;
64 # ignore any lines that don't start with PC
65 return if !$field[0] =~ /^PC/;
68 my ($pcno) = $field[0] =~ /^PC(\d\d)/; # just get the number
69 return if $pcno < 10 || $pcno > 51;
72 if ($pcno == 10) {last SWITCH;}
73 if ($pcno == 11) { # dx spot
77 if ($pcno == 12) {last SWITCH;}
78 if ($pcno == 13) {last SWITCH;}
79 if ($pcno == 14) {last SWITCH;}
80 if ($pcno == 15) {last SWITCH;}
81 if ($pcno == 16) {last SWITCH;}
82 if ($pcno == 17) {last SWITCH;}
83 if ($pcno == 18) {last SWITCH;}
84 if ($pcno == 19) {last SWITCH;}
85 if ($pcno == 20) { # send local configuration
87 # set our data (manually 'cos we only have a psuedo channel [at the moment])
88 my $hops = $self->get_hops();
89 $self->send("PC19^1^$main::mycall^0^$DXProt::myprot_version^$hops^");
91 # get all the local users and send them out
93 for (@list = DXCommandmode::get_all(); @list; ) {
94 @list = $self->pc16(@list);
95 my $out = shift @list;
98 $self->send($self->pc22());
101 if ($pcno == 21) { # delete a cluster from the list
105 if ($pcno == 22) {last SWITCH;}
106 if ($pcno == 23) {last SWITCH;}
107 if ($pcno == 24) {last SWITCH;}
108 if ($pcno == 25) {last SWITCH;}
109 if ($pcno == 26) {last SWITCH;}
110 if ($pcno == 27) {last SWITCH;}
111 if ($pcno == 28) {last SWITCH;}
112 if ($pcno == 29) {last SWITCH;}
113 if ($pcno == 30) {last SWITCH;}
114 if ($pcno == 31) {last SWITCH;}
115 if ($pcno == 32) {last SWITCH;}
116 if ($pcno == 33) {last SWITCH;}
117 if ($pcno == 34) {last SWITCH;}
118 if ($pcno == 35) {last SWITCH;}
119 if ($pcno == 36) {last SWITCH;}
120 if ($pcno == 37) {last SWITCH;}
121 if ($pcno == 38) {last SWITCH;}
122 if ($pcno == 39) {last SWITCH;}
123 if ($pcno == 40) {last SWITCH;}
124 if ($pcno == 41) {last SWITCH;}
125 if ($pcno == 42) {last SWITCH;}
126 if ($pcno == 43) {last SWITCH;}
127 if ($pcno == 44) {last SWITCH;}
128 if ($pcno == 45) {last SWITCH;}
129 if ($pcno == 46) {last SWITCH;}
130 if ($pcno == 47) {last SWITCH;}
131 if ($pcno == 48) {last SWITCH;}
132 if ($pcno == 49) {last SWITCH;}
136 if ($pcno == 51) { # incoming ping requests/answers
139 if ($field[1] eq $main::mycall) {
140 my $flag = $field[3];
142 $self->send($self->pc51($field[2], $field[1], $flag));
144 # route down an appropriate thingy
145 $self->route($field[1], $line);
151 # if get here then rebroadcast the thing with its Hop count decremented (if
152 # the is one). If it has a hop count and it decrements to zero then don't
155 # NOTE - don't arrive here UNLESS YOU WANT this lump of protocol to be
159 my $hopfield = pop @field;
160 push @field, $hopfield;
163 if (($hops) = $hopfield =~ /H(\d+)\^\~?$/o) {
164 my $newhops = $hops - 1;
166 $line =~ s/\^H$hops(\^\~?)$/\^H$newhops$1/; # change the hop count
167 DXProt->broadcast($line, $self); # send it to everyone but me
173 # This is called from inside the main cluster processing loop and is used
174 # for despatching commands that are doing some long processing job
179 my @chan = DXChannel->get_all();
182 foreach $chan (@chan) {
183 next if !$chan->is_ak1a();
185 # send a pc50 out on this channel
186 if ($t >= $chan->pc50_t + $DXProt::pc50_interval) {
194 # finish up a pc context
202 # add a (local) user to the cluster
211 # delete a (local) user to the cluster
220 # add a (locally connected) node to the cluster
229 # delete a (locally connected) node to the cluster
237 # some active measures
241 # route a message down an appropriate interface for a callsign
243 # expects $self to indicate 'from' and is called $self->route(to, pcline);
247 my ($self, $call, $line) = @_;
248 my $cl = DXCluster->get($call);
250 my $dxchan = $cl->{dxchan};
251 $cl->send($line) if $dxchan;
255 # broadcast a message to all clusters [except those mentioned after buffer]
258 my $pkg = shift; # ignored
259 my $s = shift; # the line to be rebroadcast
260 my @except = @_; # to all channels EXCEPT these (dxchannel refs)
261 my @chan = DXChannel->get_all();
264 L: foreach $chan (@chan) {
265 next if !$chan->sort eq 'A'; # only interested in ak1a channels
266 foreach $except (@except) {
267 next L if $except == $chan; # ignore channels in the 'except' list
269 chan->send($s); # send it
274 # gimme all the ak1a nodes
278 my @list = DXChannel->get_all();
281 foreach $ref (@list) {
282 push @out, $ref if $ref->sort eq 'A';
288 # obtain the hops from the list for this callsign and pc no
293 my ($self, $pcno) = @_;
294 return "H$DXProt::def_hopcount"; # for now
298 # All the PCxx generation routines
302 # add one or more users (I am expecting references that have 'call',
303 # 'confmode' & 'here' method)
305 # NOTE this sends back a list containing the PC string (first element)
306 # and the rest of the users not yet processed
311 my @list = @_; # list of users
312 my @out = ('PC16', $main::mycall);
315 for ($i = 0; @list && $i < $DXProt::pc16_max_users; $i++) {
316 my $ref = shift @list;
317 my $call = $ref->call;
318 my $s = sprintf "%s %s %d", $call, $ref->confmode ? '*' : '-', $ref->here;
321 push @out, $self->get_hops();
322 my $str = join '^', @out;
324 return ($str, @list);
327 # Request init string
330 return "PC18^wot a load of twaddle^$DXProt::myprot_version^~";
334 # add one or more nodes
336 # NOTE this sends back a list containing the PC string (first element)
337 # and the rest of the nodes not yet processed (as PC16)
342 my @list = @_; # list of users
343 my @out = ('PC19', $main::mycall);
346 for ($i = 0; @list && $i < $DXProt::pc19_max_nodes; $i++) {
347 my $ref = shift @list;
348 push @out, $ref->here, $ref->call, $ref->confmode, $ref->pcversion;
350 push @out, $self->get_hops();
351 my $str = join '^', @out;
353 return ($str, @list);
365 my ($self, $ref, $reason) = @_;
366 my $call = $ref->call;
367 my $hops = $self->get_hops();
368 return "PC21^$call^$reason^$hops^";
377 # send all the DX clusters I reckon are connected
380 my @list = DXNode->get_all();
384 foreach $list (@list) {
385 push @nodes, $list->call;
387 return "PC38^" . join(',', @nodes) . "^~";
390 # periodic update of users, plus keep link alive device (always H99)
393 my $n = DXNodeuser->count;
394 return "PC50^$main::mycall^$n^H99^";
400 my ($self, $to, $from, $val) = @_;
401 return "PC51^$to^$from^$val^";