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/
main.cpp@5:910909f34907, 2015-09-01 (annotated)
- Committer:
- Bobty
- Date:
- Tue Sep 01 15:53:52 2015 +0000
- Revision:
- 5:910909f34907
- Parent:
- 4:b521815f2657
- Child:
- 6:8df79fe1afcd
Added an idle handler so there is something to show when nothing is being sent over HTTP
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Bobty | 1:362331cec9b7 | 1 | // |
Bobty | 2:99eb4c6e9ea4 | 2 | // LightWall WebServer |
Bobty | 1:362331cec9b7 | 3 | // |
Bobty | 4:b521815f2657 | 4 | // Rob Dobson (C) 2015 |
Bobty | 4:b521815f2657 | 5 | // |
Bobty | 4:b521815f2657 | 6 | // See http://robdobson.com/2015/07/spidey-wall/ and http://robdobson.com/2015/08/a-reliable-mbed-webserver/ |
Bobty | 4:b521815f2657 | 7 | // |
Bobty | 0:887096209439 | 8 | |
Bobty | 0:887096209439 | 9 | #include "mbed.h" |
Bobty | 0:887096209439 | 10 | #include "EthernetInterface.h" |
Bobty | 1:362331cec9b7 | 11 | #include "RdWebServer.h" |
Bobty | 1:362331cec9b7 | 12 | #include "DrawingManager.h" |
Bobty | 5:910909f34907 | 13 | #include "Idler.h" |
Bobty | 0:887096209439 | 14 | #include <string.h> |
Bobty | 1:362331cec9b7 | 15 | |
Bobty | 1:362331cec9b7 | 16 | // Web port |
Bobty | 1:362331cec9b7 | 17 | const int WEBPORT = 80; // Port for web server |
Bobty | 0:887096209439 | 18 | |
Bobty | 1:362331cec9b7 | 19 | // Debugging and status |
Bobty | 1:362331cec9b7 | 20 | RawSerial pc(USBTX, USBRX); |
Bobty | 2:99eb4c6e9ea4 | 21 | DigitalOut led1(LED1); // flashes on command received |
Bobty | 1:362331cec9b7 | 22 | DigitalOut led2(LED2); // |
Bobty | 1:362331cec9b7 | 23 | DigitalOut led3(LED3); // |
Bobty | 1:362331cec9b7 | 24 | DigitalOut led4(LED4); // web server status |
Bobty | 0:887096209439 | 25 | |
Bobty | 2:99eb4c6e9ea4 | 26 | // System configuration |
Bobty | 2:99eb4c6e9ea4 | 27 | char systemName[20] = "LightWall"; |
Bobty | 2:99eb4c6e9ea4 | 28 | int systemNumLEDS = 20; |
Bobty | 2:99eb4c6e9ea4 | 29 | int systemLEDSSplitPoint = systemNumLEDS; |
Bobty | 2:99eb4c6e9ea4 | 30 | |
Bobty | 1:362331cec9b7 | 31 | // Drawing Manager |
Bobty | 2:99eb4c6e9ea4 | 32 | DrawingManager drawingManager; |
Bobty | 0:887096209439 | 33 | |
Bobty | 5:910909f34907 | 34 | // Idler - to display something when not being driven by the web interface |
Bobty | 5:910909f34907 | 35 | Idler idler(&led2, &drawingManager); |
Bobty | 5:910909f34907 | 36 | |
Bobty | 4:b521815f2657 | 37 | // General response string for REST requests |
Bobty | 4:b521815f2657 | 38 | 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"; |
Bobty | 2:99eb4c6e9ea4 | 39 | |
Bobty | 4:b521815f2657 | 40 | // Get system name - No arguments required |
Bobty | 4:b521815f2657 | 41 | char* lightwallGetSystemName(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, |
Bobty | 4:b521815f2657 | 42 | int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos) |
Bobty | 2:99eb4c6e9ea4 | 43 | { |
Bobty | 2:99eb4c6e9ea4 | 44 | // Return the system name |
Bobty | 2:99eb4c6e9ea4 | 45 | return systemName; |
Bobty | 2:99eb4c6e9ea4 | 46 | } |
Bobty | 2:99eb4c6e9ea4 | 47 | |
Bobty | 4:b521815f2657 | 48 | // Clear LEDS - No arguments required |
Bobty | 4:b521815f2657 | 49 | char* lightwallClear(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, |
Bobty | 4:b521815f2657 | 50 | int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos) |
Bobty | 4:b521815f2657 | 51 | { |
Bobty | 5:910909f34907 | 52 | idler.notIdle(); |
Bobty | 4:b521815f2657 | 53 | drawingManager.Clear(); |
Bobty | 4:b521815f2657 | 54 | return generalRespStr; |
Bobty | 4:b521815f2657 | 55 | } |
Bobty | 4:b521815f2657 | 56 | |
Bobty | 4:b521815f2657 | 57 | // RawFill - arguments for start LED (e.g. /rawfill?start=0) |
Bobty | 4:b521815f2657 | 58 | // - payload of message contains binary data for RGB (1 byte for each) for each LED to be set |
Bobty | 4:b521815f2657 | 59 | char* lightwallRawFill(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, |
Bobty | 4:b521815f2657 | 60 | int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos) |
Bobty | 4:b521815f2657 | 61 | { |
Bobty | 5:910909f34907 | 62 | idler.notIdle(); |
Bobty | 4:b521815f2657 | 63 | drawingManager.RawFill(argStr, pPayload, payloadLen, splitPayloadPos); |
Bobty | 4:b521815f2657 | 64 | return generalRespStr; |
Bobty | 4:b521815f2657 | 65 | } |
Bobty | 4:b521815f2657 | 66 | |
Bobty | 4:b521815f2657 | 67 | // Fill - arguments for start, numLeds, initial-R/G/B and ending-R/G/B (optional) |
Bobty | 4:b521815f2657 | 68 | // - e.g. /fill?start=0&len=100&r1=20&g1=30&b1=50 |
Bobty | 4:b521815f2657 | 69 | // - e.g. /fill?start=0&len=100&r1=20&g1=30&b1=50&r2=50&g2=100&b2=23 |
Bobty | 4:b521815f2657 | 70 | char* lightwallFill(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, |
Bobty | 4:b521815f2657 | 71 | int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos) |
Bobty | 4:b521815f2657 | 72 | { |
Bobty | 5:910909f34907 | 73 | idler.notIdle(); |
Bobty | 4:b521815f2657 | 74 | drawingManager.Fill(argStr); |
Bobty | 4:b521815f2657 | 75 | return generalRespStr; |
Bobty | 4:b521815f2657 | 76 | } |
Bobty | 4:b521815f2657 | 77 | |
Bobty | 4:b521815f2657 | 78 | // ShowLeds - no arguments |
Bobty | 4:b521815f2657 | 79 | char* lightwallShowLeds(int method, char*cmdStr, char* argStr, char* msgBuffer, int msgLen, |
Bobty | 4:b521815f2657 | 80 | int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos) |
Bobty | 4:b521815f2657 | 81 | { |
Bobty | 4:b521815f2657 | 82 | // Blink LED |
Bobty | 4:b521815f2657 | 83 | led1 = !led1; |
Bobty | 4:b521815f2657 | 84 | // Show LEDS |
Bobty | 5:910909f34907 | 85 | idler.notIdle(); |
Bobty | 4:b521815f2657 | 86 | drawingManager.ShowLeds(); |
Bobty | 4:b521815f2657 | 87 | return generalRespStr; |
Bobty | 4:b521815f2657 | 88 | } |
Bobty | 4:b521815f2657 | 89 | |
Bobty | 1:362331cec9b7 | 90 | // Create, configure and run the web server |
Bobty | 4:b521815f2657 | 91 | void http_server(void const* arg) |
Bobty | 0:887096209439 | 92 | { |
Bobty | 2:99eb4c6e9ea4 | 93 | // Init the web server |
Bobty | 1:362331cec9b7 | 94 | pc.printf("Starting web server\r\n"); |
Bobty | 1:362331cec9b7 | 95 | char* baseWebFolder = "/sd/"; // should be /sd/ for SDcard files - not used for local file system |
Bobty | 1:362331cec9b7 | 96 | RdWebServer webServer; |
Bobty | 2:99eb4c6e9ea4 | 97 | |
Bobty | 2:99eb4c6e9ea4 | 98 | // Add commands to handle the home page and favicon |
Bobty | 1:362331cec9b7 | 99 | webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, "index.htm", true); |
Bobty | 1:362331cec9b7 | 100 | webServer.addCommand("favicon.ico", RdWebServerCmdDef::CMD_LOCALFILE, NULL, NULL, true); |
Bobty | 2:99eb4c6e9ea4 | 101 | |
Bobty | 2:99eb4c6e9ea4 | 102 | // Add the lightwall control commands |
Bobty | 2:99eb4c6e9ea4 | 103 | webServer.addCommand("name", RdWebServerCmdDef::CMD_CALLBACK, &lightwallGetSystemName); |
Bobty | 4:b521815f2657 | 104 | webServer.addCommand("clear", RdWebServerCmdDef::CMD_CALLBACK, &lightwallClear); |
Bobty | 4:b521815f2657 | 105 | webServer.addCommand("rawfill", RdWebServerCmdDef::CMD_CALLBACK, &lightwallRawFill); |
Bobty | 4:b521815f2657 | 106 | webServer.addCommand("fill", RdWebServerCmdDef::CMD_CALLBACK, &lightwallFill); |
Bobty | 4:b521815f2657 | 107 | webServer.addCommand("showleds", RdWebServerCmdDef::CMD_CALLBACK, &lightwallShowLeds); |
Bobty | 2:99eb4c6e9ea4 | 108 | |
Bobty | 2:99eb4c6e9ea4 | 109 | // Start the server |
Bobty | 1:362331cec9b7 | 110 | webServer.init(WEBPORT, &led4, baseWebFolder); |
Bobty | 1:362331cec9b7 | 111 | webServer.run(); |
Bobty | 0:887096209439 | 112 | } |
Bobty | 0:887096209439 | 113 | |
Bobty | 2:99eb4c6e9ea4 | 114 | void getSystemConfig() |
Bobty | 2:99eb4c6e9ea4 | 115 | { |
Bobty | 2:99eb4c6e9ea4 | 116 | printf("LightWall - Configured for "); |
Bobty | 2:99eb4c6e9ea4 | 117 | // Check for a config file on the local file system |
Bobty | 2:99eb4c6e9ea4 | 118 | LocalFileSystem local("local"); |
Bobty | 2:99eb4c6e9ea4 | 119 | FILE* fp = fopen("/local/lights.txt", "r"); |
Bobty | 2:99eb4c6e9ea4 | 120 | if (fp != NULL) |
Bobty | 2:99eb4c6e9ea4 | 121 | { |
Bobty | 2:99eb4c6e9ea4 | 122 | char buf[201]; |
Bobty | 2:99eb4c6e9ea4 | 123 | buf[sizeof(buf)-1] = 0; |
Bobty | 2:99eb4c6e9ea4 | 124 | int nread = fread(buf, 1, sizeof(buf), fp); |
Bobty | 2:99eb4c6e9ea4 | 125 | if (nread > 0 && nread <= sizeof(buf)) |
Bobty | 2:99eb4c6e9ea4 | 126 | { |
Bobty | 2:99eb4c6e9ea4 | 127 | buf[nread] = 0; |
Bobty | 2:99eb4c6e9ea4 | 128 | // Read config details from the file |
Bobty | 2:99eb4c6e9ea4 | 129 | sscanf(buf, "%s %d %d", systemName, &systemNumLEDS, &systemLEDSSplitPoint); |
Bobty | 2:99eb4c6e9ea4 | 130 | } |
Bobty | 2:99eb4c6e9ea4 | 131 | fclose(fp); |
Bobty | 2:99eb4c6e9ea4 | 132 | printf("%s (%d LEDs, Split at %d)", systemName, systemNumLEDS, systemLEDSSplitPoint); |
Bobty | 2:99eb4c6e9ea4 | 133 | printf("\r\n"); |
Bobty | 2:99eb4c6e9ea4 | 134 | } |
Bobty | 2:99eb4c6e9ea4 | 135 | } |
Bobty | 2:99eb4c6e9ea4 | 136 | |
Bobty | 1:362331cec9b7 | 137 | int main() |
Bobty | 0:887096209439 | 138 | { |
Bobty | 1:362331cec9b7 | 139 | // Init |
Bobty | 1:362331cec9b7 | 140 | pc.baud(115200); |
Bobty | 1:362331cec9b7 | 141 | pc.printf("Light Wall - Rob Dobson 2015\r\n"); |
Bobty | 5:910909f34907 | 142 | |
Bobty | 2:99eb4c6e9ea4 | 143 | // Get the configuration of the system |
Bobty | 2:99eb4c6e9ea4 | 144 | getSystemConfig(); |
Bobty | 2:99eb4c6e9ea4 | 145 | |
Bobty | 2:99eb4c6e9ea4 | 146 | // Drawing manager controls the LEDs |
Bobty | 4:b521815f2657 | 147 | drawingManager.Init(systemNumLEDS, systemLEDSSplitPoint); |
Bobty | 1:362331cec9b7 | 148 | |
Bobty | 1:362331cec9b7 | 149 | // Setup ethernet interface |
Bobty | 1:362331cec9b7 | 150 | char macAddr[6]; |
Bobty | 1:362331cec9b7 | 151 | mbed_mac_address(macAddr); |
Bobty | 1:362331cec9b7 | 152 | 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]); |
Bobty | 1:362331cec9b7 | 153 | pc.printf("Connecting to ethernet ...\r\n"); |
Bobty | 5:910909f34907 | 154 | |
Bobty | 3:e5ea80fae61d | 155 | // Init ethernet |
Bobty | 1:362331cec9b7 | 156 | EthernetInterface::init(); |
Bobty | 1:362331cec9b7 | 157 | |
Bobty | 3:e5ea80fae61d | 158 | // Using code described here https://developer.mbed.org/questions/1602/How-to-set-the-TCPIP-stack-s-hostname-pr/ |
Bobty | 3:e5ea80fae61d | 159 | // to setName on the ethernet interface |
Bobty | 3:e5ea80fae61d | 160 | EthernetInterface::setName(systemName); |
Bobty | 5:910909f34907 | 161 | |
Bobty | 3:e5ea80fae61d | 162 | // Connect ethernet |
Bobty | 3:e5ea80fae61d | 163 | EthernetInterface::connect(); |
Bobty | 3:e5ea80fae61d | 164 | pc.printf("IP Address: %s HostName %s\r\n", EthernetInterface::getIPAddress(), EthernetInterface::getName()); |
Bobty | 3:e5ea80fae61d | 165 | |
Bobty | 3:e5ea80fae61d | 166 | // Web Server used to run in a thread - but I've found this slows performance a lot as described here: |
Bobty | 3:e5ea80fae61d | 167 | // http://robdobson.com/2015/08/a-reliable-mbed-webserver/ |
Bobty | 3:e5ea80fae61d | 168 | // Fortunately it doesn't matter as the LED code is all interrupt driven |
Bobty | 3:e5ea80fae61d | 169 | // This is the previous code... |
Bobty | 4:b521815f2657 | 170 | // Thread httpServer(&http_server, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3)); |
Bobty | 4:b521815f2657 | 171 | http_server(""); |
Bobty | 5:910909f34907 | 172 | |
Bobty | 3:e5ea80fae61d | 173 | // Forever - actually it won't even get here as the server has a forever loop in it too |
Bobty | 1:362331cec9b7 | 174 | while(true) |
Bobty | 1:362331cec9b7 | 175 | { |
Bobty | 1:362331cec9b7 | 176 | } |
Bobty | 0:887096209439 | 177 | } |