Sunday, March 24, 2013

Fun with Embedded HTTP Servers

I have been distracted for the past week by an embedded HTTP server. I am currently taking a very exciting course entitled Internet Embedded Systems taught by Senior Embedded Software Designer Robert Laswick. The end goal of the course is to achieve web based control and status of hardware.
Olimex MOD-IO with ENC28J60 Module
After I completed the core objective of the course I decided to run absolutely wild with the concept. I created some Makefile targets that minify, gzip and convert web resources (HTML, JavaScript, CSS) into C header files which I can then serve up to the browser.

Overview
This entire project is hosted on the Olimex MOD-IO development board with the famous ENC28J60 Ethernet controller attached. Briefly, the ENC28J60 Ethernet controller is a very cost effective way to Ethernet enable low-cost, low-power 8-bit microcontrollers using the SPI bus.

The course made use of the TuxGraphics TCP/IP stack which is surprisingly easy to bring online. The ATmega16 CPU on this development board is not natively supported by the stack but only a few simple modifications are required to make it compile and load without warning. I was up and running in under an hour.

The Interface
One severe limitation of this hardware is the 1kB of RAM. This limits the response size to approximately 700 bytes. I could have broken up my responses into multiple parts but decided to keep all responses under the buffer size.

The Relay Control Homepage
I have been doing web development since I was in elementary school. This fusion of hardware and high-level web development has been a lot of fun. The relay control homepage turned out great.

Here is the Makefile target that I use to minify, gzip and convert to a C header file the stylesheet used for this project. You can yell at me for using sed twice, I was in a hurry!

%.css.h: %.css
    yui-compressor --type css $^ > $^.min
    gzip -c $^.min > $^.gz
    xxd -i $^.gz | sed -e 's/.\[\]\ =/\[\]\ PROGMEM\ =/g' | sed -e 's/unsigned/const/g' > $@
    rm -f $^.gz $^.min

I have one of these for JavaScript and HTML (varies slightly) as well.

Uptime Counter
I have implemented 3 basic features. The first is the System Uptime counter. This is a simple struct residing on the microcontroller that keeps track of days, hours, minutes and seconds.

typedef struct {
    uint16_t days;
    uint8_t hours;
    uint8_t minutes;
    uint8_t seconds;
    uint16_t millis;
} uptime_t;

I increment uptime once per millisecond in a timer compare match ISR. It would have been faster to just keep track of uptime in a uint64_t and then convert this into days, hours, minutes and seconds when required, but I like this approach.

void __attribute__((signal)) TIMER0_COMP_vect(void) {
    if(++uptime.millis == 1000) {
        uptime.millis = 0;
       
        if(++uptime.seconds == 60) {
            uptime.seconds = 0;
           
            if(++uptime.minutes == 60) {
                uptime.minutes = 0;
               
                if(++uptime.hours == 24) {
                    uptime.hours = 0;
                    uptime.days++;
                }
            }
        }
    }
}


Uptime is served to the browser using JSON. This is fetched in JavaScript using an AJAX request. This results in a very efficient use of system resources. This system can handle 150+ hits per second on the dynamically generated JSON pages.
{"d":0, "h":0, "m":0, "s":9, "ms":754} 
Total HTTP Requests
This is a simple one. It simply counts the total number of HTTP requests. This is also served using JSON.
{"count": 35}

The "AVR Web Server" Section
Relay Control
The next step was to control some hardware. I decided to parse out a URL with the format /rly$num$state where $num is a number between 0 and 3 and $state is either 'on' or 'off'. If the microcontroller receives this command, it will turn on or off the selected relay.

In addition to this basic relay control, I have implemented HTTP authentication. When a relay command is sent, the device is also expecting the authentication headers. If no authentication headers are sent, the browser will receive a 401 response.

Authentication Required
Relay Status
I also have a relay status feature. Relay status is served using yet another JSON request.

Hardware with Programmer/Debugger Attached
Setup Overview
Conclusion
The number of possible use cases for hardware like this is unbounded. I may end up using it to control my homebrew fume extraction system, but that is a another blog for another day.

If you have any questions or comments, leave them below. Thanks for reading!  

15 comments:

  1. You could use only one sed:
    sed -e 's/xxx/yyy/g' -e 's/aaa/bbb/g'

    Nice work! I look at this and see a home automation system.

    ReplyDelete
    Replies
    1. Thanks for the tip!

      I plan to automate my fume extraction system this summer.

      Delete
  2. Great work!
    My graduation project is to realise a web server on an STM32F4 board, I am going eventually to use the LwIP tcp/ip.
    I'd like to ask you the difference between your stack and the LwIP one.
    Thanks.

    ReplyDelete
    Replies
    1. I have not personally used the LwIP stack but a quick read of the features shows that LwIP is much better but requires more system resources.

      I believe the LwIP stack is portable across many processors but the TuxGraphics stack is AVR specific.

      From the LwIP Website: "This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM."

      Even the biggest of AVRs don't have those kinds of resources. I am unsure if the TuxGraphics stack is compatible with the XMega line of AVR processors. I imagine with some tweaks it could be made to work.

      Delete
    2. FYI. An STM32F4 processor and the LWIP stack with an ENC28J60 is exactly what is used on the NetduinoPlus 2.

      Delete
  3. This is a great direction to be studying - network / machine interfaces or "virtualization" as some people seem to want to call it is going to be in increasing demand in some areas of the world with aging population demographics. A decline in available labor means more automation will be needed. But, on a more positive note, there is also the idea that more young people can be learning this technology to forge niche businesses for themselves in economically depressed areas that could be improved through strategic automation. Something to think about.

    Btw I recommend taking some business classes before you graduate if you haven't already. Making good use of this knowledge will be greatly benefited from some ability to capitalize on what you are learning. You've got a bright future ahead. :-D

    ReplyDelete
  4. Would html file be even smaller if you embedded svg directly (svg tag with a path)?

    ReplyDelete
    Replies
    1. The SVG file uncompressed is around 700 bytes. When gzipped, the svg is around 380 bytes. As far as I know, gzipped base64 encoded images are only supported in very few browsers.

      I have leveraged the img tag to have the svgz be served on another HTTP request.

      Delete
  5. Can you post the sourse code please.I want to build something like this.

    ReplyDelete
    Replies
    1. Hi Manos,

      Normally I like to share the source for my projects. In this case, there really isn't much to share. I am more or less using the default web server application provided with the stack.

      You will find the TuxGraphics TCP/IP stack here: http://tuxgraphics.org/common/src2/article09051/

      I am planning to do a summer project where I automate a some 120VAC Mains lines. I will have some code to share at that point.

      Delete
    2. Ok thank you anyways,i'll give it a try.Good luck

      Delete
  6. Can you make it with mod-wifi

    ReplyDelete