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/

Files at this revision

API Documentation at this revision

Comitter:
Bobty
Date:
Mon Aug 31 09:03:15 2015 +0000
Parent:
2:99eb4c6e9ea4
Child:
4:b521815f2657
Commit message:
Made ShowLeds an explicit command rather than automatic; Allow hostname to be set; Made sure HTTP response has keep-alive in it; Moved http_server into main loop (was in a separate thread); Added HSV fill command

Changed in this revision

DrawingManager.cpp Show annotated file Show diff for this revision Revisions of this file
EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
RdWebServer.lib Show annotated file Show diff for this revision Revisions of this file
cmdmsg.cpp Show annotated file Show diff for this revision Revisions of this file
ledstrip.cpp Show annotated file Show diff for this revision Revisions of this file
ledstrip.h 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
--- a/DrawingManager.cpp	Sat Aug 29 05:33:30 2015 +0000
+++ b/DrawingManager.cpp	Mon Aug 31 09:03:15 2015 +0000
@@ -29,7 +29,6 @@
         return "BUSY";
     isBusy = true;
     char* respStr = cmdmsg::Interpret(cmdBuf, cmdLen, pLedStrip);
-    pLedStrip->ShowLeds();
     isBusy = false;
     return respStr;
 }
--- a/EthernetInterface.lib	Sat Aug 29 05:33:30 2015 +0000
+++ b/EthernetInterface.lib	Mon Aug 31 09:03:15 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/EthernetInterface/#2fc406e2553f
+http://mbed.org/users/mbed_official/code/EthernetInterface/#8e692841213c
--- a/RdWebServer.lib	Sat Aug 29 05:33:30 2015 +0000
+++ b/RdWebServer.lib	Mon Aug 31 09:03:15 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/Bobty/code/RdWebServer/#2dfb56648b93
+http://mbed.org/users/Bobty/code/RdWebServer/#0fc3d7b5e596
--- a/cmdmsg.cpp	Sat Aug 29 05:33:30 2015 +0000
+++ b/cmdmsg.cpp	Mon Aug 31 09:03:15 2015 +0000
@@ -32,6 +32,7 @@
     (COD & 0x7f) ....
     0x01:
         Clear the entire strip
+        There are no parameters
     0x02:
         Fill a series of leds with RGB values
         <PARAMS> := <START><NUM><RGB1><RGB2>
@@ -85,6 +86,21 @@
             <LINKNUMLEDS> is the number of LEDs to control (1 byte)
             <LINKRGB> is the colour to make the link LEDs (3 bytes)
         
+    0x08:
+        Raw HSV values for a series of leds
+        <PARAMS> := <START><NUM><HSV1><HSV2><HSV3>....<HSVn>
+        Where:
+            <START> is a two byte value (bigendian) for led to start series
+            <NUM> is a two byte (bigendian) number of leds to set
+            <HSV1> is the RGB value for 1st LED (16bits) - first 8 bits = H, upper 4 (bigendian) = S / 16, lower 4 = V / 16
+            <HSV2> is the RGB value for 2nd LED
+            <HSVn> is the RGB value for nth LED
+            
+    0x09:
+        ShowLeds
+        Until this command is sent all other commands simply "paint" into the buffer and don't actually change the LEDs
+        There are no parameters
+
 */
 
 #ifdef USE_SPIDEY_GEOM
@@ -301,6 +317,34 @@
 #endif
                 break;
             }
+            case 0x08: // Raw HSV 
+            {
+                if (paramsLen > 4)
+                {
+                    int startLed = (msg[0] * 256) + msg[1];
+                    int numLeds = (msg[2] * 256) + msg[3];
+                    if (paramsLen >= numLeds * 2 + 4)
+                    {
+                        pLedStrip->HsvFill(startLed, numLeds, msg+4);
+//                        printf("R Q%04x S%d N%d Pa%d\r\n", seqCount, startLed, numLeds, paramsLen);
+                    }
+                    else
+                    {
+                        sprintf(responseStr, "%04x HSV FILL - BufLengthMismatch %d", seqCount, paramsLen);
+                    }
+                }
+                else
+                {
+                    sprintf(responseStr, "%04x HSV FILL - ParamsLen Error %d", seqCount, paramsLen);            
+                }
+                break;
+            }
+            case 0x09: // ShowLeds
+            {
+//                printf("ShowLeds - nextbyte %d\r\n", msg[0]);
+                pLedStrip->ShowLeds();
+                break;
+            }
             default:
             {
                 sprintf(responseStr, "%04x CMD %02x UNKNOWN", seqCount, cmdCode);
--- a/ledstrip.cpp	Sat Aug 29 05:33:30 2015 +0000
+++ b/ledstrip.cpp	Mon Aug 31 09:03:15 2015 +0000
@@ -146,6 +146,28 @@
     unsigned char* pBuf = GetBuffer() + pos;
     memcpy(pBuf, pLedVals, numLeds * mColoursPerLed);
 }
+
+void ledstrip::HsvFill(int startLed, int numLeds, const unsigned char* pLedVals)
+{
+    if ((startLed < 0) || (startLed >= mLedsInStrip))
+        return;
+    if (numLeds >= mLedsInStrip - startLed)
+        numLeds = mLedsInStrip - startLed;
+    int pos = startLed * mColoursPerLed;
+    unsigned char* pBuf = GetBuffer() + pos;
+    
+    // Copy over the values converting each to RGB
+    for (int i = 0; i < numLeds; i++)
+    {
+        RgbColor colrVal = HsvToRgb(HsvColor(pLedVals[0],pLedVals[1] & 0xf0, (pLedVals[1] << 4) & 0xf0));
+        pBuf[pos] = colrVal.r;
+        pBuf[pos+1] = colrVal.g;
+        pBuf[pos+2] = colrVal.b;
+//        printf("HSV %d %d %d RGB %d %d %d\r\n", pLedVals[0],pLedVals[1] & 0xf0, (pLedVals[1] << 4) & 0xf0, colrVal.r, colrVal.g, colrVal.b);
+        pos += mColoursPerLed;
+        pLedVals += 2;
+    }
+}
     
 // Fill - solid colour
 void ledstrip::Fill(int startLed, int numLeds, 
@@ -236,7 +258,7 @@
     // Check if busy
     while (isr0Busy || isr1Busy)
         wait_us(2000);
-    wait_us(2000);
+//    wait_us(2000);
     
     // Set up start points
     mCurPos0 = 0;
--- a/ledstrip.h	Sat Aug 29 05:33:30 2015 +0000
+++ b/ledstrip.h	Mon Aug 31 09:03:15 2015 +0000
@@ -31,6 +31,7 @@
         }
         void Clear();
         void RawFill(int startLed, int numLeds, const unsigned char* pLedVals);
+        void HsvFill(int startLed, int numLeds, const unsigned char* pLedVals);
         void Fill(int startLed, int numLeds, 
                 int r1, int g1, int b1, 
                 int r2, int g2, int b2);
--- a/main.cpp	Sat Aug 29 05:33:30 2015 +0000
+++ b/main.cpp	Mon Aug 31 09:03:15 2015 +0000
@@ -180,11 +180,15 @@
     // Get message payload
     int cmdLen = RdWebServer::getPayloadLengthFromMsg(msgBuf);
     unsigned char* cmdBuf = RdWebServer::getPayloadDataFromMsg(msgBuf);
-    pc.printf("Command Payload Len %d\r\n", cmdLen);
-
-    // Process command
-    char* respStr = "";
-    respStr = drawingManager.start(cmdBuf, cmdLen);
+    
+    // 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;
 }
 
@@ -220,7 +224,6 @@
 {
     printf("LightWall - Configured for ");
     // Check for a config file on the local file system
-    strcpy(systemName, "Spidey");
     LocalFileSystem local("local");
     FILE* fp = fopen("/local/lights.txt", "r");
     if (fp != NULL)
@@ -257,17 +260,27 @@
     mbed_mac_address(macAddr);
     pc.printf("Ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\r\n", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]); 
     pc.printf("Connecting to ethernet ...\r\n");
+    
+    // Init ethernet
     EthernetInterface::init();
-    EthernetInterface::connect();
-    pc.printf("IP Address: %s\r\n", EthernetInterface::getIPAddress());
 
-    // Web Server
-    Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
+    // Using code described here https://developer.mbed.org/questions/1602/How-to-set-the-TCPIP-stack-s-hostname-pr/
+    // to setName on the ethernet interface
+    EthernetInterface::setName(systemName);
     
-    // Forever
+    // Connect ethernet
+    EthernetInterface::connect();
+    pc.printf("IP Address: %s HostName %s\r\n", EthernetInterface::getIPAddress(), EthernetInterface::getName());
+
+    // Web Server used to run in a thread - but I've found this slows performance a lot as described here:
+    // 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("");
+      
+    // Forever - actually it won't even get here as the server has a forever loop in it too
     while(true)
     {
-        // Service drawing manager
-        drawingManager.service();
     }
 }