circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

Issue 107 June 1999
A Web-Based Chart Recorder


SOFTWARE FUNCTIONALITY

The system software only has to perform two functions—gathering 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 2Here’s 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, there’s nothing special about the document section of the URL. You’re 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 1—A 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 it’s 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 user’s 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 user’s 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 user’s 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].
Here’s 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.