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!  

No comments :

Post a Comment

Note: Only a member of this blog may post a comment.