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:
Thu Sep 03 20:17:23 2015 +0000
Parent:
5:910909f34907
Commit message:
Fixed an unforeseen problem with messages not aligned on RGB boundaries; Fixed potential hanging pointer problem in colourconverters; Changed Idle screen to a set of colourful snakes

Changed in this revision

DrawingManager.cpp Show annotated file Show diff for this revision Revisions of this file
DrawingManager.h Show annotated file Show diff for this revision Revisions of this file
Idler.cpp Show annotated file Show diff for this revision Revisions of this file
Idler.h Show annotated file Show diff for this revision Revisions of this file
colourconverters.cpp Show annotated file Show diff for this revision Revisions of this file
colourconverters.h 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
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/DrawingManager.cpp	Tue Sep 01 15:53:52 2015 +0000
+++ b/DrawingManager.cpp	Thu Sep 03 20:17:23 2015 +0000
@@ -11,6 +11,7 @@
 {
     pLedStrip = NULL;
     isBusy = false;
+    rawFillPayloadOverhangBytes = 0;
 }
 
 void DrawingManager::Init(int numLeds, int splitPoint)
@@ -35,10 +36,28 @@
     int startLed = GetIntFromNameValPair(args, "start=", -1);
     if (startLed != -1 && payloadLen > 0)
     {
-        int numLeds = payloadLen / 3;
+        // Include any overhang bytes from the last payload
+        int numLeds = (rawFillPayloadOverhangBytes + payloadLen) / 3;
         int fromLed = startLed + (payloadOffset / 3);
+        unsigned char newPayload[numLeds*3];
+        memcpy(newPayload, pRawFillPayloadOverhang, rawFillPayloadOverhangBytes);
+        memcpy(newPayload+rawFillPayloadOverhangBytes, payload, numLeds*3-rawFillPayloadOverhangBytes);
+        
+        // Send the data
 //        printf("RAWFILL fromLed %d numLeds %d\r\n", fromLed, numLeds);
-        pLedStrip->RawFill(fromLed, numLeds, payload);
+//        for (int i = 0; i < numLeds*3; i+=3)
+//        {
+//            printf("%02x %02x %02x\r\n", newPayload[i], newPayload[i+1], newPayload[i+2]);
+//        }
+        pLedStrip->RawFill(fromLed, numLeds, newPayload);
+
+        // Save any overhanging bytes for the next fill
+        int overhangStart = (numLeds * 3) - rawFillPayloadOverhangBytes;
+        rawFillPayloadOverhangBytes = rawFillPayloadOverhangBytes + payloadLen - (numLeds * 3);
+        for (int i = 0; i < rawFillPayloadOverhangBytes; i++)
+        {
+            pRawFillPayloadOverhang[i] = payload[overhangStart + i];
+        }
     }
 }
 
@@ -65,6 +84,7 @@
 void DrawingManager::ShowLeds()
 {
 //    printf("SHOWLEDS\r\n");
+    rawFillPayloadOverhangBytes = 0;
     if (pLedStrip)
         pLedStrip->ShowLeds();
 }
@@ -77,12 +97,22 @@
     if (pLedStrip->IsBusy())
         return;
     pLedStrip->Clear();
-    int ledsPerGroup = pLedStrip->GetNumLeds() / 10;
-    for (int i = 0; i < pLedStrip->GetNumLeds(); i += ledsPerGroup)
+    int numSnakes = 15;
+    int ledsPerGroup = pLedStrip->GetNumLeds() / numSnakes;
+    int snakeLen = 10;
+    int snakeStep = stepCount % ledsPerGroup;
+    int colrBase = (stepCount / ledsPerGroup);
+    // Create a set of colourful snakes that roam around the wall
+    for (int i = 0; i < numSnakes; i ++)
     {
-        RgbColor colrVal((stepCount * 7) + (i * 23) % 64, (stepCount * 17) + 77 + (i * 3) % 64, (stepCount * 37) + 117 + (i * 13) % 64);
-        RgbColor colrVal2((stepCount * 17) + (i * 33) % 64, (stepCount * 3) + 13 + (i * 13) % 64, (stepCount * 77) + 11 + (i * 23) % 64);
-        pLedStrip->Fill(i,ledsPerGroup,colrVal.r, colrVal.g, colrVal.b, colrVal2.r, colrVal2.g, colrVal2.b);
+        HsvColor hsv1(((colrBase + i) * 237) % 255, 128, 10);
+        RgbColor rgb1(0,0,0);
+        HsvToRgb(hsv1, rgb1);
+        HsvColor hsv2(((colrBase + i + 27) * 13) % 255, 255, 255);
+        RgbColor rgb2(0,0,0);
+        HsvToRgb(hsv2, rgb2);
+        pLedStrip->Fill((i*ledsPerGroup)+snakeStep,snakeLen/2, rgb1.r, rgb1.g, rgb1.b, rgb2.r, rgb2.g, rgb2.b);
+        pLedStrip->Fill((i*ledsPerGroup)+snakeStep+snakeLen/2, snakeLen/2, rgb2.r, rgb2.g, rgb2.b, rgb1.r, rgb1.g, rgb1.b);
     }
     pLedStrip->ShowLeds();
 }
--- a/DrawingManager.h	Tue Sep 01 15:53:52 2015 +0000
+++ b/DrawingManager.h	Thu Sep 03 20:17:23 2015 +0000
@@ -24,6 +24,8 @@
     ledstrip* pLedStrip;
     bool isBusy;
     int GetIntFromNameValPair(char* buf, char* name, int invalidVal);
+    unsigned char pRawFillPayloadOverhang[2];
+    int rawFillPayloadOverhangBytes;
 };
 
 #endif
--- a/Idler.cpp	Tue Sep 01 15:53:52 2015 +0000
+++ b/Idler.cpp	Thu Sep 03 20:17:23 2015 +0000
@@ -2,6 +2,7 @@
 #include "Idler.h"
 
 DigitalOut* Idler::_pStatusLed = NULL;
+bool Idler::_isRunning = false;
 bool Idler::_isIdle = true;
 unsigned int Idler::_stepCount = 0;
 DrawingManager* Idler::_pDrawingManager = NULL;
@@ -17,8 +18,17 @@
     _idleTicker.attach(&tick, 0.1);
 }
 
+void Idler::start()
+{
+    _isRunning = true;
+}
+
 void Idler::tick()
 {
+    // Check if we are running
+    if (!_isRunning)
+        return;
+        
     // Check if idle
     if (!_isIdle)
     {
--- a/Idler.h	Tue Sep 01 15:53:52 2015 +0000
+++ b/Idler.h	Thu Sep 03 20:17:23 2015 +0000
@@ -11,9 +11,11 @@
         static void tick();
         static void notIdle();
         static void displayStep();
+        static void start();
         
     private:
         static DigitalOut* _pStatusLed;
+        static bool _isRunning;
         static bool _isIdle;
         static unsigned int _stepCount;
         static DrawingManager* _pDrawingManager;
--- a/colourconverters.cpp	Tue Sep 01 15:53:52 2015 +0000
+++ b/colourconverters.cpp	Thu Sep 03 20:17:23 2015 +0000
@@ -1,8 +1,7 @@
 #include "colourconverters.h"
 
-RgbColor HsvToRgb(HsvColor hsv)
+void HsvToRgb(HsvColor hsv, RgbColor& rgb)
 {
-    RgbColor rgb(0,0,0);
     unsigned char region, remainder, p, q, t;
 
     if (hsv.s == 0)
@@ -10,7 +9,7 @@
         rgb.r = hsv.v;
         rgb.g = hsv.v;
         rgb.b = hsv.v;
-        return rgb;
+        return;
     }
 
     region = hsv.h / 43;
@@ -41,13 +40,10 @@
             rgb.r = hsv.v; rgb.g = p; rgb.b = q;
             break;
     }
-
-    return rgb;
 }
 
-HsvColor RgbToHsv(RgbColor rgb)
+void RgbToHsv(RgbColor rgb, HsvColor& hsv)
 {
-    HsvColor hsv(0,0,0);
     unsigned char rgbMin, rgbMax;
 
     rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
@@ -58,14 +54,14 @@
     {
         hsv.h = 0;
         hsv.s = 0;
-        return hsv;
+        return;
     }
 
     hsv.s = 255 * long(rgbMax - rgbMin) / hsv.v;
     if (hsv.s == 0)
     {
         hsv.h = 0;
-        return hsv;
+        return;
     }
 
     if (rgbMax == rgb.r)
@@ -74,6 +70,4 @@
         hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
     else
         hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
-
-    return hsv;
 }
--- a/colourconverters.h	Tue Sep 01 15:53:52 2015 +0000
+++ b/colourconverters.h	Thu Sep 03 20:17:23 2015 +0000
@@ -30,8 +30,8 @@
 
 } HsvColor;
 
-RgbColor HsvToRgb(HsvColor hsv);
+void HsvToRgb(HsvColor hsv, RgbColor& rgb);
 
-HsvColor RgbToHsv(RgbColor rgb);
+void RgbToHsv(RgbColor rgb, HsvColor& hsv);
 
 #endif
--- a/ledstrip.cpp	Tue Sep 01 15:53:52 2015 +0000
+++ b/ledstrip.cpp	Thu Sep 03 20:17:23 2015 +0000
@@ -160,7 +160,8 @@
     // 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));
+        RgbColor colrVal(0,0,0);
+        HsvToRgb(HsvColor(pLedVals[0],pLedVals[1] & 0xf0, (pLedVals[1] << 4) & 0xf0), colrVal);
         pBuf[pos] = colrVal.r;
         pBuf[pos+1] = colrVal.g;
         pBuf[pos+2] = colrVal.b;
@@ -209,9 +210,11 @@
         numLeds = mLedsInStrip - startLed;
     int pos = startLed * mColoursPerLed;
     RgbColor startRGB(r1,g1,b1);
-    HsvColor startHsv = RgbToHsv(startRGB);
+    HsvColor startHsv(0,0,0);
+    RgbToHsv(startRGB, startHsv);
     RgbColor endRGB(r2,g2,b2);
-    HsvColor endHsv = RgbToHsv(endRGB);
+    HsvColor endHsv(0,0,0);
+    RgbToHsv(endRGB, endHsv);
     int curH = startHsv.h << 16;
     int curS = startHsv.s << 16;
     int curV = startHsv.v << 16;
@@ -238,7 +241,8 @@
     unsigned char* pBuf = GetBuffer();
     for (int i = 0; i < numLeds; i++)
     {
-        RgbColor colrVal = HsvToRgb(HsvColor((curH>>16)&0xff,curS>>16,curV>>16));
+        RgbColor colrVal(0,0,0);
+        HsvToRgb(HsvColor((curH>>16)&0xff,curS>>16,curV>>16), colrVal);
         pBuf[pos] = colrVal.r;
         pBuf[pos+1] = colrVal.g;
         pBuf[pos+2] = colrVal.b;
--- a/main.cpp	Tue Sep 01 15:53:52 2015 +0000
+++ b/main.cpp	Thu Sep 03 20:17:23 2015 +0000
@@ -139,13 +139,19 @@
     // Init
     pc.baud(115200);
     pc.printf("Light Wall - Rob Dobson 2015\r\n");
+    
+    // Wait for a moment
+    wait(1);
 
     // Get the configuration of the system
     getSystemConfig();
-
+    
     // Drawing manager controls the LEDs
     drawingManager.Init(systemNumLEDS, systemLEDSSplitPoint);
 
+    // Start idler
+    idler.start();
+        
     // Setup ethernet interface
     char macAddr[6];
     mbed_mac_address(macAddr);