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/
Diff: main.cpp
- Revision:
- 4:b521815f2657
- Parent:
- 3:e5ea80fae61d
- Child:
- 5:910909f34907
diff -r e5ea80fae61d -r b521815f2657 main.cpp --- 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)