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 5:910909f34907, committed 2015-09-01
- Comitter:
- Bobty
- Date:
- Tue Sep 01 15:53:52 2015 +0000
- Parent:
- 4:b521815f2657
- Child:
- 6:8df79fe1afcd
- Commit message:
- Added an idle handler so there is something to show when nothing is being sent over HTTP
Changed in this revision
--- a/DrawingManager.cpp Mon Aug 31 15:21:47 2015 +0000
+++ b/DrawingManager.cpp Tue Sep 01 15:53:52 2015 +0000
@@ -5,6 +5,7 @@
#include "DrawingManager.h"
#include "rtos.h"
+#include "colourconverters.h"
DrawingManager::DrawingManager()
{
@@ -68,6 +69,24 @@
pLedStrip->ShowLeds();
}
+void DrawingManager::DisplayIdle(unsigned int stepCount)
+{
+ // Display a step in an auto sequence
+ if (!pLedStrip)
+ return;
+ if (pLedStrip->IsBusy())
+ return;
+ pLedStrip->Clear();
+ int ledsPerGroup = pLedStrip->GetNumLeds() / 10;
+ for (int i = 0; i < pLedStrip->GetNumLeds(); i += ledsPerGroup)
+ {
+ 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);
+ }
+ pLedStrip->ShowLeds();
+}
+
int DrawingManager::GetIntFromNameValPair(char* buf, char* name, int invalidVal)
{
int val = invalidVal;
@@ -76,3 +95,4 @@
val = atoi(pFnd + strlen(name));
return val;
}
+
--- a/DrawingManager.h Mon Aug 31 15:21:47 2015 +0000
+++ b/DrawingManager.h Tue Sep 01 15:53:52 2015 +0000
@@ -18,7 +18,7 @@
void RawFill(char* args, unsigned char* payload, int payloadLen, int payloadOffset);
void Fill(char* args);
void ShowLeds();
-
+ void DisplayIdle(unsigned int stepCount);
private:
ledstrip* pLedStrip;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Idler.cpp Tue Sep 01 15:53:52 2015 +0000
@@ -0,0 +1,49 @@
+
+#include "Idler.h"
+
+DigitalOut* Idler::_pStatusLed = NULL;
+bool Idler::_isIdle = true;
+unsigned int Idler::_stepCount = 0;
+DrawingManager* Idler::_pDrawingManager = NULL;
+Ticker Idler::_idleTicker;
+Timer Idler::_idleTimer;
+
+const int IDLE_TIMEOUT = 10; // N seconds of no REST commands -> idle
+
+Idler::Idler(DigitalOut* pStatusLed, DrawingManager* pDrawingManager)
+{
+ _pStatusLed = pStatusLed;
+ _pDrawingManager = pDrawingManager;
+ _idleTicker.attach(&tick, 0.1);
+}
+
+void Idler::tick()
+{
+ // Check if idle
+ if (!_isIdle)
+ {
+ // Check time since last notIdle
+ if (_idleTimer.read() < IDLE_TIMEOUT)
+ return;
+
+ // Now idle again
+ _idleTimer.stop();
+ _isIdle = true;
+ }
+
+ // Blink LED
+ *_pStatusLed = !(*_pStatusLed);
+
+ // Step through display
+ _pDrawingManager->DisplayIdle(_stepCount);
+ _stepCount++;
+}
+
+void Idler::notIdle()
+{
+ _isIdle = false;
+ *_pStatusLed = false;
+ _idleTimer.reset();
+ _idleTimer.start();
+ _stepCount = 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Idler.h Tue Sep 01 15:53:52 2015 +0000
@@ -0,0 +1,25 @@
+#ifndef IDLER__H
+#define IDLER__H
+
+#include "mbed.h"
+#include "DrawingManager.h"
+
+class Idler
+{
+ public:
+ Idler(DigitalOut* pStatusLed, DrawingManager* pDrawingManager);
+ static void tick();
+ static void notIdle();
+ static void displayStep();
+
+ private:
+ static DigitalOut* _pStatusLed;
+ static bool _isIdle;
+ static unsigned int _stepCount;
+ static DrawingManager* _pDrawingManager;
+ static Ticker _idleTicker;
+ static Timer _idleTimer;
+
+};
+
+#endif
--- a/main.cpp Mon Aug 31 15:21:47 2015 +0000
+++ b/main.cpp Tue Sep 01 15:53:52 2015 +0000
@@ -10,6 +10,7 @@
#include "EthernetInterface.h"
#include "RdWebServer.h"
#include "DrawingManager.h"
+#include "Idler.h"
#include <string.h>
// Web port
@@ -30,6 +31,9 @@
// Drawing Manager
DrawingManager drawingManager;
+// Idler - to display something when not being driven by the web interface
+Idler idler(&led2, &drawingManager);
+
// 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";
@@ -45,6 +49,7 @@
char* lightwallClear(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen,
int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
{
+ idler.notIdle();
drawingManager.Clear();
return generalRespStr;
}
@@ -54,6 +59,7 @@
char* lightwallRawFill(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen,
int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
{
+ idler.notIdle();
drawingManager.RawFill(argStr, pPayload, payloadLen, splitPayloadPos);
return generalRespStr;
}
@@ -64,6 +70,7 @@
char* lightwallFill(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen,
int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
{
+ idler.notIdle();
drawingManager.Fill(argStr);
return generalRespStr;
}
@@ -75,6 +82,7 @@
// Blink LED
led1 = !led1;
// Show LEDS
+ idler.notIdle();
drawingManager.ShowLeds();
return generalRespStr;
}
@@ -131,7 +139,7 @@
// Init
pc.baud(115200);
pc.printf("Light Wall - Rob Dobson 2015\r\n");
-
+
// Get the configuration of the system
getSystemConfig();
@@ -143,14 +151,14 @@
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();
// 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);
-
+
// Connect ethernet
EthernetInterface::connect();
pc.printf("IP Address: %s HostName %s\r\n", EthernetInterface::getIPAddress(), EthernetInterface::getName());
@@ -161,7 +169,7 @@
// This is the previous code...
// 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)
{