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/
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 6:8df79fe1afcd, committed 2015-09-03
- 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
diff -r 910909f34907 -r 8df79fe1afcd DrawingManager.cpp --- 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(); }
diff -r 910909f34907 -r 8df79fe1afcd DrawingManager.h --- 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
diff -r 910909f34907 -r 8df79fe1afcd Idler.cpp --- 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) {
diff -r 910909f34907 -r 8df79fe1afcd Idler.h --- 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;
diff -r 910909f34907 -r 8df79fe1afcd colourconverters.cpp --- 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; }
diff -r 910909f34907 -r 8df79fe1afcd colourconverters.h --- 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
diff -r 910909f34907 -r 8df79fe1afcd ledstrip.cpp --- 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;
diff -r 910909f34907 -r 8df79fe1afcd main.cpp --- 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);