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