Issue 107 June 1999
A Web-Based Chart Recorder
SOFTWARE
FUNCTIONALITY
The
system software only has to perform two functionsgathering
and storing the data, and presenting the data as a web
page.
The
data gathering is done with the simple task code shown
in Listing 1. It waits 1 s, sends a read request to
the DVM, and stores the response in a large circular
buffer. The values are stored as simple integers.
Most
of the software work went into the user interface and
display code. The user interface consists of the web
page shown in Photo 2. The page is an HTML form with
an embedded image.
| Listing
1This code gathers samples from
the DVM and stores them in a circular buffer. It
also detects errors in the DVM connectivity and
settings. |
|

(Click
here to enlarge)
|
Photo
2Heres a web-browser view of
the web chart recorder. This particular graph
shows a plot of the temperature outside my house
in New Hampshire. |
This
form allows the user to set the extent of the graph
and control the size of the embedded image. The form
was originally laid out and tested as an HTML file
on the PC.
Because
multiple users may want to display different views
of the same data, I wanted to store display information
for each user. The most logical way to do this is
to store the page settings in the URL used to access
the web page. In an embedded environment, theres
nothing special about the document section of the
URL. Youre free to encode whatever you want
in that name.
When
the web page is first accessed, it assigns default
values for the display limits and graph sizes. When
a user changes these settings, the choices are encoded
in the new URL. Table 1 shows the URL used in this
application and how it is encoded.
Table
1A URL like http://10.1.1.95/INDEX.HTM?
S0000000AFFFFFFF1FFFF23B000000000 has a number
of data fields.
|
All
of the numerical values are encoded in eight hex digits
and all times are in seconds. Using this scheme to
store settings in the URL enables multiple users to
save different display formats by bookmarking the
page.
Photo
2 shows a plot of temperature outside my house in
New Hampshire. Putting a simple web page on the embedded
server is trivial; this page was a little more complex.
This
page has to parse the URL and fill in the proper values
in the form elements, reference the proper embedded
image to display the graph that the user wants, allow
changes to the settings, and render the embedded GIF.
Filling
in the proper values is quite straightforward. The
Netburner system enables you to embed a specially
formatted comment in the HTML page wherever you want
to embed dynamic content. A dynamic snippet of this
HTML code is:
<INPUT
TYPE="text" NAME="MaxD" VALUE="<!--FUNCTIONCALL
DoMaxD -->" SIZE=5>
Whenever
this code is encountered in a web page, it causes the
web server to call the C function DoMaxD. The actual
web page used in this example has seven of these function
calls, shown in Listing 2.
| Listing
2These data-rendering function
calls are selected from comments in the HTML code.
They are used to render dynamic values in the
web page. |
DoMaxD
has to fill in the current value of the maximum display
on the chart, so it calls a function to extract the
GraphData and SizeData structures from the URL. Then
its just a simple matter of displaying the proper
value (shown in Listing 3) and referencing the proper
embedded image to display the graph the user wants.
To display the page, the system downloads the HTML page
and the embedded image.
| Listing
3The DoMaxD function is called
when the HTML code contains a comment of the form.
<!--FUNCTIONCALL DoMaxD-->. This mechanism
is used to put dynamic content into an otherwise
static web page. |
Both
the page and the graph need to know the value of the
users display settings (encoded in the URL). So,
the seventh function in the list, GetImageKey (see Listing
4), is a little different. It takes the URL value used
to render the HTML page and adds this URL to the end
of the image URL so that the GIF image rendered on the
form is the proper image.
The
HTML image specification for the graph is <IMG SRC
="IMAGE.GIF <!--FUNCTIONCALL GetImageKey -->"
>. When the user wants to change any of the settings,
they press one of the buttons, which causes the HTML
browser to generate a post request. This request passes
the values of all the inputs on the form to the web
server. This form encodes the variables shown in Table
2 and sends them to the web server.
This
process is done in the DoGraphPost function. After processing
all of the form elements, DoGraphPost constructs a new
URL that represents the users selections and redirects
the browser to reload that URL. This code is shown in
Listing 5.
| Table
2The variables encoded in the
form response are used to control the display.
|
| Listing
4The GetImageKey function renders
the setting components of the URL (the part past
the "?") to the page being displayed.
It passes the URL setting to the HTML page so that
it can be sent as part of the GIF image request
that draws the graph. |
| Listing
5This code processes the variables
sent in the POST request from the web browser. It
extracts the individual control variables and uses
them to generate a new URL that reflects the new
settings. |
The
final step in the display processing is the generation
of the GIF image that displays the data. When the browser
loads the main page and its embedded IMG tag, the browser
parses this IMG tag and generates a separate request
to get the GIF file. The server parses the URL and creates
a GIF image that is sent to the users browser
over the network connection.
Before
I can discuss the graph drawing-code, I need to tell
you about building a GIF-generation library. There are
a number of packages available that programmatically
render GIF images, but most of them have some problems
for embedded work. I chose to adapt the library GD because
source was readily available, and it contained a run-length
compressor that avoids the Unisys patent [5].
Heres
a brief update on the patent issue. The normal GIF image
is compressed using the LZW compression algorithm. Many
years after CompuServe promoted the GIF format as the
de facto graphics exchange format, Unisys figured out
that they held the patent on the underlying compression.
As a result, people are searching for ways to circumvent
this patent.
The
technically correct solution is to use the new patent-free
graphics standard, PNG. Unfortunately, not all older
browsers support it. The additional problem is that
it has a much bigger code impact in an embedded environment.
I
modified the GD system in several steps. First, I removed
everything except the GIF compressor and then encapsulated
the global statics in a C++ class.
Next,
I added some general-purpose line-drawing routines from
my toolbox. I then compressed the large GD fonts and
wrote some font-rendering routines to use the new format.
The
result is a simple GIF generation class with the public
interface (see Listing 6). This class is simple, but
it was sufficient to create the graphs for this project.
| Listing
6Here is the interface for the
GIF-generation class. This class encapsulates a
small subset of the public-domain GD graphics library. |