NOS-ABS Beacon Server


What is a NOS-ABS Beacon Server...

A necessary component of a NOS-ABS, an automatic beacon system, is the capability to manage beacon broadcasts. This brief article will outline several methods for setting up the outgoing side of an ABS. By using cron, a shell script, a Perl script, and several data tables and template beacons, a system can be designed with great flexibility, having both the stability of regularly scheduled broadcasts and the interruptibility of on-demand alerts or annoucements.

So in theory, you get the best of both worlds. You can use a programmatic approach to sending beacons, one that is tied to an hourly cycle, and one that may use beacons created on-the-fly for emergency operations. A further plus is that any beacon message may be created from scratch by an operator which, in turn, may be sent out on an interrupt basis. By taking advantage of Perl's string handling capabilities, and Perl's eval function, formats may be merged with "live" data streams, either from a human operator or from socket sources, and inserted into "real-time" documents, which become the beacon texts to be broadcast!




How to set up a NOS-ABS Beacon Server

What do you need to get started? I am assuming a Linux OS, the ability to edit shell scripts, having Perl onboard, and a familiarity with cron. That's it! If you can manage all of the above, you can set up the broadcast side of an ABS in an afternoon...

Composing Your Beacon Files

The first step is to compose your beacon text messages. Let's begin with a very simple one-liner! The text below lives in a file named shortform. I am using the term "form" to imply that this could be more involved and potentially be a form to be filled in.

Example bctext file: /jnos/scripts/beacons/shortform

JNOS/Linux 1.11f * Network 105 * 14.105<>145.090 [Wellesley, MA]

Note too, that this beacon file is located in the directory /jnos/scripts/beacons. (You could choose another location if you like.) On my system, I have placed all beacon/id text files in this directory. And the content here is minimal, just enough to let the net know that you are up, what frequencies can be crossed over, and the geographic location. This is the "classic" one-liner beacon/id.

Let's look at another example beacon text, longform. A bit more information has been included that may be "interesting" or useful to the net.

Example bctext file: /jnos/scripts/beacons/longform

KA1FSB-7/Node WELLS  * Network 105 *  14.105<>145.090 - Karl
    JNOS/Linux 1.11f - TCP/IP 44.56.26.11 - AX25 Utilities
                FN42jh - [Wellesley, MA]

And, it should be pointed out that this file is a plain "flat" file created in an editor, such as vi, and is still the "finished" product with no extra processing being called for. What you see is what you get, just as you typed it in!

Let's look at a more "interesting" example, a file that is really a format in Perl. It is called infoform, on my system.

Example bctext file: /jnos/scripts/beacons/infoform

KA1FSB-7/N (WELLS)  * Network 105 *  FN42jh  [Wellesley, MA]
  Local Time.:@>>>>>>>>             UTC......:@>>>>>>>>
$loctime, $utctime
  Local WX...: @<<<<<<<<<<<<<<<<<<< Temp.....: @<<<<<<<<<<
$wxdesc, $wxtemp
  Watches....: @<<<<<<<<<<<<<<<<<   Warnings.: @<<<<<<<<<<<<
$wxwat, $wxwarn

This "strange" looking file is really a boilerplate or template form that will be filled in according to the values in the variables below each line. So, for example, the variable $loctime will be "slugged" into the first field in its above line. The variable $utctime will be located in the next field, and so on. The variables list must be comma separated and there must be a variable for each field in its above line. The "@" character indicates that this is the beginning of a field to be filled. The "<" and ">" characters indicate the justification and their number, the actual size of the field. (There is a bit more to the format keyword in Perl, a declaration and a trailing dot, but this is all I have placed in the file itself here... )

There is a companion data file to this format file named infoform.var. This file is optional, but is required if the format file has any reference to those variables! At some point these variables need to be loaded with values. A typical variables file for the weather data might look something like this:

Example bctext file: /jnos/scripts/beacons/infoform.var

$wxdesc = "Clear & Sunny";
$wxtemp = "Mid 70's";
$wxwat  = "(none)";
$wxwarn = "(none)";

If this file exists, the program myformer.plx reads in this data and merges it into the format form. You might be wondering what happened to the time related variables. Why aren't they included in the companion variables file? Well, they are built on-the-fly by the Perl program since you want the latest "live" time on the system. What about the weather data? As it stands now, an operator has to fill this in. (However, another program dedicated to this variables file, infoform.var, could update these values from various machine sources, i.e., the internet or other shared data outputs. That is why I chose to separate the format files from the variables files.)

So, to review, the format file only needs to be "designed" once. When you are happy with the appearance, then you can "stuff" it away and not fuss with it anymore. The variables files were designed to either be completely over-written or edited manually, or edited by an automated process on your machine. In other words, an independent listing of data.

To see how this all "comes together," take a look at the next section for the actual Perl code, myformer.plx.

Joining Formats & Data: myformer.plx

This piece of Perl code is really a very primitive server. It can accept inputs from the command line via a named pipe, or from another piece of code, in this case a shell script run from cron. This dual input function is what makes this code interruptible. At nearly any time, an operator can issue a special alert or bulletin via a beacon/id transmission.

A Beaconing Server: /jnos/scripts/myformer.plx

#! /usr/bin/perl -w
# myformer.plx 
# 08-30-04, 08-31-04
# 09-02-04
# KA1FSB/kbn
#
# --------------------------------------------------------------------
# A Merging Server:
#
# Feed in data thru a pipe, now mybeacon. Then get the name of
# the form that was passed in. Process that form and write to 
# an output file...
#
# Check to see if any "companion" data files which can be changed
# manually or on-the-fly, or by another program. <beacon-type>.var
#
# If "silent" screen output, use myformer.plx & > /dev/null and
# remove the "-w" at the top of this Perl script...
#
# You may edit or change any .var file on-the-fly. Use this command
# echo "<beacon_name> <device>" > mybeacon to feed the server. Then 
# from the JNOS console give that device a kick. ax25 bc <device>
# --------------------------------------------------------------------

#----- Data Inits...
$myPath   = "";
$beacon   = "";
$loctime  = "";
$utctime  = "";
$thisform = "";
$myvars   = "";
$vars     = "";
$device   = "";
$line     = "";

#----- Default inits...
$myPath   = "/jnos/scripts";
$myPipe   = $myPath . "/mybeacon";
$myBeacs  = $myPath . "/beacons/";


#===== Main

#----- Endless loop...
OUTER: while ( 1 )
{
#----- Open a pipe read here and wait...
        open(MYPIPE, "< $myPipe");

        $beacon = "";
        $device = "";
        $line   = "";

#----- Should wait here for valid data...
        while (defined($line = <MYPIPE>)) {last;}
        chomp($line);
        $line =~ tr/  / /;
        ($beacon, $device) = split(/ /, $line);

#----- Release the pipe here...
        close(MYPIPE);

#----- Test for a "forced" exit 
        if ( $line eq "quit" )
        {
                last OUTER;
	}

#----- Make this an upper case format name...
        $ucformat = $beacon;
        $ucformat =~ tr/[a-z]/[A-Z]/;

#----- File I/O ops, read in data from format form
        open(BEACON, "< $myBeacs$beacon");

#----- Begin to build the format
        $thisform = "";
        $thisform = "format " . $ucformat . " =\n";

#----- Read in the lines... create one big line
        while (defined($buffer = <BEACON>))
        {
                $thisform .= $buffer;
        }
        close(BEACON);

#----- Requires a "dot" at the end of string...
        $thisform .= ".";

#----- Now eval this for any vars...
        eval $thisform;

#----- Give the "handle" a name...
        *DATAFORM = $ucformat;

#----- NOTE: Open the form for output... 
#-----       /jnos/scripts/beacons/dataform
        open(DATAFORM, "> $myPath/beacons/dataform");

#----- Load a few default Common Global vars...
        chomp($loctime   = `/bin/date +%H:%M:%S`);
        chomp($utctime   = `/bin/date -u +%H:%M:%S`);

#----- Load companion variables if they exist, a .var file ...
        $vars     = $beacon . ".var";
        $myBPath  = "$myBeacs$vars";

        if ( open(VARDATA, "< $myBPath") )
        {
                while (defined($line = <VARDATA>))
                {
                        chomp($line);
                        $myvars .= $line;
                }

                close(VARDATA);
                eval $myvars;
        }

#----- Write the format block ...
        write (DATAFORM);

#----- Close the file
        close(DATAFORM);

#----- Now build the JNOS do_beacon script,
#-----  "dataform" is the repository for all the formats above, etc...
        system("/jnos/scripts/build_beacon $device dataform");
}

#----- "Offical" exit on quit
exit;

#----- End of myformer.plx

My location for this code is in /jnos/scripts. You could locate it anywhere as long as you use full path names for the input and output files. You also need to create a named pipe. I called mine mybeacon, but you may call it any name that makes sense to you, just be sure the Perl code agrees with any name changes you make. Here is how to create the pipe, and it should be located in /jnos/scripts, or where ever you decide to locate the code. (In other words, all these items should be together... )

  • mkfifo mybeacon


This pipe now serves as the input to the server. It should be created with root ownership granting write permission to root only.

To start up the server, after logging in as root, use this command from the prompt:

  • myformer.plx > /dev/null &


The /dev/null will catch many of the "warnings" coming from Perl or from the system. You may also remove the "-w" from the topmost line in the script after you see it is working OK. (Sometimes, Perl likes to "comment" on the activities of eval.)

To "talk to" the server from the prompt, use this line:

  • echo "quit" > mybeacon


Where mybeacon is the named pipe which is the input for the Perl code, myformer.plx. This command will stop the server. To pass a processing command into the (pipe) server input, use:

  • echo "infoform hf" > mybeacon


This tells the server to get the format and variable files for infoform which will be set up on the hf device. Note, too, that all output data is written to a file /jnos/scripts/beacons/dataform. This is essentially the output "buffer." The final step is a call to build_beacon which takes the content of dataform as its input and continues to generate the JNOS script file, do_beacon. That script will in turn be called by one of the AT timer routines, loading the ifconfig table for device hf, and finally will be sent out as the next beacon message...

Remember, you may pass in the name of any format form that you have created that resides in /jnos/scripts/beacons at any time. This affords great flexibility. If you interrupt the regular broadcasts, or interject with a special alert, it will return to the normal cycle according to the schedule that you have set up in a broadcast table.

Automating the Feed to myformer.plx

As seen above one way to "talk to" the myformer.plx server is to echo commands in from the keyboard. But eminently more useful is the ability to feed a command line from another program or script. This is where the shell script do_sched comes into play. This script reads a table for the broadcast schedule and then sends a command line to the server, just as if it had been typed in by hand. Here is the code:

Shell Script: do_sched

#! /bin/sh
# do_sched
# KA1FSB/kbn
# 08-28-04, 08-30-04 (bambi)
# 09-02-04
#
# ---------------------------------------------------------------------
# Lookup in sched table what is to be run at what time and
# compare to time now. Then send down the pipe the correct commands
# to the server which are in the table...
#
# First, check to see if pipe exists. And check if server is running.
#
# Should be run only once for each call from cron. 
# Can accept command line argument for the lookup table from cron
# ---------------------------------------------------------------------

#----- Inits...
line=""
Minutes=""
tblMins=""
myPipe=""
myProg=""
myForm=""
myTable=""
device=""
ISUP=""

#----- Data Inits...
myPath="/jnos/scripts/"

#----- Defaults or pass in...
if [ "$1" ]
then
        myTable="$1"
else
        myTable="sched.tbl"
fi

#===== Main

#----- Get the minutes from the system clock...
Minutes=`date +%M`

#----- Main process loop, read table file for data...
#----- Break out if table minutes greater/equal than system time minutes
while [ 1 ]
do
        read tblMins myForm myProg myPipe device || break
        test `echo $tblMins | grep ^#` && continue
	
        if [ $tblMins -ge $Minutes ]
        then
# echo "Sending this to $myPipe: $myForm $myProg for $device"
                break
        fi

done < ${myPath}${myTable}

#----- Is pipe there ?
if [ ! -e "${myPath}${myPipe}" ] && [ ! -p "${myPath}${myPipe}" ]
then
        echo "The file $myPipe is not a pipe! Server needs this pipe"
        exit
fi

#----- Is program running?
ISUP=`/bin/ps ax | /usr/bin/grep ${myProg} | /usr/bin/grep -v grep`

if [ ! "${ISUP}" ]
then
        echo "The program $myProg is not running now ... exiting"
        exit
fi

#----- Then send command line args to server on this pipe only if
#-----  all of the above conditions are true ...
echo "$myForm $device" > ${myPath}${myPipe}

exit

#----- End of do_sched
Again, this piece of code needs to be in the same directory as all the others mentioned here. I use /jnos/scripts, but as long as you are consistent, you may locate it anywhere you like.

Aside from looking up data in a table, this script checks to see if a named pipe exists and if its receiving server is up and running. There is nothing worse than trying to send to a non-existent pipe or server. So, it won't try unless it finds everything is a "go." A little bit of defensive programming... Here is the cron line that you need to enter to coordinate this script with the broadcast schedule. (Use crontab -e to enter this line.)

  • 18,38,58 */1 * * * /jnos/scripts/do_sched sched.tbl 1>/dev/null 2>/dev/null


These times are set for a 20 minute cycle through the hour. (The shell script will be run at 18, 38, and 58 minutes after every hour.) To find out more about automating and synchronizing beacons: please see, Automating a Beacon and Synchronzing a Beacon for details.

The Schedule Table: sched.tbl

#Time   Form            Server          Pipe            device
20      shortform       myformer.plx    mybeacon        hf
40      infoform        myformer.plx    mybeacon        hf
60      longform        myformer.plx    mybeacon        hf

The table lists all the needed data to automatically construct a wide variety of beacons! Even though this setup might seem like a lot of "overhead," it allows for great flexibility. The code do_sched may take a different table name as its argument, and the detailed data in any given table, may refer to a wide range of options, i.e., named pipes, format forms, and servers that may all be running. These methods are quite re-useable...

And this table can be edited on-the-fly as well. If a line begins with the pound sign "#", it will not be seen by the shell script. This makes it easy to have alternate lines which can be switched in quickly with just a few key strokes.

The Schedule Table: sched.tbl with alternate lines commented in/out

#Time   Form            Server          Pipe            device
20      shortform       myformer.plx    mybeacon        hf
40      infoform        myformer.plx    mybeacon        hf
#40     shortform       myformer.plx    mybeacon        hf
60      longform        myformer.plx    mybeacon        hf
#60     shortform       myformer.plx    mybeacon        hf

I often set all the lines to broadcast the shortform unless there is something worth sending out as a public announcement, like a severe storm warning, or a unusually "nice" day for my part of the world. :)

Interjecting an Alert or Emergency Beacon

Suppose you have a beacon message that you want to broadcast immediately. And further suppose that this message has been completed, resides in /jnos/scripts/beacons, and is ready to go. There are three (3) steps/commands to accomplish this transmission:

  1. From Linux:  echo "<beacon_name> <device>" > mybeacon
  2. From JNOS: source /jnos/scripts/do_beacon
  3. From JNOS: ax25 bc <device>


The first step should be taken from /jnos/scripts or wherever you have located all the server support code. And since the automated part of the server is still in force, you might want to be sure you are not conflicting with a previously scheduled broadcast. (If you are quick, you can probably send out the alert in less than a minute.) So the output of your alert message will appear in /jnos/scripts/do_beacon almost immediately. (You can check to be sure ... )

Step two requires that you change to the JNOS console, either logging in as sysop or switching sessions, and run the JNOS script do_beacon. This loads the ifconfig table with the new message.

The last step "fires" the beacon out onto the net. Since this is an "interjection," all regularly scheduled broadcasts will resume as usual.

Caveats

As always, you copy, use, and modify this code at your own risk. As we all know, code running on one system may not always adapt well to other systems or packages. So, for a start, please be sure to read as much as you can "tolerate" in the NOS-ABS index page. These "utilities" have been running fine here for about two (2) months now with no "detectable" problems. That doesn't mean there aren't any. The code is in a perpetual prototypical state and is easily modifiable by you, the user, net sysop, or programmer. (That is the good part!)

Concluding Observations ...

So here is a summary list of the required components for a NOS-ABS Beacon Server:

  • A Named Pipe: mybeacon
  • A Shell Script: do_sched
  • A Cron entry for do_sched
  • A Perl Server: myformer.plx
  • A Perl Script: build_beacon
  • A Schedule Table: sched.tbl
  • A Directory under /jnos/scripts: /beacons
  • A Selection of Beacon Text Messages
  • A JNOS Script such as: do_beacon built by build_beacon


By coordinating these code and system "parts," you can gain complete mastery of the JNOS broadcast system! You can send out nearly any kind of information you wish, in any format, and at any time. If you are a programmer, or have been a Linux administrator for some time, take a look at these ideas and build your own system around the concepts. These programs all work fine, but the design I chose is one that can be extensively modified to fit your network. Have fun and keep experimenting with the "NOS-ABS utilities!" You never know what you might come up with!

For more background and supplemental information, please see Automating a Beacon for the comprehensive treatment of this topic.


(Courtesy KBNorton Computer Services)