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