For the latest information on how COVID-19 is impacting our business, please see our updates page.

Creating Dynamic Web Content with NNDK 3.x

NetBurner Dynamic Web Content
Share on facebook
Share on reddit
Share on twitter
Share on linkedin
Share on email
Share on print

Introduction

Having the ability to turn your embedded system into a small web server provides a substantial advantage when it comes to relaying information from your device to the outside world in a human accessible format. However, that advantage becomes next to useless if the content served is unable to change to reflect the data the embedded system is managing. Fortunately, all network-enabled NetBurner devices have the ability to serve and handle dynamic web content. This capability has gotten even better with our latest tools, NNDK 3.x.

A Short HTTP Overview

Before we dig into the world of dynamic web content, let’s take a step back and look at the components involved in your typical web connection, as well as the protocol that makes it all tick. In every web connection, there are two acting parties: a web client, and a web server.

A web server can be described as a TCP server that has the ability to control access to the system’s hosted files. For the purposes of this discussion, a “file” can refer to static or dynamically generated content. At a minimum, a web server is a Hypertext Transfer Protocol (HTTP) server that understands web addresses (URLs) and the HTTP protocol. This enables a client web browser to view the hosted files. 

For example, when you typed in the URL for this article into your web browser (or clicked on a link somewhere), it requested a file from our web server using HTTP. The web server accepted the request, found the requested content, and sent it back to your web browser, again using HTTP.

The two main types of web browser interaction are referred as GET and POST:

  • A web browser issues an HTTP GET request to ask the web server to send a specific file. For example, when you go to a web site the file index.html is typically retrieved with a GET request.
  • A web browser issues an HTTP POST when it wants to send data to the web server. For example, when you fill in a web page form with your name and address and then click on submit, it uses a POST to send that to the web server.

Static Content vs Dynamic Content

Previously we mentioned that the content being served by a web server can be static or dynamic. What does that really mean, though?

Static content refers to files that are stored on the web server. When a web browser request is received for a static file, the file is sent to the web browser along with some HTTP content such as a header containing information on the file type. Also sent are any resources that the file might use, such as images. This helps the web browser determine how to display the content. Static web pages can consist of a markup language such as HTML, or programming languages such as JavaScript.

Dynamic content refers to content that, partially or in whole, is generated at the time of a request. A well know back-end (server-side) language is PHP. While large footprint server-side languages are great for large scale applications, in the embedded world, where a web server may have to run in much smaller memory environments on a single chip, a more efficient solution is required.   

Dynamic Content on a NetBurner 

The NetBurner platform can deliver both static and dynamic content. The majority of web server content will be delivered automatically with no additional programming. Web server content should be placed in a directory with the name html in your project. When you build an application, all HTML content will be processed automatically and will be available to web browser requests. This includes HTML, JavaScrpt, Java applets, images, etc.

For dynamic content, a number of options are provided, which we will describe in greater detail below: 

  • HTML tags for function callbacks
    • A CPPCALL HTML tag in an HTML page will directly call the specified function in your application. The function receives a file descriptor to the session as a parameter, and can send any type of content to it. This looks like the following: <–CPPCALL YourCppFunction –>
  • HTML tag for displaying an application variable
    • A VARIABLE HTML tag in an HTML page that will display any variable from the application. This looks like the following: <–VARIABLE YourVariable –>
  • Intercepting a web browser GET request
    • An HTML GET callback function, CallBackFunctionPageHandler, that will be called when a corresponding HTML GET request is recieved.
  • Processing a web browser POST
    • An HTML POST callback function, HtmlPostVariableListCallback, that will be called when a corresponding HTML form POST is received.

Dynamic HTML Tags

To understand the concept of the dynamic content HTML tags mentioned above, it helps to think of the web page delivery as a serial stream to the web browser: 

  • The web browser requests a web page from the web server 
  • The web server starts sending the web page as a serial stream of data 
  • When the web server detects a dynamic HTML tag (CPPCALL <name> or VARIABLE <name>), instead of sending the tag, it takes the action as directed by the tag.
  • For a CPPCALL tag, the specified function in the application is called. For example:
    void Foo(int socket, PCSTR pUrl)
    The function is provided the session socket and a pointer to the URL. Any content sent to the socket will appear to the web browser as the web page content it requested. The function can be as simple as reading the status of something in the system, or as complex as delivering HTML or JavaScript code.
  • For a VARIABLE tag, the tag is replaced with the value of the specified variable. For example, the web page could display the system seconds since boot variable.

A significant advantage of dynamic HTML tags is that they provide you with the flexibility to create most of the web page content by any means you wish. They dynamic portion is inserted where needed. That way formatting, CSS styling, images, etc. can all be done with the tools and languages you already know.

VARIABLE Tag Example

Below shows the C++ code, the HTML, and the web browser output for a very simple VARIABLE tag.

C++ Code

htmlvar.h
#ifndef HTMLVARS_H_
#define HTMLVARS_H_

#include <nbrtos.h>     // For access to TimeTick

extern int  gIntVal;
extern char gStrVal[];

#endif /*HTMLVARS_H_*/
main.cpp
#include <init.h>
#include <iosys.h>
#include <netinterface.h>
#include <fdprintf.h>

const char *AppName = "HTML Variable Tag Demo";

int  gIntVal   = 1234;
char gStrVal[] = "Hello World";

/*
 * Function called from the CPPCALL tag. Display the URL on the web page
 */
void Foo(int fd, PCSTR pUrl)
{
    fdprintf(fd, "The URL value is: %s\r\n", pUrl);
}

/*
 *  UserMain
 */
void UserMain(void *pd)
{
    init();
    StartHttp();
    WaitForActiveNetwork();

    while (1)
    {
        OSTimeDly(TICKS_PER_SECOND);
    }
}

HTML Code

<html>
    <body>
        <h1>HTML Variable Example</h1>
        <div>Number of seconds since system boot: <!--VARIABLE TimeTick/TICKS_PER_SECOND --></div>
        <div>Application integer value: <!--VARIABLE gIntVal --></div>
        <div>Application string value: <!--VARIABLE gStrVal --></div>
    </body>
</html>

Browser Output

The output from the HTML VARIABLE tag.
Output from the HTML VARIABLE Tag

CPPCALL Tag Example

Below shows the C++ code, the HTML, and the web browser output for a very simple CPPCALL tag.

C++ Code

htmlvar.h
#ifndef HTMLVARS_H_
#define HTMLVARS_H_

const char *FooWithParameters(int fd, int v);

#endif /*HTMLVARS_H_*/
main.cpp
#include <init.h>
#include <iosys.h>
#include <netinterface.h>
#include <fdprintf.h>

const char *AppName = "HTML CPPCALL Example";

/*
 * Function called from the CPPCALL tag. Display the URL on the web page
 */
void Foo(int fd, PCSTR pUrl)
{
    fdprintf(fd, "The URL value is: %s\r\n", pUrl);
}

/*
 *  UserMain
 */
void UserMain(void *pd)
{
    init();
    StartHttp();
    WaitForActiveNetwork();

    while (1)
    {
        OSTimeDly(TICKS_PER_SECOND);
    }
}

HTML Code

<html>
    <body>
        <h1>HTML CPPCALL Example</h1>
        <div><!--CPPCALL Foo --></div>
    </body>
</html>

Browser Output

Output from the HTML CPPCALL Tag

Overriding Browser HTTP GET Requests

The third method for dynamic content is to have the application override a web browser HTTP GET request. This is accomplished by creating a HTTP GET callback function and page handler. For example, to override the HTTP GET request for a web page named MyPage.html, you would register a callback function such as callbackGetMyPage():

int callbackGetMyPage(int sock, HTTP_Request &pHttpRequest) 
{ 
    // Custom application code goes here 
} 

The HTTP_Request parameter is a reference to a structure containing detailed information of the request. Next, a page handler is created named getHandlerMyPage():

CallBackFunctionPageHandler getHandlerMyPage("MyPage.html", callbackGetMyPage, tGet, 0, false);

You can override any web page or URL, whether a file of that name exists or not. In the example above, the callback function can do some pre-processing, then send a file named MyPage.html, or it can dynamically create content and send it to the web browser as MyPage.html.

This mechanism can also be used to make decisions on which file to send. Let’s say there is a default file compiled into the system named index.html, but you also wish to have files stored on an external flash drive. The callback function could look first on the flash drive and deliver that file if it exists. If it does not exist, the file stored in the application could be sent as a default/fallback.

A quick description of the page handler function parameters is given below. They are covered in greater detail in the examples, the documentation on creating a GET request handler, and the API documentation.

  • The tGet parameter tells it to process a HTTP GET request.
  • The 0 parameter specifies the access group has no password. For most web applications, this value will suffice. For more information, please see the documentation referenced above.
  • The last parameter can be referred to as “beforeFiles”. If set to false, the file system will be checked first for the existence of the web page, and if found, the file will be sent instead of executing callback function. If set to true, the callback function will always be called.

Processing HTTP POSTs 

When data is entered into a web page form, a HTTP POST is used to send that data to the web server. Since each type of form an application provides is unique, the application must implement a POST handler to process the form data.

Similar to the HTTP GET mechanism discussed previously, post handling consists of a callback function to process the form data, and an object of type HtmlPostVariableListCallback to identify the form name and assign the callback function. For example, to set the callback function for a form named MyForm you would declare the following object:

HtmlPostVariableListCallback postForm1("MyForm", callbackPostForm1);

The callback would then be defined with the following:

void callbackPostForm1(int sock, PostEvents event, const char * pName, const char * pValue) 
{ 
    // Code to process posted form data 
} 

The callback function will be called once for each data field in the POST, with the name of the field being passed in as pName, and the value of the field being passed in as pValue. For more information on the specific parameters used in the callback function, please see our document on creating a form POST handler.

When form data is posted, the callback function can process the data, then take any action you wish based on the results. It could simply store data, request specific data, report system status, control an electronic or mechanical device, etc.

Where To Go Now

With the basics of writing dynamic web content for your NetBurner based applications under your belt, you’re well on your way to creating easy-to-use and informative web interfaces for your own devices. For more information, please see our online documentation. When you dive into your own projects, be sure to take a peak at our extensive set of examples. We have over a dozen that cover exactly how to implement concepts we’ve discussed here. If you have additional questions or comments, please reach out to us as sales@netburner.com. We here to help, and love hearing how our products are being used.

Share this post

Share on facebook
Share on twitter
Share on linkedin
Share on reddit
Share on email

Subscribe to our Newsletter

Get monthly updates from our Learn Blog with the latest in IoT and Embedded technology news, trends, tutorial and best practices. Or just opt in for product change notifications.

Leave a Reply

Your email address will not be published. Required fields are marked *

Click to access the login or register cheese