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/

Committer:
Bobty
Date:
Mon Aug 31 09:03:15 2015 +0000
Revision:
3:e5ea80fae61d
Parent:
2:99eb4c6e9ea4
Child:
4:b521815f2657
Made ShowLeds an explicit command rather than automatic; Allow hostname to be set; Made sure HTTP response has keep-alive in it; Moved http_server into main loop (was in a separate thread); Added HSV fill command

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Bobty 1:362331cec9b7 1 //
Bobty 2:99eb4c6e9ea4 2 // LightWall WebServer
Bobty 1:362331cec9b7 3 //
Bobty 1:362331cec9b7 4 // Rob Dobson 2015
Bobty 0:887096209439 5
Bobty 0:887096209439 6 #include "mbed.h"
Bobty 0:887096209439 7 #include "EthernetInterface.h"
Bobty 1:362331cec9b7 8 #include "RdWebServer.h"
Bobty 1:362331cec9b7 9 #include "DrawingManager.h"
Bobty 0:887096209439 10 #include <string.h>
Bobty 1:362331cec9b7 11
Bobty 1:362331cec9b7 12 // Web port
Bobty 1:362331cec9b7 13 const int WEBPORT = 80; // Port for web server
Bobty 0:887096209439 14
Bobty 1:362331cec9b7 15 // Debugging and status
Bobty 1:362331cec9b7 16 RawSerial pc(USBTX, USBRX);
Bobty 2:99eb4c6e9ea4 17 DigitalOut led1(LED1); // flashes on command received
Bobty 1:362331cec9b7 18 DigitalOut led2(LED2); //
Bobty 1:362331cec9b7 19 DigitalOut led3(LED3); //
Bobty 1:362331cec9b7 20 DigitalOut led4(LED4); // web server status
Bobty 0:887096209439 21
Bobty 2:99eb4c6e9ea4 22 // System configuration
Bobty 2:99eb4c6e9ea4 23 char systemName[20] = "LightWall";
Bobty 2:99eb4c6e9ea4 24 int systemNumLEDS = 20;
Bobty 2:99eb4c6e9ea4 25 int systemLEDSSplitPoint = systemNumLEDS;
Bobty 2:99eb4c6e9ea4 26
Bobty 1:362331cec9b7 27 // Drawing Manager
Bobty 2:99eb4c6e9ea4 28 DrawingManager drawingManager;
Bobty 0:887096209439 29
Bobty 1:362331cec9b7 30 //int ledsCount = 904;
Bobty 1:362331cec9b7 31 //int ledSplitPoint = 448;
Bobty 1:362331cec9b7 32 //ledstrip* pLedStrip = NULL;
Bobty 1:362331cec9b7 33 //
Bobty 1:362331cec9b7 34 //char* indexHtmName = "index.htm";
Bobty 1:362331cec9b7 35 //
Bobty 1:362331cec9b7 36 //const int TICK_MS = 100;
Bobty 1:362331cec9b7 37 //LedCmdHandler* pLedCmdHandler = NULL;
Bobty 1:362331cec9b7 38 //int blinkCtr = 0;
Bobty 1:362331cec9b7 39 //
Bobty 1:362331cec9b7 40 //void ledTickfunc()
Bobty 1:362331cec9b7 41 //{
Bobty 1:362331cec9b7 42 // if(webServer.isListening())
Bobty 1:362331cec9b7 43 // {
Bobty 1:362331cec9b7 44 // blinkCtr++;
Bobty 1:362331cec9b7 45 // if (blinkCtr > 1)
Bobty 1:362331cec9b7 46 // {
Bobty 1:362331cec9b7 47 // led1 = !led1;
Bobty 1:362331cec9b7 48 // blinkCtr = 0;
Bobty 1:362331cec9b7 49 // }
Bobty 1:362331cec9b7 50 // }
Bobty 1:362331cec9b7 51 // else
Bobty 1:362331cec9b7 52 // {
Bobty 1:362331cec9b7 53 // led1 = false;
Bobty 1:362331cec9b7 54 // }
Bobty 1:362331cec9b7 55 //
Bobty 1:362331cec9b7 56 // if (pLedCmdHandler != NULL)
Bobty 1:362331cec9b7 57 // pLedCmdHandler->NextGen();
Bobty 1:362331cec9b7 58 //}
Bobty 1:362331cec9b7 59 //
Bobty 1:362331cec9b7 60 //void handleCmd_ledControl(char* cmdStr, char* argStr)
Bobty 1:362331cec9b7 61 //{
Bobty 1:362331cec9b7 62 // printf("LEDS COMMAND %s %s\r\n", cmdStr, argStr);
Bobty 1:362331cec9b7 63 // if (argStr == NULL)
Bobty 1:362331cec9b7 64 // return;
Bobty 1:362331cec9b7 65 // pLedCmdHandler->DoCommand(argStr);
Bobty 1:362331cec9b7 66 //
Bobty 1:362331cec9b7 67 // // Store last command
Bobty 1:362331cec9b7 68 // LocalFileSystem local("local");
Bobty 1:362331cec9b7 69 // FILE* fp = fopen("/local/lastcmd.inf", "w");
Bobty 1:362331cec9b7 70 // if (fp != NULL)
Bobty 1:362331cec9b7 71 // {
Bobty 1:362331cec9b7 72 // fwrite(argStr, 1, strlen(argStr)+1, fp);
Bobty 1:362331cec9b7 73 // fclose(fp);
Bobty 1:362331cec9b7 74 // }
Bobty 1:362331cec9b7 75 //}
Bobty 1:362331cec9b7 76 //
Bobty 1:362331cec9b7 77 //void reRunLastCommand()
Bobty 1:362331cec9b7 78 //{
Bobty 1:362331cec9b7 79 // // Store last command
Bobty 1:362331cec9b7 80 // LocalFileSystem local("local");
Bobty 1:362331cec9b7 81 // FILE* fp = fopen("/local/lastcmd.inf", "r");
Bobty 1:362331cec9b7 82 // if (fp != NULL)
Bobty 1:362331cec9b7 83 // {
Bobty 1:362331cec9b7 84 // char buf[501];
Bobty 1:362331cec9b7 85 // buf[sizeof(buf)-1] = 0;
Bobty 1:362331cec9b7 86 // int nread = fread(buf, 1, sizeof(buf), fp);
Bobty 1:362331cec9b7 87 // fclose(fp);
Bobty 1:362331cec9b7 88 // if (nread > 0 && nread <= sizeof(buf))
Bobty 1:362331cec9b7 89 // {
Bobty 1:362331cec9b7 90 // buf[nread] = 0;
Bobty 1:362331cec9b7 91 // pLedCmdHandler->DoCommand(buf);
Bobty 1:362331cec9b7 92 // }
Bobty 1:362331cec9b7 93 // }
Bobty 1:362331cec9b7 94 //}
Bobty 1:362331cec9b7 95 //
Bobty 1:362331cec9b7 96 //#include "colourconverters.h"
Bobty 1:362331cec9b7 97 //
Bobty 1:362331cec9b7 98 //void BodgeSmooth(ledstrip* pLedStrip)
Bobty 1:362331cec9b7 99 //{
Bobty 1:362331cec9b7 100 // pLedStrip->Clear();
Bobty 1:362331cec9b7 101 // pLedStrip->ShowLeds();
Bobty 1:362331cec9b7 102 //
Bobty 1:362331cec9b7 103 //
Bobty 1:362331cec9b7 104 // RgbColor startRGB(50,0,0);
Bobty 1:362331cec9b7 105 // HsvColor curHsv = RgbToHsv(startRGB);
Bobty 1:362331cec9b7 106 // while(1)
Bobty 1:362331cec9b7 107 // for (int k = 0; k < 1000; k++)
Bobty 1:362331cec9b7 108 // for (int j = 0; j < 255; j++)
Bobty 1:362331cec9b7 109 // {
Bobty 1:362331cec9b7 110 // pLedStrip->Clear();
Bobty 1:362331cec9b7 111 // RgbColor colrVal = HsvToRgb(curHsv);
Bobty 1:362331cec9b7 112 // pLedStrip->Fill(0,pLedStrip->GetNumLeds(),colrVal.r, colrVal.g, colrVal.b);
Bobty 1:362331cec9b7 113 // pLedStrip->ShowLeds();
Bobty 1:362331cec9b7 114 // wait_ms(250);
Bobty 1:362331cec9b7 115 // curHsv.h++;
Bobty 1:362331cec9b7 116 // }
Bobty 1:362331cec9b7 117 //}
Bobty 1:362331cec9b7 118 //
Bobty 1:362331cec9b7 119 //void setLightsConfig()
Bobty 1:362331cec9b7 120 //{
Bobty 1:362331cec9b7 121 // printf("Rob LightWall - Configured for ");
Bobty 1:362331cec9b7 122 // // Check for a config file on the local file system
Bobty 1:362331cec9b7 123 // strcpy(nameOfLights, "Spidey");
Bobty 1:362331cec9b7 124 // LocalFileSystem local("local");
Bobty 1:362331cec9b7 125 // FILE* fp = fopen("/local/spidey.cnf", "r");
Bobty 1:362331cec9b7 126 // if (fp != NULL)
Bobty 1:362331cec9b7 127 // {
Bobty 1:362331cec9b7 128 // char buf[201];
Bobty 1:362331cec9b7 129 // buf[sizeof(buf)-1] = 0;
Bobty 1:362331cec9b7 130 // int nread = fread(buf, 1, sizeof(buf), fp);
Bobty 1:362331cec9b7 131 // if (nread > 0 && nread <= sizeof(buf))
Bobty 1:362331cec9b7 132 // {
Bobty 1:362331cec9b7 133 // buf[nread] = 0;
Bobty 1:362331cec9b7 134 // sscanf(buf, "%s %d %d", nameOfLights, &ledsCount, &ledSplitPoint);
Bobty 1:362331cec9b7 135 // }
Bobty 1:362331cec9b7 136 // fclose(fp);
Bobty 1:362331cec9b7 137 // printf("%s (%d LEDs, Split at %d)", nameOfLights, ledsCount, ledSplitPoint);
Bobty 1:362331cec9b7 138 // printf("\n\r");
Bobty 1:362331cec9b7 139 // }
Bobty 1:362331cec9b7 140 //
Bobty 1:362331cec9b7 141 // // Leds setup
Bobty 1:362331cec9b7 142 // pLedStrip = new ledstrip(ledsCount, ledSplitPoint);
Bobty 1:362331cec9b7 143 // wait_ms(100);
Bobty 1:362331cec9b7 144 // pLedStrip->Clear();
Bobty 1:362331cec9b7 145 // pLedStrip->ShowLeds();
Bobty 1:362331cec9b7 146 //
Bobty 1:362331cec9b7 147 // // Cmd handler
Bobty 1:362331cec9b7 148 // pLedCmdHandler = new LedCmdHandler(pLedStrip);
Bobty 1:362331cec9b7 149 //}
Bobty 2:99eb4c6e9ea4 150
Bobty 1:362331cec9b7 151 //int main (void)
Bobty 1:362331cec9b7 152 //{
Bobty 1:362331cec9b7 153 // pc.baud(115200);
Bobty 1:362331cec9b7 154 //
Bobty 1:362331cec9b7 155 // setLightsConfig();
Bobty 1:362331cec9b7 156 //
Bobty 1:362331cec9b7 157 // BodgeSmooth(pLedStrip);
Bobty 1:362331cec9b7 158 //
Bobty 1:362331cec9b7 159 // ledTick.attach(&ledTickfunc,TICK_MS / 1000.0);
Bobty 1:362331cec9b7 160 //
Bobty 1:362331cec9b7 161 //// reRunLastCommand();
Bobty 1:362331cec9b7 162 //
Bobty 1:362331cec9b7 163 // // setup ethernet interface
Bobty 1:362331cec9b7 164 // eth.init(); //Use DHCP
Bobty 1:362331cec9b7 165 // eth.connect();
Bobty 1:362331cec9b7 166 // printf("IP Address is %s\n\r", eth.getIPAddress());
Bobty 1:362331cec9b7 167 //
Bobty 1:362331cec9b7 168 // webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, indexHtmName, true);
Bobty 1:362331cec9b7 169 // webServer.addCommand("cmd", RdWebServerCmdDef::CMD_CALLBACK, &handleCmd_ledControl);
Bobty 1:362331cec9b7 170 // webServer.init(PORT, &led2);
Bobty 1:362331cec9b7 171 // webServer.run();
Bobty 1:362331cec9b7 172 //}
Bobty 0:887096209439 173
Bobty 1:362331cec9b7 174 // Handle a command
Bobty 1:362331cec9b7 175 char* lightwallCmd(int method, char* cmdStr, char* argStr, char* msgBuf)
Bobty 0:887096209439 176 {
Bobty 2:99eb4c6e9ea4 177 // Blink LED
Bobty 2:99eb4c6e9ea4 178 led1 = !led1;
Bobty 2:99eb4c6e9ea4 179
Bobty 2:99eb4c6e9ea4 180 // Get message payload
Bobty 1:362331cec9b7 181 int cmdLen = RdWebServer::getPayloadLengthFromMsg(msgBuf);
Bobty 1:362331cec9b7 182 unsigned char* cmdBuf = RdWebServer::getPayloadDataFromMsg(msgBuf);
Bobty 3:e5ea80fae61d 183
Bobty 3:e5ea80fae61d 184 // Check if the command length is 0 - in this case respond ok as it might be a
Bobty 3:e5ea80fae61d 185 // pre-flight check on a Cross Domain request - https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Bobty 3:e5ea80fae61d 186 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";
Bobty 3:e5ea80fae61d 187 if (cmdLen != 0)
Bobty 3:e5ea80fae61d 188 {
Bobty 3:e5ea80fae61d 189 // Process command
Bobty 3:e5ea80fae61d 190 drawingManager.start(cmdBuf, cmdLen);
Bobty 3:e5ea80fae61d 191 }
Bobty 1:362331cec9b7 192 return respStr;
Bobty 0:887096209439 193 }
Bobty 0:887096209439 194
Bobty 2:99eb4c6e9ea4 195 // Get system name
Bobty 2:99eb4c6e9ea4 196 char* lightwallGetSystemName(int method, char* cmdStr, char* argStr, char* msgBuf)
Bobty 2:99eb4c6e9ea4 197 {
Bobty 2:99eb4c6e9ea4 198 // Return the system name
Bobty 2:99eb4c6e9ea4 199 return systemName;
Bobty 2:99eb4c6e9ea4 200 }
Bobty 2:99eb4c6e9ea4 201
Bobty 1:362331cec9b7 202 // Create, configure and run the web server
Bobty 1:362331cec9b7 203 void http_thread(void const* arg)
Bobty 0:887096209439 204 {
Bobty 2:99eb4c6e9ea4 205 // Init the web server
Bobty 1:362331cec9b7 206 pc.printf("Starting web server\r\n");
Bobty 1:362331cec9b7 207 char* baseWebFolder = "/sd/"; // should be /sd/ for SDcard files - not used for local file system
Bobty 1:362331cec9b7 208 RdWebServer webServer;
Bobty 2:99eb4c6e9ea4 209
Bobty 2:99eb4c6e9ea4 210 // Add commands to handle the home page and favicon
Bobty 1:362331cec9b7 211 webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, "index.htm", true);
Bobty 1:362331cec9b7 212 webServer.addCommand("favicon.ico", RdWebServerCmdDef::CMD_LOCALFILE, NULL, NULL, true);
Bobty 2:99eb4c6e9ea4 213
Bobty 2:99eb4c6e9ea4 214 // Add the lightwall control commands
Bobty 1:362331cec9b7 215 webServer.addCommand("cmd", RdWebServerCmdDef::CMD_CALLBACK, &lightwallCmd);
Bobty 2:99eb4c6e9ea4 216 webServer.addCommand("name", RdWebServerCmdDef::CMD_CALLBACK, &lightwallGetSystemName);
Bobty 2:99eb4c6e9ea4 217
Bobty 2:99eb4c6e9ea4 218 // Start the server
Bobty 1:362331cec9b7 219 webServer.init(WEBPORT, &led4, baseWebFolder);
Bobty 1:362331cec9b7 220 webServer.run();
Bobty 0:887096209439 221 }
Bobty 0:887096209439 222
Bobty 2:99eb4c6e9ea4 223 void getSystemConfig()
Bobty 2:99eb4c6e9ea4 224 {
Bobty 2:99eb4c6e9ea4 225 printf("LightWall - Configured for ");
Bobty 2:99eb4c6e9ea4 226 // Check for a config file on the local file system
Bobty 2:99eb4c6e9ea4 227 LocalFileSystem local("local");
Bobty 2:99eb4c6e9ea4 228 FILE* fp = fopen("/local/lights.txt", "r");
Bobty 2:99eb4c6e9ea4 229 if (fp != NULL)
Bobty 2:99eb4c6e9ea4 230 {
Bobty 2:99eb4c6e9ea4 231 char buf[201];
Bobty 2:99eb4c6e9ea4 232 buf[sizeof(buf)-1] = 0;
Bobty 2:99eb4c6e9ea4 233 int nread = fread(buf, 1, sizeof(buf), fp);
Bobty 2:99eb4c6e9ea4 234 if (nread > 0 && nread <= sizeof(buf))
Bobty 2:99eb4c6e9ea4 235 {
Bobty 2:99eb4c6e9ea4 236 buf[nread] = 0;
Bobty 2:99eb4c6e9ea4 237 // Read config details from the file
Bobty 2:99eb4c6e9ea4 238 sscanf(buf, "%s %d %d", systemName, &systemNumLEDS, &systemLEDSSplitPoint);
Bobty 2:99eb4c6e9ea4 239 }
Bobty 2:99eb4c6e9ea4 240 fclose(fp);
Bobty 2:99eb4c6e9ea4 241 printf("%s (%d LEDs, Split at %d)", systemName, systemNumLEDS, systemLEDSSplitPoint);
Bobty 2:99eb4c6e9ea4 242 printf("\r\n");
Bobty 2:99eb4c6e9ea4 243 }
Bobty 2:99eb4c6e9ea4 244 }
Bobty 2:99eb4c6e9ea4 245
Bobty 1:362331cec9b7 246 int main()
Bobty 0:887096209439 247 {
Bobty 1:362331cec9b7 248 // Init
Bobty 1:362331cec9b7 249 pc.baud(115200);
Bobty 1:362331cec9b7 250 pc.printf("Light Wall - Rob Dobson 2015\r\n");
Bobty 2:99eb4c6e9ea4 251
Bobty 2:99eb4c6e9ea4 252 // Get the configuration of the system
Bobty 2:99eb4c6e9ea4 253 getSystemConfig();
Bobty 2:99eb4c6e9ea4 254
Bobty 2:99eb4c6e9ea4 255 // Drawing manager controls the LEDs
Bobty 2:99eb4c6e9ea4 256 drawingManager.init(systemNumLEDS, systemLEDSSplitPoint);
Bobty 1:362331cec9b7 257
Bobty 1:362331cec9b7 258 // Setup ethernet interface
Bobty 1:362331cec9b7 259 char macAddr[6];
Bobty 1:362331cec9b7 260 mbed_mac_address(macAddr);
Bobty 1:362331cec9b7 261 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 262 pc.printf("Connecting to ethernet ...\r\n");
Bobty 3:e5ea80fae61d 263
Bobty 3:e5ea80fae61d 264 // Init ethernet
Bobty 1:362331cec9b7 265 EthernetInterface::init();
Bobty 1:362331cec9b7 266
Bobty 3:e5ea80fae61d 267 // Using code described here https://developer.mbed.org/questions/1602/How-to-set-the-TCPIP-stack-s-hostname-pr/
Bobty 3:e5ea80fae61d 268 // to setName on the ethernet interface
Bobty 3:e5ea80fae61d 269 EthernetInterface::setName(systemName);
Bobty 0:887096209439 270
Bobty 3:e5ea80fae61d 271 // Connect ethernet
Bobty 3:e5ea80fae61d 272 EthernetInterface::connect();
Bobty 3:e5ea80fae61d 273 pc.printf("IP Address: %s HostName %s\r\n", EthernetInterface::getIPAddress(), EthernetInterface::getName());
Bobty 3:e5ea80fae61d 274
Bobty 3:e5ea80fae61d 275 // Web Server used to run in a thread - but I've found this slows performance a lot as described here:
Bobty 3:e5ea80fae61d 276 // http://robdobson.com/2015/08/a-reliable-mbed-webserver/
Bobty 3:e5ea80fae61d 277 // Fortunately it doesn't matter as the LED code is all interrupt driven
Bobty 3:e5ea80fae61d 278 // This is the previous code...
Bobty 3:e5ea80fae61d 279 // Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
Bobty 3:e5ea80fae61d 280 http_thread("");
Bobty 3:e5ea80fae61d 281
Bobty 3:e5ea80fae61d 282 // Forever - actually it won't even get here as the server has a forever loop in it too
Bobty 1:362331cec9b7 283 while(true)
Bobty 1:362331cec9b7 284 {
Bobty 1:362331cec9b7 285 }
Bobty 0:887096209439 286 }