Spidey Wall is the name for a physical wall lit up by multiple addressable LED strips. This program is an LPC1768 web server to control the wall from a browser.

Dependencies:   EthernetInterfacePlusHostname RdWebServer mbed-rtos mbed

This project is part of a Light-Wall using addressable LED strips (WS2801). I have published a few posts on my blog about the construction of the wall and building a game to play on it (PacMan). I have also had a guest post from a friend who has set his children the task of producing some interesting animations. The original post is http://robdobson.com/2015/07/spidey-wall/ /media/uploads/Bobty/20130722_112945_img_9674_62895-1184x1579.jpg

So far, however, I hadn't fully connected the physical (and electronic) wall with the web-browser creations to drive it. This project is hopefully the final link. A fast and reliable web server using REST commands to drive the 1686 LEDs in the Spidey Wall from code running in a browser (say on an iPad while you are playing a game).

The approach taken here results in the ability to control the RGB values of all 1686 LEDs at a rate of 20 frames per second.

A blog post describing the whole thing is here:

http://robdobson.com/2015/08/a-reliable-mbed-webserver/

Revision:
4:b521815f2657
Parent:
3:e5ea80fae61d
Child:
5:910909f34907
--- a/main.cpp	Mon Aug 31 09:03:15 2015 +0000
+++ b/main.cpp	Mon Aug 31 15:21:47 2015 +0000
@@ -1,7 +1,10 @@
 // 
 // LightWall WebServer
 // 
-// Rob Dobson 2015
+// Rob Dobson (C) 2015
+// 
+// See http://robdobson.com/2015/07/spidey-wall/ and http://robdobson.com/2015/08/a-reliable-mbed-webserver/
+//
 
 #include "mbed.h"
 #include "EthernetInterface.h"
@@ -27,180 +30,57 @@
 // Drawing Manager
 DrawingManager drawingManager;
 
-//int ledsCount = 904;
-//int ledSplitPoint = 448;
-//ledstrip* pLedStrip = NULL;
-//
-//char* indexHtmName = "index.htm";
-//
-//const int TICK_MS = 100;
-//LedCmdHandler* pLedCmdHandler = NULL;
-//int blinkCtr = 0;
-//
-//void ledTickfunc()
-//{
-//    if(webServer.isListening())
-//    {
-//        blinkCtr++;
-//        if (blinkCtr > 1)
-//        {
-//            led1 = !led1;
-//            blinkCtr = 0;
-//        }
-//    }
-//    else
-//    {
-//        led1 = false;
-//    }
-//    
-//    if (pLedCmdHandler != NULL)
-//        pLedCmdHandler->NextGen();
-//}
-//
-//void handleCmd_ledControl(char* cmdStr, char* argStr)
-//{
-//    printf("LEDS COMMAND %s %s\r\n", cmdStr, argStr);
-//    if (argStr == NULL)
-//        return;
-//    pLedCmdHandler->DoCommand(argStr);
-//    
-//    // Store last command
-//    LocalFileSystem local("local");
-//    FILE* fp = fopen("/local/lastcmd.inf", "w");
-//    if (fp != NULL)
-//    {
-//        fwrite(argStr, 1, strlen(argStr)+1, fp);
-//        fclose(fp);
-//    }    
-//}
-//
-//void reRunLastCommand()
-//{
-//    // Store last command
-//    LocalFileSystem local("local");
-//    FILE* fp = fopen("/local/lastcmd.inf", "r");
-//    if (fp != NULL)
-//    {
-//        char buf[501];
-//        buf[sizeof(buf)-1] = 0;
-//        int nread = fread(buf, 1, sizeof(buf), fp);
-//        fclose(fp);
-//        if (nread > 0 && nread <= sizeof(buf))
-//        {
-//            buf[nread] = 0;
-//            pLedCmdHandler->DoCommand(buf);
-//        }
-//    }    
-//}
-//
-//#include "colourconverters.h"
-//
-//void BodgeSmooth(ledstrip* pLedStrip)
-//{
-//    pLedStrip->Clear();
-//    pLedStrip->ShowLeds();
-//
-//
-//    RgbColor startRGB(50,0,0);
-//    HsvColor curHsv = RgbToHsv(startRGB);
-//    while(1)
-//    for (int k = 0; k < 1000; k++)
-//    for (int j = 0; j < 255; j++)
-//    {
-//        pLedStrip->Clear();
-//        RgbColor colrVal = HsvToRgb(curHsv);        
-//        pLedStrip->Fill(0,pLedStrip->GetNumLeds(),colrVal.r, colrVal.g, colrVal.b);
-//        pLedStrip->ShowLeds();
-//        wait_ms(250);
-//        curHsv.h++;
-//    }
-//}
-//
-//void setLightsConfig()
-//{
-//    printf("Rob LightWall - Configured for ");
-//    // Check for a config file on the local file system
-//    strcpy(nameOfLights, "Spidey");
-//    LocalFileSystem local("local");
-//    FILE* fp = fopen("/local/spidey.cnf", "r");
-//    if (fp != NULL)
-//    {
-//        char buf[201];
-//        buf[sizeof(buf)-1] = 0;
-//        int nread = fread(buf, 1, sizeof(buf), fp);
-//        if (nread > 0 && nread <= sizeof(buf))
-//        {
-//            buf[nread] = 0;
-//            sscanf(buf, "%s %d %d", nameOfLights, &ledsCount, &ledSplitPoint);
-//        }
-//        fclose(fp);
-//        printf("%s (%d LEDs, Split at %d)", nameOfLights, ledsCount, ledSplitPoint);
-//        printf("\n\r");
-//    }
-//    
-//    // Leds setup
-//    pLedStrip = new ledstrip(ledsCount, ledSplitPoint);
-//    wait_ms(100);
-//    pLedStrip->Clear();
-//    pLedStrip->ShowLeds();
-//
-//    // Cmd handler
-//    pLedCmdHandler = new LedCmdHandler(pLedStrip);
-//}
+// General response string for REST requests
+char* generalRespStr = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: POST, GET, OPTIONS\r\nAccess-Control-Allow-Headers:accept, content-type\r\nContent-Length: 0\r\nContent-Type: application/octet-stream\r\n\r\n";
 
-//int main (void)
-//{
-//    pc.baud(115200);
-//    
-//    setLightsConfig();
-//    
-//    BodgeSmooth(pLedStrip);
-//    
-//    ledTick.attach(&ledTickfunc,TICK_MS / 1000.0);
-//
-////    reRunLastCommand();
-//    
-//    // setup ethernet interface
-//    eth.init(); //Use DHCP
-//    eth.connect();
-//    printf("IP Address is %s\n\r", eth.getIPAddress());
-//
-//    webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, indexHtmName, true);
-//    webServer.addCommand("cmd", RdWebServerCmdDef::CMD_CALLBACK, &handleCmd_ledControl);
-//    webServer.init(PORT, &led2);
-//    webServer.run();
-//}
-
-// Handle a command
-char* lightwallCmd(int method, char* cmdStr, char* argStr, char* msgBuf)
-{
-    // Blink LED
-    led1 = !led1;
-    
-    // Get message payload
-    int cmdLen = RdWebServer::getPayloadLengthFromMsg(msgBuf);
-    unsigned char* cmdBuf = RdWebServer::getPayloadDataFromMsg(msgBuf);
-    
-    // Check if the command length is 0 - in this case respond ok as it might be a
-    // pre-flight check on a Cross Domain request - https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
-    char* respStr = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: POST, GET, OPTIONS\r\nAccess-Control-Allow-Headers:accept, content-type\r\nContent-Length: 0\r\nContent-Type: application/octet-stream\r\n\r\n";
-    if (cmdLen != 0)
-    {
-        // Process command
-        drawingManager.start(cmdBuf, cmdLen);
-    }
-    return respStr;
-}
-
-// Get system name
-char* lightwallGetSystemName(int method, char* cmdStr, char* argStr, char* msgBuf)
+// Get system name - No arguments required
+char* lightwallGetSystemName(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
+                int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
 {
     // Return the system name
     return systemName;
 }
 
+// Clear LEDS - No arguments required
+char* lightwallClear(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
+                int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
+{
+    drawingManager.Clear();
+    return generalRespStr;
+}
+
+// RawFill - arguments for start LED (e.g. /rawfill?start=0)
+//         - payload of message contains binary data for RGB (1 byte for each) for each LED to be set
+char* lightwallRawFill(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
+                int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
+{
+    drawingManager.RawFill(argStr, pPayload, payloadLen, splitPayloadPos);
+    return generalRespStr;
+}
+
+// Fill - arguments for start, numLeds, initial-R/G/B and ending-R/G/B (optional)
+//      - e.g. /fill?start=0&len=100&r1=20&g1=30&b1=50
+//      - e.g. /fill?start=0&len=100&r1=20&g1=30&b1=50&r2=50&g2=100&b2=23
+char* lightwallFill(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
+                int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
+{
+    drawingManager.Fill(argStr);
+    return generalRespStr;
+}
+
+// ShowLeds - no arguments
+char* lightwallShowLeds(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, 
+                int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
+{
+    // Blink LED
+    led1 = !led1;
+    // Show LEDS
+    drawingManager.ShowLeds();
+    return generalRespStr;
+}
+
 // Create, configure and run the web server
-void http_thread(void const* arg)
+void http_server(void const* arg)
 {
     // Init the web server
     pc.printf("Starting web server\r\n");
@@ -212,8 +92,11 @@
     webServer.addCommand("favicon.ico", RdWebServerCmdDef::CMD_LOCALFILE, NULL, NULL, true);
     
     // Add the lightwall control commands
-    webServer.addCommand("cmd", RdWebServerCmdDef::CMD_CALLBACK, &lightwallCmd);
     webServer.addCommand("name", RdWebServerCmdDef::CMD_CALLBACK, &lightwallGetSystemName);
+    webServer.addCommand("clear", RdWebServerCmdDef::CMD_CALLBACK, &lightwallClear);
+    webServer.addCommand("rawfill", RdWebServerCmdDef::CMD_CALLBACK, &lightwallRawFill);
+    webServer.addCommand("fill", RdWebServerCmdDef::CMD_CALLBACK, &lightwallFill);
+    webServer.addCommand("showleds", RdWebServerCmdDef::CMD_CALLBACK, &lightwallShowLeds);
     
     // Start the server
     webServer.init(WEBPORT, &led4, baseWebFolder);
@@ -253,7 +136,7 @@
     getSystemConfig();
 
     // Drawing manager controls the LEDs
-    drawingManager.init(systemNumLEDS, systemLEDSSplitPoint);
+    drawingManager.Init(systemNumLEDS, systemLEDSSplitPoint);
 
     // Setup ethernet interface
     char macAddr[6];
@@ -276,8 +159,8 @@
     // http://robdobson.com/2015/08/a-reliable-mbed-webserver/
     // Fortunately it doesn't matter as the LED code is all interrupt driven
     // This is the previous code...
-    // Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
-    http_thread("");
+    // Thread httpServer(&http_server, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
+    http_server("");
       
     // Forever - actually it won't even get here as the server has a forever loop in it too
     while(true)