Webserver dynamic pages

From openPicus Wiki
Jump to: navigation, search

Contents

What you are going to learn

This tutorial will walk you through the Web Server more advanced capabilities especially demonstrating dynamic two-way interaction. Ideally you should have completed the first tutorial Webserver Simple Usage to better understand the basics involved in the present article.


Introduction to the Web Server

Ours Wi-Fi and Ethernet modules provide web service functionalities through the TCP/IP stack and a light Web Server. The Web Server is a collection of libraries concurring to enable the Flyport to serve web pages and dynamic content in a way similar to a real webserver. Remember the Flyport is an embedded device so it is not meant to replace a full-fledged webserver like apache. Things will go smoother if there is any previous knowledge of topics like networks, html and such.. Nevertheless the tutorial is structured with very few assumptions, detailing most aspects and functionalities so that it is possible to follow along without trouble.

Disclaimers done it’s time for some real things so let’s get going!

Growing up: autoupdate, and getting data from client to server

As we’ve seen in the previous example, getting data from the server to the client is easy enough: just place a few keywords and you can get control over what is sent to the client. Nothing prevents you from using the same method to create html code on the fly, it’s just time consuming. But you could for example put different strings pointing to different java scripts according to some other parameter.

You’re probably starting to see the power of this. But to harness this power we need information to flow bi-directionally so we will see how to automate page update.

We need a few pieces each doing part of the work. First of all a smart script by Microchip which provides some service functions and the main polling loop which need we not delve into (it’s called Mchp.js and is part of the libraries, you will find it if you create a Webserver Example project).

Next we focus our attention on the parts we need to bother about: a dynamic module, some kind of code that gets executed client side, and an xml.

Introducting the XML syntax

Let’s start with the XML first, we call it status.xml and it has this syntax:

<response>
<led0>~led(0)~</led0>
<led1>~led(1)~</led1>
<led2>~led(2)~</led2>
<led3>~led(3)~</led3>
<led4>~led(4)~</led4>
<var1>~var1~</var1>
<var2>~var2~</var2>
</response>

You can see we can squeeze both vectors and simple variables in there. It’s exactly the same as putting ~something~ into an html file: whenever the server gets a request for a file, it starts streaming it and when it encounters ~something~ it asks the code what it has to do. We will have a detailed look at vector variables in the next step of the tutorial, for now we concentrate on automating the reload.

So let’s write our status.xml this way:

<response>
<keyword>~keyword~</keyword>
</response>

The index.html

then open again the index.html, and change it this way:

<html>
<head>
<title>Flyport online webserver</title>
<script type="text/javascript" src="scripts/mchp.js"></script>
</head>
<body>
<div align="center">
If this page loads you’re good to go.
 
<br><p id="keyword">placeholder</p>
</div>
<script type="text/javascript">
<!--
// Parses the xmlResponse from status.xml and updates the status box
function updateStatus(xmlData) {
   document.getElementById('keyword').innerHTML = getXMLValue(xmlData, 'keyword');
}
setTimeout("newAJAXCommand('status.xml', updateStatus, true)",500);
//-->
</script>
</body>
</html>

Here there are a few things going on so let’s stop a moment and digest.

We are including a script in the header, that’s because this scripts need be executed at first to start an automatic loop that periodically reloads the xml. It’s like a service we start at the beginning and then runs in the background doing things for us.

This is the workhorse that does the dirty work whenever we want to refresh the page.

The next modification is in the body

<p id="keyword">placeholder</p>

This is needed because this time we are going to use javascript to modify the value rather than the web server itself like in the previous example, that’s to say the content modification will not be done by the server when streaming, but rather by the client upon execution of the script. We got rid of the double tilde and instead used a tag to delimit where the modification should occur and thus allow the script to manipulate the object.

So when we use javascript to modify the object whose id is keyword, whatever is contained in that object (placeholder in our case) will get replaced by the content of the variable we passed from the server.

The last step is understanding the script that does the replacing.

Conceptual description

Let’s have a birdseye look at things with a flowchart first:

Tutorial 02 flowchart.jpeg

This is a simple extension of the one shown in the previous example.

You can see that after the usual fetching and parsing, a resource is served this time containing a script. The browser loads this scripts and starts executing it in a loop.

This loop contains fetching instructions, so each time the loop is executed, a fetch&parse operation is carried out by the Flyport just as in the first instance.

It’s this that gives the dynamically updated content.

So now that we’ve got a good look at how things work in theory, it’s time to see how they work in practice by analyzing the script itself.

First a function is defined, called updateStatus taking some data as parameter. The function then looks up for an object in the page called keyword and substitutes its html content with the content of the corresponding keyword object contained in the xml data.

Then setTimeout assigns a recurring event to the javascript engine, timed at 125ms, indicating that each time the function newAJAXCommand shall be executed, and its result shall be given to updateStatus.

So what happens is that the javascript engine will set up a timer so that it will call newAJAXCommand 8 times a second giving status.xml as the url to fetch, updateStatus as container and telling it the call will be repeated.

If everything went correctly you should see the number of reloads updating automatically a few times a second.

This has achieved automatic content updating, and it wasn’t that complex right?

Mastering JScript may be hard, but to do this kind of things you need not become a professional web-dev.

Revised index.html

So we’ve seen how to automate content delivery, but up to now we’ve only seen how data can be shuffled from the Flyport to a client, it’s now time to add some client->server fanciness: we will add a button to toggle a led, so let’s go illuminate our Flyports! Back to the index.html add the button code below the keyword block

<br><p id="keyword">a</p>
</div>
<div style="text-align:center;">
<button type="button" onclick="newAJAXCommand('leds.cgi?led');">Toggle Led</button>
</div>
<script type="text/javascript">

What do we have here? Again we see the newAJAXCommand of before as it’s the function doing most of the work, but this time it’s different: we’re passing a string and apparently a file name. Why?

A little digression on the GET method. The GET method appends parameters over the url, meaning it uses the GET command (which is used to get anything from a web server, from pages to images and scripts) by way of giving a custom URL to the server as if the client were asking some strange resource. So in our example we’re doing this http://192.168.1.2/leds.cgi?led. What is important to understand is that the entire url, save for the device’s IP, is passed to the code. So the developer can do whatever he/she wants with that. In our case we are going to get leds.cgi first and then, if we ask for the next part, we are going to get led. This allows for some serious control power.

CGI files are just excuses, they aren’t really necessary. But having different resources can help separate different variables. For example leds with led.cgi, buttons with button.cgi and so forth. Since you are effectively parsing the entire url, it’s just to keep the code a little cleaner, so that if you have vectors you can have them inside a sort of container rather than having every possible option in the same if. Just a tidy habit and as you get better at using this feature, you can well choose to do some pretty powerful thing by abolishing some stupid habit ;)

Back to our example, we were saying we call the ajax and use it to ask for a file. This is because by exploiting a request, we can have parameters piggybacking on the request and effectively act as SET instructions.

So we put the command in the html, now we have to deal with the rest. First of all we have to create leds.cgi like this:

Success! ~led(0)~

It’s just a dummy, the Success! is just a CGI convention while the ~led(0)~ is more important: it doesn’t really matter what we put here, as long as it’s a recognizable dynamic variable (double tilde, remember?). This is because unless the object is dynamic, it would be static and hence would end up being served by the browser’s cache instead of being reloaded ruining all our nice system.

Should you compile the project now, with the new leds.cgi, the compiler would rightfully complain: we have added a dynamic variable, so we have to also add the correct HTTPPrint function. As before, a CGI is a file like any other (excluding images) so when it’s served by the Web Server, it is parsed and if a dynamic variable is found, the code wants a callback to handle that variable.

The Flyport code

So we are using a standard behaviour to do something else entirely: we could even write ~keyword~ in there and it would still work. You have to understand that we are using a file, hosted on the server, as a means to SEND something to the server itself rather than to get something. So the server sees the file and behaves like with all the other files, observing there is some dynamic content and requiring code to deal with the dynamic variable. But we are never going to actually request and display this file. We use an already used dynamic variable to avoid putting in the new code, or we put an empty HTTPPrint_led() function in HTTPApp.c, either one is a good solution.

At this point index.html has been modified, leds.cgi has been written, but the code to handle the request is still missing. This code goes into HTTPApp.c in this function:

HTTP_IO_RESULT HTTPExecuteGet(void)
{
   return HTTP_IO_DONE;
}

This callback gets called whenever the GET method is used. As we said before we will get the whole url, so we are going to get leds.cgi AND led, “and” meaning we are able to get the two as two separate parameters iteratively fetching pieces of the url from the internal parser which will get rid of escape characters for us (like ? or =).

Let’s now get a look at the code:

HTTP_IO_RESULT HTTPExecuteGet(void)
{
   BYTE filename[20];
   MPFSGetFilename(curHTTP.file, filename, 20);
   if(!memcmp(filename, "leds.cgi", 8))
   {
       IOPut(p19, toggle);
   }    
   return HTTP_IO_DONE;
}

We assign storage for a filename variable, then proceed to store filename detected in the url to this variable.

Then we compare the stored filename with what we expect it to be, if the comparison is successful, we toggle the led.

Working demonstration

So why not compile and run this code? If everything went fine you should see something like this:

Tutorial 02 browser.png

And be able to toggle the led with the button.

As you can see it’s still pretty easy to have the Flyport react to input from the web client, and we are going to show a lot more powerful things in the next step of these tutorials.

Source Code

Source Code Zip

In the zip file you'll find:

  • taskFlyport.c
  • HTTPApp.c
  • Web pages\index.htm
  • Web pages\leds.cgi
  • Web pages\status.xml
  • Web pages\scripts\mchp.js
Personal tools
Namespaces

Variants
Actions
START HERE
DEVELOPMENT
HARDWARE INFO
RESOURCES
PHASED OUT
Toolbox