gawkinet: REMCONF
3.3 REMCONF: Remote Configuration of Embedded Systems
=====================================================
Today, you often find powerful processors in embedded systems.
Dedicated network routers and controllers for all kinds of machinery are
examples of embedded systems. Processors like the Intel 80x86 or the
AMD Elan are able to run multitasking operating systems, such as XINU or
GNU/Linux in embedded PCs. These systems are small and usually do not
have a keyboard or a display. Therefore it is difficult to set up their
configuration. There are several widespread ways to set them up:
* DIP switches
* Read Only Memories such as EPROMs
* Serial lines or some kind of keyboard
* Network connections via 'telnet' or SNMP
* HTTP connections with HTML GUIs
In this node, we look at a solution that uses HTTP connections to
control variables of an embedded system that are stored in a file.
Since embedded systems have tight limits on resources like memory, it is
difficult to employ advanced techniques such as SNMP and HTTP servers.
'gawk' fits in quite nicely with its single executable which needs just
a short script to start working. The following program stores the
variables in a file, and a concurrent process in the embedded system may
read the file. The program uses the site-independent part of the simple
web server that we developed in A Web Service with Interaction
Interacting Service. As mentioned there, all we have to do is to write
two new procedures 'SetUpServer()' and 'HandleGET()':
function SetUpServer() {
TopHeader = "<HTML><title>Remote Configuration</title>"
TopDoc = "<BODY>\
<h2>Please choose one of the following actions:</h2>\
<UL>\
<LI><A HREF=" MyPrefix "/AboutServer>About this server</A></LI>\
<LI><A HREF=" MyPrefix "/ReadConfig>Read Configuration</A></LI>\
<LI><A HREF=" MyPrefix "/CheckConfig>Check Configuration</A></LI>\
<LI><A HREF=" MyPrefix "/ChangeConfig>Change Configuration</A></LI>\
<LI><A HREF=" MyPrefix "/SaveConfig>Save Configuration</A></LI>\
</UL>"
TopFooter = "</BODY></HTML>"
if (ConfigFile == "") ConfigFile = "config.asc"
}
The function 'SetUpServer()' initializes the top level HTML texts as
usual. It also initializes the name of the file that contains the
configuration parameters and their values. In case the user supplies a
name from the command line, that name is used. The file is expected to
contain one parameter per line, with the name of the parameter in column
one and the value in column two.
The function 'HandleGET()' reflects the structure of the menu tree as
usual. The first menu choice tells the user what this is all about.
The second choice reads the configuration file line by line and stores
the parameters and their values. Notice that the record separator for
this file is '"\n"', in contrast to the record separator for HTTP. The
third menu choice builds an HTML table to show the contents of the
configuration file just read. The fourth choice does the real work of
changing parameters, and the last one just saves the configuration into
a file:
function HandleGET() {
if(MENU[2] == "AboutServer") {
Document = "This is a GUI for remote configuration of an\
embedded system. It is is implemented as one GAWK script."
} else if (MENU[2] == "ReadConfig") {
RS = "\n"
while ((getline < ConfigFile) > 0)
config[$1] = $2;
close(ConfigFile)
RS = "\r\n"
Document = "Configuration has been read."
} else if (MENU[2] == "CheckConfig") {
Document = "<TABLE BORDER=1 CELLPADDING=5>"
for (i in config)
Document = Document "<TR><TD>" i "</TD>" \
"<TD>" config[i] "</TD></TR>"
Document = Document "</TABLE>"
} else if (MENU[2] == "ChangeConfig") {
if ("Param" in GETARG) { # any parameter to set?
if (GETARG["Param"] in config) { # is parameter valid?
config[GETARG["Param"]] = GETARG["Value"]
Document = (GETARG["Param"] " = " GETARG["Value"] ".")
} else {
Document = "Parameter <b>" GETARG["Param"] "</b> is invalid."
}
} else {
Document = "<FORM method=GET><h4>Change one parameter</h4>\
<TABLE BORDER CELLPADDING=5>\
<TR><TD>Parameter</TD><TD>Value</TD></TR>\
<TR><TD><input type=text name=Param value=\"\" size=20></TD>\
<TD><input type=text name=Value value=\"\" size=40></TD>\
</TR></TABLE><input type=submit value=\"Set\"></FORM>"
}
} else if (MENU[2] == "SaveConfig") {
for (i in config)
printf("%s %s\n", i, config[i]) > ConfigFile
close(ConfigFile)
Document = "Configuration has been saved."
}
}
We could also view the configuration file as a database. From this
point of view, the previous program acts like a primitive database
server. Real SQL database systems also make a service available by
providing a TCP port that clients can connect to. But the application
level protocols they use are usually proprietary and also change from
time to time. This is also true for the protocol that MiniSQL uses.