A sample program demonstrating a small but powerful web server using the Wifly module. This uses several libraries from others, but has a custom version of the WiflyInterface library, with numerous improvement to the mbed standard library.

Dependencies:   SW_HTTPServer WiflyInterface mbed C12832 IniManager

Here's the code

But you also might want to check out the SmartBoard-WiFly project page.

Basic Web Server

  • Serves static files from the selected file system. This is a compile-time setting, and a typical configuration supports gif, jpg, jpeg, ico, png, zip, gz, tar, txt, pdf, htm, and html.
  • It is designed to be small, thereby better supporting the limited resources of an embedded environment.

Advanced Web Services

  • Serves dynamically generated pages, where your software registers for a path, and then everything to that path activates your handler. Your handler then defines the header and body response.
  • Dynamic handlers can process GET query parameters (e.g. /dyn1?sky=blue&grass=green).
  • Dynamic handlers can process POST query parameters, as delivered from submission of a form.
  • Dynamic handlers can protect a resource with user:password access.

Run-Time Configurations

  • File System Support - using either the "local" file system supported by the magic chip, or from either an SD-Card or a USB flash drive.
  • Configurable to the maximum number of dynamic handlers (minimize memory requirements).
  • Configurable to the maximum number of name=value pairs for dynamic handlers (minimize memory requirements).

Compile-Time Configurations

  • Default filename for URL ending in '/' - default is 'index.htm'.
  • Configurable buffer sizes permit minimizing RAM requirements.
  • Configurable header response information.
  • Configurable for which serial port is used to communicate to the WiFly module.
  • Improved security option - to disable telnet access.

Diagnostics

  • API to determine the largest header (to more efficiently size the buffers).
  • API to gather the run-time characteristics - header processing time and content delivery time.

Limitations / Constraints

Known Issues

These are known issues, not yet resolved.

  1. Occasionally fails to serve a page - one test will constantly reload a web page every 30 seconds. It may run for hours, or minutes, then fail to load. Behaviors then are:
    • Hit the reload button in the browser and away it goes.
    • Hit the reload and you'll see the Wifly LEDs energize from the request, but no response by the web server. It appears that the embedded code does not "accept()" the connection in the TCP Socket Server.
      • In this case, the Wifly module has gone through an internal watchdog reset and the configuration parameters are such that it does not gracefully recover. Microchip is aware of this issue, but has not solved it.

Wifly Limitations

  • Single thread - it doesn't respond to overlapping requests (e.g. an embedded image may be requested before the main page completes transfer - the request is lost and the image not shown).
  • Single client - goes along with the single thread, but it doesn't support more than one client at a time.

Smart-Wifly-WebServer

  • Dynamic memory allocation - it does use dynamic memory allocation, which would be discouraged/avoided in many embedded systems. Here it uses it in parsing a request and it releases those resources upon completion of that request. If there is no other dynamic allocation that persists beyond a transaction, it should not cause memory fragmentation. Note that with multi-threading (if this is implemented with an OS), you then have race conditions that could cause fragmentation.

Web Server

Here's the web server in action. A combination of static pages served from the file system and dynamically generated pages.

/media/uploads/WiredHome/swsvr_1.pngPart of the main demo page,
which basically has all the
specifications, configurations, and limitations.
/media/uploads/WiredHome/swsvr_2.pngA zoomed out view of the same page.
/media/uploads/WiredHome/swsvr_3.pngIt would be possible to configure
the server via the web.
/media/uploads/WiredHome/swsvr_4.pngOne of the dynamically generated pages.
This one has parsed the query parameters.
/media/uploads/WiredHome/swsvr_5.pngA simple form which has a dynamic handler on the back end.
Here it takes the value associated with "leds"
and uses that to set the 4 LEDs on the mbed module.
/media/uploads/WiredHome/swsvr_6.pngA dynamic handler can require authentication.
/media/uploads/WiredHome/swsvr_7.pngSuccess!

But I've now gone so far beyond that in the current version. Here's what this one can do:

  1. It serves static web pages from a file system. I've only tested with the local file system and an SD card, but should work for any, so long as you remember that the local file system can't read subdirectories.
  2. It can serve dynamically generated web pages. This lets you accept name=value pairs using the URL (using either a GET or POST method). It can also accept them from forms. The demo lets you control the 4 LEDs from a form.
  3. As safely as possible it retrieves your credentials to the Wi-Fi Access Point. After using them, it overwrites that ram so they can't be as easily extracted.
  4. I made a large number of changes to the Wifly driver. It had too short of a timeout and I found quite a number of optimizations for performance and robustness.
  5. I have the start on a security feature - you can configure a resource to require user credentials to access it. The browser typically provides a username and password dialog. Take care however, as it does not support a secure (https) connection, so the credentials are not as securely transferred as I would like.

Optimizations I'd like to do:

  1. speed it up - I'm running the mbed to wifly module interface at 230K, which is about the top speed w/o flow control. There are other places where some time delays remain - I have eliminated a number of them.
  2. make it non-blocking, so other work can happen.
  3. integrate it with the rtos
  4. When a web page has referenced resources (e.g. an image tag), it rarely loads the image on the first try. I think the request for the resource comes in while it is still in the WiflyInterface cleaning up from the last connection. The Wifly module supports only a single connection at a time. I worked around this with a small bit of javascript to load the images after the web page.

But all in all I think it is a good start.

Program prerequisite

Here's the link to the program, but when you open it up, note a few very important items.

  1. Port Numbers listed in the constructor match the SmartBoard Baseboard.
  2. I sped up the communication baud rate to the mbed from the default 9600. Match your terminal program accordingly.
  3. Download this zip. Place it and an unzipped copy into the mbed local file system. These are the demo files.
  4. The typical ssid and password are not shown. See below to set yours.

ssid and password

You need to create a simple text file on your mbed root folder named "config.ini". The easiest way perhaps is to create "config.txt", add the information shown below and then rename it. This will be read at startup to connect you to the network. Something quite simple, like this:

[Wifi]
ssid=your_ssid
pass=your_pass_code

The program

And the program.

Import programSmart-WiFly-WebServer

A sample program demonstrating a small but powerful web server using the Wifly module. This uses several libraries from others, but has a custom version of the WiflyInterface library, with numerous improvement to the mbed standard library.

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Mon Sep 01 20:54:51 2014 +0000
Parent:
33:41ac99847df8
Child:
36:5ca4a8b8d888
Commit message:
Updates to remove dependency on WiFly.

Changed in this revision

Credentials.cpp Show diff for this revision Revisions of this file
Credentials.h Show diff for this revision Revisions of this file
Examples/DynamicFileIn.cpp Show diff for this revision Revisions of this file
Examples/DynamicFileIn.h Show diff for this revision Revisions of this file
Examples/DynamicPages.cpp Show annotated file Show diff for this revision Revisions of this file
Examples/SecurePage.cpp Show diff for this revision Revisions of this file
Examples/SecurePage.h Show diff for this revision Revisions of this file
Examples/ServerConfig.cpp Show diff for this revision Revisions of this file
Examples/ServerConfig.h Show diff for this revision Revisions of this file
FileSystem.lib Show diff for this revision Revisions of this file
IniManager.lib Show diff for this revision Revisions of this file
MODSERIAL.lib Show diff for this revision Revisions of this file
SW_HTTPServer.lib Show annotated file Show diff for this revision Revisions of this file
Utility/Utility.h Show annotated file Show diff for this revision Revisions of this file
WiflyInterface.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- a/Credentials.cpp	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-
-#include "mbed.h"
-#include "Credentials.h"
-
-/** Right Trim whitespace from the string.
-*
-* @param p is a pointer to the string to modify.
-*/
-/** Get amount of free memory.
-*
-* @returns number of bytes of unused memory on the heap.
-*/
-// trim the trailing \r\n
-static void RTrim(char *p) {
-    while (*p >= ' ' && *p < 0x7F)
-        p++;
-    *p = '\0';
-}
-
-
-bool ReadCredentials(char * file, credentials * cr)
-{
-    FILE *fp = fopen(file, "r");
-
-    cr->ssid = (char *)malloc(SSID_SIZE);
-    cr->pass = (char *)malloc(PASS_SIZE);
-    if (fp) {
-        fgets(cr->ssid, SSID_SIZE, fp);     // Trusts that the sizes were not violated
-        fgets(cr->pass, PASS_SIZE, fp);
-        fclose(fp);
-        RTrim(cr->ssid);
-        RTrim(cr->pass);
-        return true;
-    } else {
-        return false;
-    }
-}
-
-void FreeCredentials(credentials * cr)
-{
-    // first secure them by wiping them out
-    for (int i=0; i<SSID_SIZE; i++)
-        cr->ssid[i] = '*';
-    for (int i=0; i<PASS_SIZE; i++)
-        cr->pass[i] = '*';
-    
-    // then free the memory
-    free(cr->ssid);
-    free(cr->pass);
-}
--- a/Credentials.h	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-
-#ifndef CREDENTIALS_H
-#define CREDENTIALS_H
-#include "mbed.h"
-
-/// This section helps manage the credentials. I don't like the examples
-/// that show clear text credentials, even if they are simply the
-/// access point ssid and passphrase. So, I created this to let me
-/// edit a simple file on the file system and put them in there.
-/// Marginally more secure, but at least not in the source code that
-/// I might inadvertently share with others.
-///
-typedef struct {
-    char * ssid;
-    char * pass;
-} credentials;
-
-// Size changed (from 50 for both) to comply with WiFi Specifications
-#define SSID_SIZE 30
-#define PASS_SIZE 64
-
-/** Read credentials from a file.
-*
-* This reads a file constructed for hosting the credentials needed
-* to sign on to a WiFy access point.
-*
-* @param filename of interest that hosts the credentials.
-* @param cr is the credentials structure that is populated with the credentials.
-* @returns true if it successfully read the credentials, false otherwise.
-*/
-bool ReadCredentials(char * file, credentials * cr);
-
-/** Free the credentials structure to reduce ram usage.
-* 
-* This will release the resources, but before it does so it will
-* wipe the memory, so the credentials are not left in memory.
-*
-* @param cr is the credentials structure.
-*/
-void FreeCredentials(credentials * cr);
-
-#endif // CREDENTIALS_H
\ No newline at end of file
--- a/Examples/DynamicFileIn.cpp	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,469 +0,0 @@
-/// Demonstration of dynamic page creation using the Smartware Web Server
-///
-/// Here is a sample for file upload.
-#include "SW_HTTPServer.h"
-#include "DynamicFileIn.h"
-
-#define DEBUG "File"
-#include "Utility.h"
-
-// This defines the size of the largest file you are willing to accept
-//
-#define ACCEPT_MAX_BYTES (25000)
-
-// This defines the local cache, which should be about 2 x the size of a single chunk hand-off
-// which is based on the size of an ethernet data frame (~1500 bytes). So 2 x 1500 is a good number.
-#define ETHER_CHUNK (1500)
-#define PCACHE_SIZE (3000)
-#define MAX_BOUNDARY_LEN (150)      // Seems very generous...
-static int bytesInCache;
-static char * pCache;
-static char * boundary = "";        // for pointing at the boundary marker part of multipart/form-data in pCache
-static char * fqfn = NULL;          // for the filepath/filename
-static char * contenttype = NULL;   // for "text/plain", or "image/bmp"
-static int bytesWritten;
-
-static int FileSize(const char * dir, const char * filename);
-static char _tolower(char c);
-static int _strnicmp(const char * left, const char * right, int len);
-static char * _stristr(char * pHaystack, const char * pNeedle);
-static char * _strnbin(char * pBinstack, const char *pNeedle, int len);
-
-typedef enum {
-    IDLE,
-    ACCEPTED,
-    REJECTED_TOO_LARGE
-} AcceptStatus;
-
-//
-//-----------------------------7de3ab1652086c
-//Content-Disposition: form-data; name="InFile"; filename="Len0700.txt"
-//Content-Type: text/plain
-//
-//__1 - _50 12345678901234567890123456789012345678
-//_51 - 100 12345678901234567890123456789012345678
-//101 - 150 12345678901234567890123456789012345678
-//151 - 200 12345678901234567890123456789012345678
-//201 - 250 12345678901234567890123456789012345678
-//251 - 300 12345678901234567890123456789012345678
-//301 - 350 12345678901234567890123456789012345678
-//351 - 400 12345678901234567890123456789012345678
-//401 - 450 12345678901234567890123456789012345678
-//451 - 500 12345678901234567890123456789012345678
-//501 - 550 12345678901234567890123456789012345678
-//551 - 600 12345678901234567890123456789012345678
-//601 - 650 12345678901234567890123456789012345678
-//651 - 700 12345678901234567890123456789012345678
-//
-//-----------------------------7de3ab1652086c--
-//^^ Boundary Definition                     ^^ Boundary Definition
-//   is appended to "--"                        is suffixed "--" indicating the end.
-//---
-//Content-Disposition: form-data; name="InFile"; filename="somefile.txt"\r\n
-//Content-Type: image/bmp\r\n
-//\r\n
-//BM6.... (where the ... is purely binary data data)
-//\r\n------webKitFormBoundary9A3C872FAC9BE23--\r\n
-//---
-//
-HTTPServer::CallBackResults ProcessCache(HTTPServer *svr, HTTPServer::CallBackType type)
-{
-    typedef enum {
-        Seeking_Boundary_Start,
-        Seeking_Filename,
-        Seeking_ContentType,
-        Seeking_Data
-    } EF_State_E;
-    static EF_State_E EF_State = Seeking_Boundary_Start;
-    static FILE * fp = NULL;
-
-    char * pDataStart = pCache;                 // start of data in this transaction
-    char * pDataEnd = pCache + bytesInCache;    // end of data in this transaction
-    char * pDBLcrlf;
-    char *p1, *p2, *p3;                         // general purpose pointer for processing the results
-    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_CONTINUE;
-
-    INFO("### Cache Begin\r\n%s\r\n### Cache End", pCache);
-    if (EF_State == Seeking_Boundary_Start) {
-        pDBLcrlf = _strnbin((char *)pDataStart, "\r\n\r\n", pDataEnd - pDataStart);    // find end of preamble
-        if (pDBLcrlf) {
-            p1 = _strnbin((char *)pDataStart, boundary, pDBLcrlf - pDataStart);   // is there a boundary in the cache?
-            if (p1) {
-                EF_State = Seeking_Filename;
-            }
-        }
-    }
-    
-    if (EF_State == Seeking_Filename) {
-        pDBLcrlf = _strnbin((char *)pDataStart, "\r\n\r\n", pDataEnd - pDataStart);    // find end of preamble
-        if (pDBLcrlf) {
-            p2 = _strnbin((char *)pDataStart, "Content-Disposition: ", pDBLcrlf - pDataStart);   // and the filename container?
-            if (p2) {
-                p2 = _strnbin((char *)p2, "filename=\"", pDBLcrlf - pDataStart);
-                if (p2) {   // found filename
-                    p2 += strlen("filename=\"");    // start of filename
-                    p3 = strchr(p2, '"');           // end of filename
-                    if (p3) {
-                        *p3 = '\0';
-                        fqfn = (char *)malloc(p3-p2 + strlen(svr->GetWebRoot())+2);
-                        if (fqfn) {
-                            strcpy(fqfn, svr->GetWebRoot());     // We could put it elsewhere
-                            strcat(fqfn, "/");
-                            strcat(fqfn, p2);
-                            *p3 = '"';              // Put this back so we can print the cache
-                            EF_State = Seeking_ContentType;
-                            pDataStart = p3 + 1;
-                        } else {
-                            ERR("Failed to allocate space for filename");
-                            ret = HTTPServer::ACCEPT_ERROR;
-                            EF_State = Seeking_Boundary_Start;
-                            bytesInCache = 0;
-                            return ret;
-                        }
-                    }
-                }
-            }
-        }
-    }
-    
-    if (EF_State == Seeking_ContentType) {
-        pDBLcrlf = _strnbin((char *)pDataStart, "\r\n\r\n", pDataEnd - pDataStart);    // find end of preamble
-        if (pDBLcrlf) {
-            p2 = _strnbin((char *)pDataStart, "Content-Type: ", pDBLcrlf - pDataStart);
-            if (p2) {
-                p2 += strlen("Content-Type: ");
-                p3 = strchr(p2, '\r');
-                if (p3) {
-                    *p3 = '\0';
-                    contenttype = (char *)malloc(p3-p2 + 2);
-                    if (contenttype) {
-                        strcpy(contenttype, p2);
-                        *p3 = '\r';             // put it back so we can print the cache
-                    } else {
-                        ERR("Failed to allocate space for content type");
-                        ret = HTTPServer::ACCEPT_ERROR;
-                        EF_State = Seeking_Boundary_Start;
-                        bytesInCache = 0;
-                        return ret;
-                    }
-                    pDataStart = pDBLcrlf + 4;  // Advance to the actual data
-                    EF_State = Seeking_Data;
-                }
-            }
-        }
-    }
-    
-    if (EF_State == Seeking_Data) {
-        if (!fp && fqfn) {
-            //INFO("Open file [%s]", fqfn);
-            fp = fopen(fqfn, "w");
-            if (!fp) {
-                ERR("failed to open [%s]", fqfn);
-                free(fqfn);
-                fqfn = NULL;
-                if (contenttype) {
-                    free(contenttype);
-                    contenttype = NULL;
-                }
-                ret = HTTPServer::ACCEPT_ERROR;
-                return ret;
-            }
-        }
-        if (fp) {
-            Timer t;
-            // The file is open, so we're writing data to it. 
-            // We do this until we find the ending boundary, but we may not have the [whole]
-            // ending boundary in the cache yet.
-            p1 = _strnbin((char *)pDataStart, boundary, pDataEnd - pDataStart);   // is there a boundary in the cache?
-            if (p1) {       // if we find the ending boundary, we can truncate and write the data ahead of the boundary
-                p1 -= 4;    // Actual ending boundary is "\r\n--" + "boundary" + "--", so back up 4.
-                *p1 = '\0';
-                pDataEnd = p1;
-                if (pDataEnd > pDataStart) {
-                    bytesWritten += pDataEnd - pDataStart;
-                    t.start();
-                    fwrite(pDataStart, 1, pDataEnd - pDataStart, fp);
-                    INFO("Writing %5d bytes, %5d total written, (reserve %d) in %d us", 
-                        pDataEnd - pDataStart, bytesWritten, 0, t.read_us());
-                    //INFO("Write: %s***", pDataStart);
-                    bytesInCache = 0;
-                    *pCache = '\0';         // this for debugging in case it is text and you want to print it.
-                } else {
-                    INFO("Not enough data to write (%d <= %d)", pDataEnd, pDataStart);
-                }
-            } else {  // didn't find the boundary, but it might be partially there...
-                // write the data, but not the last (strlen(boundary) + 4) 
-                // in case this transaction has some, but not all of the boundary
-                int reserve = strlen(boundary) + 4;
-                pDataEnd -= reserve;
-                if (pDataEnd > pDataStart) {
-                    bytesWritten += pDataEnd - pDataStart;
-                    t.start();
-                    fwrite(pDataStart, 1, pDataEnd - pDataStart, fp);
-                    INFO("Writing %5d bytes, %5d total written, (reserve %d) in %d us", 
-                        pDataEnd - pDataStart, bytesWritten, reserve, t.read_us());
-                    //INFO("Write: %s###", pDataStart);
-                    memcpy(pCache, pDataEnd, reserve+1);    // copies the trailing '\0'
-                    bytesInCache = reserve;
-                    //*(pCache + bytesInCache) = '\0';
-                    INFO("remaining: %s", pCache);
-                } else {
-                    INFO("Not enough data to write (%d <= %d)", pDataEnd, pDataStart);
-                }
-            }
-            ret = HTTPServer::ACCEPT_CONTINUE;
-        }
-    }
-
-    if (type == HTTPServer::DATA_TRANSFER_END) {
-        if (fp) {
-            fclose(fp);
-            fp = NULL;
-            if (fqfn) {
-                free(fqfn);
-                fqfn = NULL;
-            }
-            if (contenttype) {
-                free(contenttype);
-                contenttype = NULL;
-            }
-        }
-        if (pCache) {
-            //INFO("pCache - freed");
-            free(pCache);
-            pCache = NULL;
-            bytesInCache = 0;
-        }
-        ret = HTTPServer::ACCEPT_COMPLETE;
-    }
-    return ret;
-}
-
-
-
-/// DynamicFileIn
-///
-/// This page lets you submit a file.
-///
-/// You can see in main how this page was registered.
-///
-HTTPServer::CallBackResults DynamicFileIn(
-    HTTPServer *svr,
-    HTTPServer::CallBackType type,
-    const char * path,
-    const HTTPServer::namevalue *params,
-    int count)
-{
-    char buf[100];
-    int clSize;     // content-length size to be transferred
-    static AcceptStatus accept = IDLE;
-    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
-    DIR *d;
-    struct dirent *p;
-
-    switch (type) {
-        case HTTPServer::CONTENT_LENGTH_REQUEST:
-            // Here we can find out how much data is headed our way,
-            // and choose to accept or reject it.
-            clSize = atoi(svr->GetHeaderValue("Content-Length"));
-            //printf("Content Len RQST(%d)\r\n", clSize);
-            //printf("Content-Type: [%s]\r\n", svr->GetHeaderValue("Content-Type"));
-            // also, for the multipart data, we have to learn and track
-            // the boundary sequence, so we can parse the big block
-            // successfully.
-            boundary = _stristr((char *)svr->GetHeaderValue("Content-Type"), "boundary=");
-            if (boundary)
-                boundary += strlen("boundary=");
-            //INFO("C-Len: %d, boundary: [%s]", clSize, boundary);
-            //printf("InFile = [%s]\r\n", svr->GetHeaderValue("InFile"));
-            // If we're happy with the size, and we have the boundary marker we need
-            if (clSize < ACCEPT_MAX_BYTES && boundary) {
-                pCache = (char *)malloc(PCACHE_SIZE);
-                if (pCache) {
-                    //INFO("pCache - allocated");
-                    bytesInCache = 0;
-                    accept = ACCEPTED;
-                    ret = HTTPServer::ACCEPT_COMPLETE;
-                } else {
-                    accept = REJECTED_TOO_LARGE;    // can't get the RAM to host the stream
-                    ret = HTTPServer::ACCEPT_ERROR;
-                }
-            } else {
-                accept = REJECTED_TOO_LARGE;
-            }
-            break;
-
-        case HTTPServer::DATA_TRANSFER_END:
-            //INFO("\r\n\\\\\\\\\\\\ Transfer Begin [%d, %d]\r\n%s\r\n////// Transfer End", count, bytesInCache, path);
-            // if there is anything there, copy it in.
-            if (count) {
-                memcpy(pCache + bytesInCache, path, count);
-                bytesInCache += count;
-                pCache[bytesInCache] = '\0';    // one past the data, so ok (and good for debugging text streams)
-            }
-            ret = ProcessCache(svr, type);
-            break;
-
-        case HTTPServer::DATA_TRANSFER:
-            //INFO("\r\n\\\\\\\\\\\\ Transfer Begin [%d, %d]\r\n%s\r\n////// Transfer End", count, bytesInCache, path);
-            // We chose to accept the transfer, and it may come in chunks.
-            if (bytesInCache + count < PCACHE_SIZE - ETHER_CHUNK) { // room in the cache for more, juat accept it locally
-                memcpy(pCache + bytesInCache, path, count);
-                bytesInCache += count;
-                pCache[bytesInCache] = '\0'; // one past the data, so ok (and good for debugging text streams)
-                ret = HTTPServer::ACCEPT_CONTINUE;
-            } else if (bytesInCache + count < PCACHE_SIZE) {        // room in the cache, now process it.
-                memcpy(pCache + bytesInCache, path, count);
-                bytesInCache += count;
-                pCache[bytesInCache] = '\0';    // one past the data, so ok (and good for debugging text streams)
-                ret = ProcessCache(svr, type);  // now hand it off
-            } else {
-                ret = ProcessCache(svr, type);  // panic, ah!, ok, first hand it off then cache it
-                memcpy(pCache + bytesInCache, path, count);
-                bytesInCache += count;
-                pCache[bytesInCache] = '\0';    // one past the data, so ok (and good for debugging text streams)
-                ERR("FATAL - didn't flush pCache, was about to be overrun");
-                break;
-            }
-            break;
-
-        case HTTPServer::SEND_PAGE:
-            svr->header(200, "OK", svr->GetSupportedType(".htm"));
-            svr->send("<html><head><title>Dynamic File Submit</title></head>\r\n");
-            svr->send("<body>\r\n");
-            svr->send("<h1>Smart WiFly Web Server</h1>\r\n");
-            sprintf(buf, "This example permits you to upload a file of not more than %d bytes. ", ACCEPT_MAX_BYTES);
-            svr->send(buf);
-            svr->send("If the file is one of the supported types, you can then download it too. ");
-            svr->send("Select the file using the form gadget and then submit it.");
-            switch(accept) {
-                case IDLE:
-                default:
-                    break;
-                case ACCEPTED:
-                    svr->send("<br/><b>Previous submission accepted.</b><br/>\r\n");
-                    break;
-                case REJECTED_TOO_LARGE:
-                    svr->send("<br/><b>Previous submission rejected.</b><br/>\r\n");
-                    break;
-            }
-            // note that to accept a file, the form enctype is multipart/form-data.
-            svr->send("<blockquote>\r\n");
-            sprintf(buf, "<form method='post' enctype='multipart/form-data' action='%s'>\r\n", path);
-            svr->send(buf);
-            svr->send("<table border='0'>\r\n");
-            svr->send("<tr><td>File</td><td><input type='file' name='InFile' size='60'></td></tr>\r\n");
-            svr->send("<tr><td>&nbsp;</td><td><input type='submit' value='Submit'><input type='reset' value='Clear'></td></tr>\r\n");
-            svr->send("</table>\r\n");
-            svr->send("</form>\r\n");
-            svr->send("</blockquote>\r\n");
-#if 1
-            sprintf(buf, "<h2>Directory of [%s]:</h2>\r\n", svr->GetWebRoot());
-            svr->send(buf);
-            d = opendir(svr->GetWebRoot());
-            if ( d != NULL ) {
-                svr->send("<ul>\r\n");
-                while ( (p = readdir(d)) != NULL ) {
-                    if (svr->GetSupportedType(p->d_name) != NULL)
-                        sprintf(buf, "<li><a href='%s'>%s</a> (%d bytes)</li>\r\n", p->d_name, p->d_name, FileSize(svr->GetWebRoot(), p->d_name)); // only supported types linked
-                    else
-                        sprintf(buf, "<li>%s (%d bytes)</li>\r\n", p->d_name, FileSize(svr->GetWebRoot(), p->d_name));     // We could skip/hide these if that makes more sense
-                    svr->send(buf);
-                }
-                svr->send("</ul>\r\n");
-                closedir(d);
-            } else {
-                svr->send("Unable to open directory!");
-            }
-#endif
-            svr->send("<a href='/'>Back to main</a></body></html>\r\n");
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-
-        default:
-            printf("unknown command %d\r\n", type);
-            ret = HTTPServer::ACCEPT_ERROR;
-            break;
-    }
-    return ret;
-}
-
-static int FileSize(const char * dir, const char * filename)
-{
-    int size = 0;
-    char * fqfn = (char *)malloc(strlen(dir) + strlen(filename) + 2);
-    if (fqfn) {
-        strcpy(fqfn, dir);
-        strcat(fqfn, "\\");
-        strcat(fqfn, filename);
-        FILE * f = fopen(fqfn,"r");
-        if (f) {
-            fseek(f, 0, SEEK_END); // seek to end of file
-            size = ftell(f);
-            fclose(f);
-        }
-    }
-    return size;
-}
-
-// very simple ASCII only function to convert
-// UPPERCASE to lowercase.
-//
-static char _tolower(char c)
-{
-    if (c >= 'A' && c <= 'Z')
-        c = c - 'A' + 'a';
-    return c;
-}
-
-// case insensitive compare
-static int _strnicmp(const char * left, const char * right, int len)
-{
-    if (!left || !right)
-        return 0;           // actually, can't compare so this is a small lie
-    while (len) {
-        if (_tolower(*left) < _tolower(*right))
-            return -1;
-        else if (_tolower(*left) > _tolower(*right))
-            return 1;
-        left++;
-        right++;
-        len--;
-    }
-    return 0;   // match
-}
-
-// Search a haystack string for a needle string - case insensitive.
-//
-static char * _stristr(char * pHaystack, const char * pNeedle)
-{
-    if (!pHaystack || !*pHaystack || !pNeedle || !*pNeedle)
-        return NULL;    // bad params
-    while (*pHaystack) {
-        if (_strnicmp(pHaystack, pNeedle, strlen(pNeedle)) == 0)
-            return pHaystack;
-        pHaystack++;
-    }
-    return NULL;
-}
-
-// Search the [possibly] binary haystack for the Needle, which is a string.
-// This is used to find the 'boundary' marker in a stream from the network
-// interface. The contents between the boundary markers could be text, or
-// it could be a binary stream. Since the haystack could be binary, we need
-// to control the search by a length parameter.
-//
-static char * _strnbin(char * pBinstack, const char *pNeedle, int len)
-{
-    char * pLast;
-    if (!pBinstack || !pNeedle || !*pNeedle || len == 0)
-        return NULL;    // bad params
-    len -= strlen(pNeedle); // only search [most] of the haystack
-    pLast = pBinstack + len;
-    while (pBinstack <= pLast) {
-        if (_strnicmp(pBinstack, pNeedle, strlen(pNeedle)) == 0)
-            return pBinstack;
-        pBinstack++;
-    }
-    return NULL;
-}
--- a/Examples/DynamicFileIn.h	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-
-#ifndef DYNAMICFILEIN_H
-#define DYNAMICFILEIN_H
-#include "mbed.h"
-
-#include "SW_HTTPServer.h"
-
-HTTPServer::CallBackResults DynamicFileIn(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount);
-
-#endif // DYNAMICFILEIN_H
--- a/Examples/DynamicPages.cpp	Fri Jan 03 19:57:31 2014 +0000
+++ b/Examples/DynamicPages.cpp	Mon Sep 01 20:54:51 2014 +0000
@@ -7,6 +7,8 @@
 
 #include "SW_HTTPServer.h"
 #include "DynamicPages.h"
+
+#define DEBUG "dynP"    /* activate this before "Utility.h" */
 #include "Utility.h"
 
 
@@ -24,26 +26,19 @@
 {
     HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
     char contentlen[30];
-    #ifdef INCLUDE_GETREMOTE
-    char remoteIP[36];
-    #endif
     char buf[250];
 
     switch (type) {
         case HTTPServer::SEND_PAGE:
             // This sample drops it all into a local buffer, computes the length,
             // and passes that along as well. This can help the other end with efficiency.
-            strcpy(buf, "<html><head><title>Dynamic Page</title></head>\r\n");
+            strcpy(buf, "<html><head><title>Home Page</title></head>\r\n");
             strcat(buf, "<body>\r\n");
             strcat(buf, "<h1>Smart WiFly Web Server</h1>\r\n");
             strcat(buf, "This page was generated dynamically.<br/>\r\n");
-            #ifdef INCLUDE_GETREMOTE
-            svr->GetRemoteAddr(remoteIP, sizeof(remoteIP));
-            strcat(buf, "Client IP Address: ");
-            strcat(buf, remoteIP);
-            strcat(buf, "<br/>\r\n");
-            #endif
-            strcat(buf, "<a href='/'>back to main</a></body></html>\r\n");
+            strcat(buf, "<a href='/dyn'>To another dynamically generated page.</a><br/>\r\n");
+            strcat(buf, "<a href='/led'>A page to control the LEDs.</a><br/>\r\n");
+            strcat(buf, "</body></html>\r\n");
             sprintf(contentlen, "Content-Length: %d\r\n", strlen(buf));
             // Now the actual header response
             svr->header(200, "OK", "Content-Type: text/html\r\n", contentlen);
@@ -79,9 +74,11 @@
     char buf[100];
     HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
     HTTPServer::SW_PerformanceData perfData;
+    //Wifly * w = svr->GetWifly()->getInstance();
 
     switch (type) {
         case HTTPServer::SEND_PAGE:
+            INFO("dt: %d, %s", type, path);
             if (strcmp("true", svr->GetParameter("Reset")) == 0)
                 svr->ResetPerformanceData();
             // Send the header
@@ -117,10 +114,10 @@
             svr->send(buf);
             sprintf(buf,"<tr><td align='right'>%d</td><td>Max Header size</td></tr>\r\n", svr->GetMaxHeaderSize());
             svr->send(buf);
-            sprintf(buf,"<tr><td align='right'>%3.2f</td><td>Wifly SW version</td></tr>\r\n", svr->GetWifly()->getWiflyVersion());
-            svr->send(buf);
-            sprintf(buf,"<tr><td align='right'>%s</td><td>Wifly Version Information</td></tr>\r\n", svr->GetWifly()->getWiflyVersionString());
-            svr->send(buf);
+            //sprintf(buf,"<tr><td align='right'>%3.2f</td><td>Wifly SW version</td></tr>\r\n", w->getWiflyVersion());
+            //svr->send(buf);
+            //sprintf(buf,"<tr><td align='right'><font size='-1'>%s</font></td><td>Wifly Version Information</td></tr>\r\n", w->getWiflyVersionString());
+            //svr->send(buf);
             svr->send("</table>\r\n");
             svr->send("</blockquote>\r\n");
 
@@ -168,12 +165,15 @@
             ret = HTTPServer::ACCEPT_COMPLETE;
             break;
         case HTTPServer::CONTENT_LENGTH_REQUEST:
+            INFO("dt: %d, %s", type, path);
             ret = HTTPServer::ACCEPT_COMPLETE;
             break;
         case HTTPServer::DATA_TRANSFER:
+            INFO("dt: %d, %s", type, path);
             ret = HTTPServer::ACCEPT_COMPLETE;
             break;
         default:
+            INFO("dt: %d, %s", type, path);
             ret = HTTPServer::ACCEPT_ERROR;
             break;
     }
@@ -193,12 +193,26 @@
 HTTPServer::CallBackResults SimpleDynamicForm(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount)
 {
     char buf[100];
+    const char * p1, *p2;
     HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
 
     switch (type) {
+        case HTTPServer::CONTENT_LENGTH_REQUEST:
+            INFO("dt: %d, %s", type, path);
+            // this callback asks this handler if it will accept a data transfer.
+            ret = HTTPServer::ACCEPT_COMPLETE;
+            break;
+            
         case HTTPServer::SEND_PAGE:
+            INFO("dt: %d, %s", type, path);
             // set the LEDs based on a passed in parameter.
-            leds = atoi(svr->GetParameter("leds"));
+            p1 = svr->GetParameter("leds");
+            p2 = svr->GetPostParameter("leds");
+            if (p1)
+                leds = atoi(p1);
+            else if (p2)
+                leds = atoi(p2);
+
             // send the header
             svr->header(200, "OK", svr->GetSupportedType(".htm"));  //svr->header(200, "OK", "Content-Type: text/html\r\n");
             // send some data
@@ -207,36 +221,64 @@
             svr->send("<h1>Smart WiFly Web Server</h1>\r\n");
             svr->send("This form was generated dynamically. You can add name=value pairs on the URL "
                       "which will show up in the form, but the form is submitted using POST method.<br/>\r\n");
-            svr->send("Hint: leds=7 turns on 3 of the 4 blue leds on the mbed<br/>\r\n");
+            svr->send("Hint: <a href='/led?leds=7&sky=Blue&car=Jaguar'>leds=7&sky=Blue&car=Jaguar</a> turns on"
+                      " 3 of the 4 blue leds on the mbed and passes a couple other parameters.<br/>\r\n");
             sprintf(buf, "%d parameters passed to {%s}:<br/>\r\n", paramcount, path);
             svr->send(buf);
+            
             // Create a user form for which they can post changes
-            sprintf(buf, "<form method='post' action='%s'>\r\n", path);
+            sprintf(buf, "POST Form: <form method='post' action='%s'>\r\n", path);
+            //sprintf(buf, "<form method='post' enctype='multipart/form-data' action='%s'>\r\n", path); // not supported
+            svr->send(buf);
+            // show the parameters in a nice format
+            svr->send("<table>\r\n");
+            
+            for (int i=0; i<svr->GetParameterCount(); i++) {
+                HTTPServer::namevalue * p = svr->GetParameter(i);
+                sprintf(buf, "<tr><td>%d</td><td>%s</td><td><input type='text' name='%s' value='%s'></td></tr>\r\n", 
+                    i, p->name, p->name, p->value);
+                svr->send(buf);
+            }
+            for (int i=0; i<svr->GetPostParameterCount(); i++) {
+                HTTPServer::namevalue * p = svr->GetPostParameter(i);
+                sprintf(buf, "<tr><td>%d</td><td>%s</td><td><input type='text' name='%s' value='%s'></td></tr>\r\n", 
+                    i, p->name, p->name, p->value);
+                svr->send(buf);
+            }
+
+            //svr->send("<tr><td>&nbsp;</td><td>File</td><td><input type='file' name='InFile' size='40'></td></tr>\r\n");
+            svr->send("<tr><td>&nbsp;</td><td colspan='2'><input type='submit' value='submit'><input type='reset' value='clear'></td></tr>\r\n");
+            svr->send("</table>\r\n");
+            svr->send("</form>\r\n");
+
+            // Create a user form for which they can post changes
+            sprintf(buf, "GET Form: <form method='get' action='%s'>\r\n", path);
             //sprintf(buf, "<form method='post' enctype='multipart/form-data' action='%s'>\r\n", path); // not supported
             svr->send(buf);
             // show the parameters in a nice format
             svr->send("<table>\r\n");
             for (int i=0; i<paramcount; i++) {
-                if (strcmp(params[i].name, "InFile") == 0)
-                    continue;
-                sprintf(buf, "<tr><td>%d</td><td>%s</td><td><input type='text' name='%s' value='%s'></td></tr>\r\n", i, params[i].name, params[i].name, params[i].value);
+                sprintf(buf, "<tr><td>%d</td><td>%s</td><td><input type='text' name='%s' value='%s'></td></tr>\r\n", 
+                    i, 
+                    params[i].name, params[i].name, params[i].value);
                 svr->send(buf);
             }
             //svr->send("<tr><td>&nbsp;</td><td>File</td><td><input type='file' name='InFile' size='40'></td></tr>\r\n");
             svr->send("<tr><td>&nbsp;</td><td colspan='2'><input type='submit' value='submit'><input type='reset' value='clear'></td></tr>\r\n");
             svr->send("</table>\r\n");
             svr->send("</form>\r\n");
-            // see how we're doing with free memory
+
             svr->send("<br/><a href='/'>Back to main</a></body></html>\r\n");
             ret = HTTPServer::ACCEPT_COMPLETE;
             break;
-        case HTTPServer::CONTENT_LENGTH_REQUEST:
+            
+        case HTTPServer::DATA_TRANSFER:
+            INFO("dt: %d, %s", type, path);
             ret = HTTPServer::ACCEPT_COMPLETE;
             break;
-        case HTTPServer::DATA_TRANSFER:
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
+            
         default:
+            INFO("dt: %d, %s", type, path);
             ret = HTTPServer::ACCEPT_ERROR;
             break;
     }
--- a/Examples/SecurePage.cpp	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-
-#include "mbed.h"
-
-#include "SW_HTTPServer.h"
-#include "DynamicPages.h"
-#include "Utility.h"
-#include "Base64.h"
-
-
-Base64 bc64;
-char * converted = NULL;
-size_t convertedLen = 0;
-bool accessGranted = false;
-
-bool CredentialCheck(char * user, char * pass)
-{
-    printf("CredentialCheck(%s,%s)\r\n", user, pass);
-    if (strcmp(user, "user1") == 0 && strcmp(pass, "pass1") == 0)
-        return true;
-    else
-        return false;
-}
-
-
-/// SimpleSecurityCheck
-HTTPServer::CallBackResults SimpleSecurityCheck(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount)
-{
-    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
-    char buf[150];
-
-    switch (type) {
-        case HTTPServer::SEND_PAGE:
-            accessGranted = false;
-            if (svr->GetHeaderValue("Authorization") != NULL) {
-                const char * p = svr->GetHeaderValue("Authorization");
-                if (p && strncmp(p, "Basic ", 6) == 0) {
-                    p += 6;
-                    if (converted)          // this should never be true, but is a nice safeguard
-                        free(converted);
-                    converted = bc64.Decode(p, strlen(p), &convertedLen);
-                    if (converted) {
-                        // Now check the actual credentials...
-                        char *colon;
-                        converted[convertedLen] = '\0';
-                        colon = strchr(converted, ':');
-                        if (colon) {
-                            *colon++ = '\0';
-                            if (CredentialCheck(converted, colon))
-                                accessGranted = true;
-                        }
-                    }
-                }
-            }
-            if (!accessGranted)
-                svr->header(401, "Access Denied", "WWW-Authenticate: Basic realm='Smart HTTPServer insecure logon'\r\n");
-            else {
-                svr->header(200, "OK", "Content-Type: text/html\r\n");
-                svr->send("<html><head><title>Security Check</title></head>\r\n");
-                svr->send("<body>\r\n");
-                sprintf(buf, "<h1>Welcome %s</h1>\r\n", converted);
-                svr->send(buf);
-                svr->send("Authorization was approved.<p/>\r\n");
-                svr->send("Your browser will now cache the credentials until you close it.");
-                svr->send("So, be sure to close it for maximum security (and don't let it save your credentials).<p/>\r\n");
-                svr->send("<a href='/'>back to main</a></body></html>\r\n");
-            }
-            if (converted)
-                free(converted);    // don't leak memory
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-        case HTTPServer::CONTENT_LENGTH_REQUEST:
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-        case HTTPServer::DATA_TRANSFER:
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-        default:
-            ret = HTTPServer::ACCEPT_ERROR;
-            break;
-    }
-    return ret;
-}
--- a/Examples/SecurePage.h	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-
-#ifndef SECUREPAGE_H
-#define SECUREPAGE_H
-#include "mbed.h"
-
-#include "SW_HTTPServer.h"
-
-HTTPServer::CallBackResults SimpleSecurityCheck(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount);
-
-#endif // SECUREPAGE_H
-
--- a/Examples/ServerConfig.cpp	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/// Demonstration of dynamic page creation using the Smartware Web Server
-///
-/// There are a few samples here of the dynamically generated web pages.
-/// Read the header above each one for more details.
-///
-/// Status - very experimental. 
-///
-///         It reads the ini file, but is not reliably managing it.
-///         have only tried on the local file system so far.
-///
-#include "mbed.h"
-
-#include "SW_HTTPServer.h"
-#include "DynamicPages.h"
-#include "Utility.h"
-#include "IniManager.h"
-
-
-
-/// ServerConfig
-///
-/// ssid
-/// pass code
-/// Security
-/// time server
-/// time zone
-///
-HTTPServer::CallBackResults ServerConfig(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount) {
-    char buf[250];
-    HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
-    char ssid[50] = "";
-    char pass[50] = "";
-    char security[10] = "";
-    char timeserver[60] = "";
-    char timezone[4] = "";       // -12
-    //char *securityList[] = 
-    //    { "NONE", "WEP_128", "WPA1", "WPA", "WPA2_PSK", "n/a", "ADHOC", "n/a", "WPE_64" };
-    INI ini("/local/config.ini");
-
-    switch (type) {
-        case HTTPServer::SEND_PAGE:
-            // svr->GetParameter("SSID");
-            
-            // ReadString(const char * section, const char * key, char * buffer, size_t bufferSize)
-            ini.ReadString("Wifi", "ssid", ssid, sizeof(ssid), svr->GetParameter("ssid"));
-            printf("svr ssid: %s\r\n", ssid);
-            printf("web ssid: %s\r\n", svr->GetParameter("ssid"));
-            if (svr->GetParameter("ssid") && strcmp(ssid, svr->GetParameter("ssid")) != 0)
-                {
-                strcpy(ssid, svr->GetParameter("ssid"));
-                printf("==  ssid: %s\r\n", ssid);
-                ini.WriteString("Wifi", "ssid", ssid);
-                }
-            printf("svr ssid: %s\r\n", ssid);
-            ini.ReadString("Wifi", "pass", pass, sizeof(pass), svr->GetParameter("pass"));
-            if (svr->GetParameter("pass") && strcmp(pass, svr->GetParameter("pass")) != 0)
-                {
-                strcpy(pass, svr->GetParameter("pass"));
-                ini.WriteString("Wifi", "pass", pass);
-                }
-            printf("svr pass: %s\r\n", pass);
-            ini.ReadString("Wifi", "security", security, sizeof(security), svr->GetParameter("security"));
-            if (svr->GetParameter("security") && strcmp(security, svr->GetParameter("security")) != 0)
-                {
-                strcpy(security, svr->GetParameter("security"));
-                ini.WriteString("Wifi", "security", security);
-                }
-            ini.ReadString("Clock", "timeserver", timeserver, sizeof(timeserver), svr->GetParameter("timeserver"));
-            if (svr->GetParameter("timeserver") && strcmp(timeserver, svr->GetParameter("timeserver")) != 0)
-                {
-                strcpy(timeserver, svr->GetParameter("timeserver"));
-                ini.WriteString("Clock", "timeserver", timeserver);
-                }
-            ini.ReadString("Clock", "timezone", timezone, sizeof(timezone), svr->GetParameter("timezone"));
-            if (svr->GetParameter("timezone") && strcmp(timezone, svr->GetParameter("timezone")) != 0)
-                {
-                strcpy(timezone, svr->GetParameter("timezone"));
-                ini.WriteString("Clock", "timezone", timezone);
-                }
-            
-            // send the header
-            svr->header(200, "OK", svr->GetSupportedType(".htm"));
-            // send some data
-            svr->send("<html><head><title>Server Config</title></head>\r\n");
-            svr->send("<body>\r\n");
-            svr->send("<h1>Smart WiFly Web Server - Server Config</h1>\r\n");
-            svr->send("Configure options here.<br/>\r\n");
-            // Create a user form for which they can post changes
-            sprintf(buf, "<form method='post' action='%s'>\r\n", path);
-            svr->send(buf);
-            // show the parameters in a nice format
-            svr->send("<table border='1'>\r\n");
-            sprintf(buf, "<tr><td>Setting</td><td>Value</td><td>Description</td></tr>\r\n");
-            svr->send(buf);
-            sprintf(buf, "<tr><td>SSID</td><td><input type='text' name='ssid' value='%s'></td><td>Name of the Access Point</td></tr>\r\n", ssid);
-            svr->send(buf);
-            sprintf(buf, "<tr><td>PassCode</td><td><input type='text' name='pass' value='%s'></td><td>Passcode</td></tr>\r\n", pass);
-            svr->send(buf);
-            sprintf(buf, "<tr><td>Security</td><td><input type='text' name='security' value='%s'></td><td>Security Setting</td></tr>\r\n", security);
-            svr->send(buf);
-            sprintf(buf, "<tr><td>Time Server</td><td><input type='text' name='timeserver' value='%s'></td><td>Time Server</td></tr>\r\n", timeserver);
-            svr->send(buf);
-            sprintf(buf, "<tr><td>Time Zone</td><td><input type='text' name='timezone' value='%s'></td><td>Time Zone</td></tr>\r\n", timezone);
-            svr->send(buf);
-            //svr->send("<tr><td>&nbsp;</td><td>File</td><td><input type='file' name='InFile' size='40'></td></tr>\r\n");
-            svr->send("<tr><td>&nbsp;</td><td colspan='2'><input type='submit' value='submit'><input type='reset' value='clear'></td></tr>\r\n");
-            svr->send("</table>\r\n");
-            svr->send("</form>\r\n");
-            // see how we're doing with free memory
-            svr->send("<br/><a href='/'>Back to main</a></body></html>\r\n");
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-        case HTTPServer::CONTENT_LENGTH_REQUEST:
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-        case HTTPServer::DATA_TRANSFER:
-            ret = HTTPServer::ACCEPT_COMPLETE;
-            break;
-        default:
-            ret = HTTPServer::ACCEPT_ERROR;
-            break;
-    }
-    return ret;
-}
--- a/Examples/ServerConfig.h	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-
-#ifndef SERVERCONFIG_H
-#define SERVERCONFIG_H
-#include "mbed.h"
-
-#include "SW_HTTPServer.h"
-
-HTTPServer::CallBackResults ServerConfig(HTTPServer *svr, HTTPServer::CallBackType type, const char * path, const HTTPServer::namevalue *params, int paramcount);
-
-#endif // SERVERCONFIG_H
--- a/FileSystem.lib	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/WiredHome/code/FileSystem/#19a776ced714
--- a/IniManager.lib	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/WiredHome/code/IniManager/#64fcaf06b012
--- a/MODSERIAL.lib	Fri Jan 03 19:57:31 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/Sissors/code/MODSERIAL/#f42def64c4ee
--- a/SW_HTTPServer.lib	Fri Jan 03 19:57:31 2014 +0000
+++ b/SW_HTTPServer.lib	Mon Sep 01 20:54:51 2014 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/WiredHome/code/SW_HTTPServer/#ef165a67ab22
+http://mbed.org/users/WiredHome/code/SW_HTTPServer/#0427544a5c08
--- a/Utility/Utility.h	Fri Jan 03 19:57:31 2014 +0000
+++ b/Utility/Utility.h	Mon Sep 01 20:54:51 2014 +0000
@@ -21,15 +21,17 @@
 // INFO("Stuff to show %d", var); // new-line is automatically appended
 // [I myfile  23] Stuff to show 23\r\n
 //
+#include <cstdio>
 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
-#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define DBG(x, ...)  std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
 #define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
 #else
-#define INFO(x, ...)
+#define DBG(x, ...)
 #define WARN(x, ...)
 #define ERR(x, ...)
+#define INFO(x, ...)
 #endif
 
-
 #endif // UTILITY_H
--- a/WiflyInterface.lib	Fri Jan 03 19:57:31 2014 +0000
+++ b/WiflyInterface.lib	Mon Sep 01 20:54:51 2014 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/WiredHome/code/WiflyInterface/#0729959263b7
+http://mbed.org/users/WiredHome/code/WiflyInterface/#a4064f7e3529
--- a/main.cpp	Fri Jan 03 19:57:31 2014 +0000
+++ b/main.cpp	Mon Sep 01 20:54:51 2014 +0000
@@ -1,221 +1,71 @@
 /** @file main.cpp contains the main program that a user would write.
  * see the documentation above "main"
  */
-#include "mbed.h"               // ver 75
-
-// Standard components
-#include "MODSERIAL.h"          // ver 32 of Erik Olieman's derivative from Andy Kircham
+#include "mbed.h"               // ver 83
+#include "RawSerial.h"
 
 // My components
 #include "Utility.h"            // a couple of simple helper functions
 #include "WiflyInterface.h"     // ver 53, derived from mbed official ver 4
 #include "SW_HTTPServer.h"      // ver 31, derived from nweb
-#include "Credentials.h"        // ver 0, credential manager
 #include "DynamicPages.h"       // my dynamically generated pages
-#include "SecurePage.h"         // my secure pages
-#include "ServerConfig.h"       // various configuration options
-#include "DynamicFileIn.h"      // Upload a file to the server
-#include "MSCFileSystem.h"      // ver 1, this and SDFileSystem
-#include "SDFileSystem.h"       // ver 1, this and MSCFileSystem
+
+#define MBED_APP_BOARD 1        /* http://mbed.org/components/mbed-Application-Board/ */
+#define SMART_BOARD    2        /* http://mbed.org/users/WiredHome/notebook/SmartBoard-baseboard/ */
+
+#define HW_ADAPTER MBED_APP_BOARD   /* Which board are we compiling against? SMART_BOARD or MBED_APP_BOARD */
 
 #define HTTP_SERVER_PORT 80
 
-#ifdef MODSERIAL_H
-MODSERIAL pc(USBTX, USBRX, "modser");
-#else
-Serial pc(USBTX, USBRX);
-#endif
-
-
-LocalFileSystem local("local");         // some place to hold settings and maybe the static web pages
-MSCFileSystem msc("msc");               // Mass Storage on USB
-SDFileSystem sd(p5, p6, p7, p8, "sd");  // for the static web pages
-#define WEBROOT "/msc/web"
-
-PwmOut signOfLife(LED1);
-
-Timer onceinawhile;
-
-/// ShowSignOfLife
-///
-/// Pulse an LED to indicate a sign of life of the program.
-/// also has some moderate entertainment value.
-///
-void ShowSignOfLife() {
-#define PI 3.14159265359
-    static Timer activityTimer;
-    static unsigned int activityStart;
-    static bool init;
-    //static float currentBrightness = 0.0;
-    static int degrees = 0;
-    float v;
-    //static bool rampUp = true;
-
-    if (!init) {
-        activityTimer.start();
-        activityStart = (unsigned int) activityTimer.read_ms();
-        init = true;
-    }
-    if ((unsigned int)activityTimer.read_ms() - activityStart > 20) {
-
-        v = sin(degrees * PI / 180);
-        if (v < 0)
-            v = 0;
-        signOfLife = v;
-        degrees += 2;
-        activityStart = (unsigned int) activityTimer.read_ms();
-    }
-}
-
-
-// A time-bound hook on startup to permit the user to access the wifly module
-//
-void WiFlyShell(Wifly & wifly, PC & pc)
-{
-    Timer userTimer;
-    const int baudrates[] = {2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400};
-    static int i = 0;
-    
-    pc.printf("Pausing 5 sec for shell access to WiFly (press <enter>).\r\n");
-    userTimer.start();
-    do {
-        if (pc.readable()) {
-            bool loop = true;
-            int c = pc.getc();
-            pc.printf("Shell opened to WiFly module: <esc> to exit,\r\n  ctrl-B to reboot, ctrl-C to step baud\r\n");
-            while (loop) {
-                if (pc.readable()) {
-                    int c = pc.getc();
-                    switch (c) {
-                        case '\x1B':        // <ESC>
-                            loop = false;
-                            break;
-                        case '\x02':        // Ctrl-B
-                            wifly.reboot();
-                            break;
-                        case '\x03':        // Ctrl-C
-                            pc.printf("Setting to %d baud.\r\n", baudrates[i]);
-                            wifly.baud(baudrates[i]);
-                            i++;
-                            if (i >= (sizeof(baudrates)/sizeof(baudrates[0])))
-                                i = 0;
-                            break;
-                        default:
-                            wifly.putc(c);
-                            break;
-                    }
-                }
-                if (wifly.readable())
-                    pc.putc(wifly.getc());
-            }
-        }
-    } while (userTimer.read_ms() < 5000);
-    pc.printf("  WiFly shell closed.\r\n");
-}
+RawSerial pc(USBTX, USBRX);
 
 
 
-/// Smart-WiFly-WebServer is the creation of a web server using a WiFly module.
-///
-/// This is a working version, but it is not using the standardized wifly
-/// library, which would not work for me... I had to make a number
-/// of changes to get it to work well. After trying to minmimize those
-/// changes, additional improvements became more and more clumsy, so
-/// I have now been working to refactor where it makes sense, even as
-/// it further deviates from the mbed-library version.
-///
-/// I created this because I couldn't find one that worked and wanted to
-/// learn the WiFly module. There are a lot of possible improvements:
-/// @li I think I'm not using the Socket interface as fully as I should.
-/// @li I would like it to be faster (the interface from mbed to wifly is
-///     limited to 230400 baud before it drops chars. HW handshake could
-///     improve this, but the HW handshake pins on the LPC1768 are not
-///     both brought out.
-/// @li I would like to integrate this with the rtos.
-/// @li If a page has multiple components (e.g. images), it appears
-///     unreliable. It doesn't see the request for the extra component.
-///     A poor workaround, for images, is to use a javascript to post-
-///     load them. This is fundamentally a constraint of the WiFly module.
-///
-/// history:
-/// @li 20130602 added .txt to the supported types (e.g. robots.txt), so
-///         revised the credentials to .crd, which is an unsupported type
-///         therefore won't be delivered to the user.
-///
-/// @note Copyright &copy; 2013 by Smartware Computing, all rights reserved.
-///     Individuals may use this application for evaluation or non-commercial
-///     purposes. Within this restriction, changes may be made to this application
-///     as long as this copyright notice is retained. The user shall make
-///     clear that their work is a derived work, and not the original.
-///     Users of this application and sources accept this application "as is" and
-///     shall hold harmless Smartware Computing, for any undesired results while
-///     using this application - whether real or imagined.
-///
-/// @author David Smart, Smartware Computing
-///
 int main()
 {
-    credentials cr;     // handles the credentials
-
-    pc.baud(921600);    // I like a snappy terminal, so crank it up!
-    pc.claim();         // capture stdout
+    pc.baud(460800);    // I like a snappy terminal, so crank it up!
     pc.printf("\r\nSmart WiFly - Build " __DATE__ " " __TIME__ "\r\n");
 
-    if (!ReadCredentials("/local/user.crd", &cr)) {
-        pc.printf("**** ERROR, no /local/user.crd file was found. ****\r\n");
-        wait(1.0);
-        error("     Waiting for user to fix this problem.         \r\n"); // flash and die
-    }
-
-    WiflyInterface wifly(p28, p27, p23, p24, cr.ssid, cr.pass, WPA);    // Instantiate the WiflyInterface
-    FreeCredentials(&cr);   // Release the credentials, which also secures them
+    // first signals are tx, rx, reset, status pins.
+    #if HW_ADAPTER == MBED_APP_BOARD
+    WiflyInterface wifly( p9, p10, p30, p29, "sf1896", "Sir William Hearth", WPA);
+    #elif HW_ADAPTER == SMART_BOARD
+    WiflyInterface wifly(p28, p27, p23, p24, "sf1896", "Sir William Hearth", WPA);
+    #endif
 
     // Bring the WiFly interface online
     do {
         wifly.init(); // start it up as a client of my network using DHCP
-        wifly.baud(921600);     // Only 230K w/o HW flow control
-        if (wifly.connect())
+        wifly.baud(230400);     // Only 230K w/o HW flow control
+        if (0 == wifly.connect())
             break;
         pc.printf(" Failed to connect, retrying...\r\n");
         wait(1.0);
         wifly.reset();
     } while (1);
 
-    WiFlyShell(wifly, pc);  // 5 second access at startup - in case you need it.
+    // Let the human know it is ready - if they are watching
+    pc.printf("Connect to this server at http://%s:%d\r\n", wifly.getIPAddress(), HTTP_SERVER_PORT);
 
     // Now let's instantiate the web server - along with a few settings:
     // the Wifly object, the port of interest (typically 80),
-    // file system path to the static pages,
+    // file system path to the static pages, if any.
     // the maximum parameters per transaction (in the query string),
     // the maximum number of dynamic pages that can be registered,
     // the serial port back thru USB (for development/logging)
-    HTTPServer svr(&wifly, HTTP_SERVER_PORT, WEBROOT, 15, 30, 10, &pc);
+    HTTPServer svr(HTTP_SERVER_PORT, "/", 15, 30, 10, &pc);
 
     // But for even more fun, I'm registering a few dynamic pages
     // You see the handlers for in DynamicPages.cpp.
     // Here you can see the path to place on the URL.
     // ex. http://192.168.1.140/dyn
-    svr.RegisterHandler("/dyn",  SuperSimpleDynamicPage);
-    svr.RegisterHandler("/dyn1", SimpleDynamicPage);
-    svr.RegisterHandler("/dyn2", SimpleDynamicForm);
-    svr.RegisterHandler("/pass", SimpleSecurityCheck);
-    svr.RegisterHandler("/config", ServerConfig);
-    svr.RegisterHandler("/FileIn", DynamicFileIn);
-
-    // Let the human know it is ready - if they are watching
-    pc.printf("Connect to this server at http://%s:%d\r\n", wifly.getIPAddress(), HTTP_SERVER_PORT);
+    svr.RegisterHandler("/",     SuperSimpleDynamicPage);
+    svr.RegisterHandler("/dyn",  SimpleDynamicPage);
+    svr.RegisterHandler("/led",  SimpleDynamicForm);
 
-    onceinawhile.start();
+
     while (true) {
-        if (onceinawhile.read_ms() >= 200)
-            {
-            onceinawhile.reset();
-            //pc.printf("Largest free mem block is %d\r\n", Free());
-            ShowSignOfLife();
-            }
         svr.Poll();   // non-blocking, but also not deterministic
-        if (pc.readable())
-            WiFlyShell(wifly, pc);  // allow shell access at runtime (if user taps a key)
     }
 }
 
--- a/mbed.bld	Fri Jan 03 19:57:31 2014 +0000
+++ b/mbed.bld	Mon Sep 01 20:54:51 2014 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/dc225afb6914
\ No newline at end of file
+http://mbed.org/users/mbed_official/code/mbed/builds/9327015d4013
\ No newline at end of file