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/

main.cpp

Committer:
Bobty
Date:
2015-09-03
Revision:
6:8df79fe1afcd
Parent:
5:910909f34907

File content as of revision 6:8df79fe1afcd:

// 
// LightWall WebServer
// 
// 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"
#include "RdWebServer.h"
#include "DrawingManager.h"
#include "Idler.h"
#include <string.h>

// Web port
const int WEBPORT = 80; // Port for web server

// Debugging and status
RawSerial pc(USBTX, USBRX);
DigitalOut led1(LED1); // flashes on command received
DigitalOut led2(LED2); //
DigitalOut led3(LED3); //
DigitalOut led4(LED4); // web server status

// System configuration
char systemName[20] = "LightWall";
int systemNumLEDS = 20;
int systemLEDSSplitPoint = systemNumLEDS;

// 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";

// 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)
{
    idler.notIdle();
    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)
{
    idler.notIdle();
    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)
{
    idler.notIdle();
    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
    idler.notIdle();
    drawingManager.ShowLeds();
    return generalRespStr;
}

// Create, configure and run the web server
void http_server(void const* arg)
{
    // Init the web server
    pc.printf("Starting web server\r\n");
    char* baseWebFolder = "/sd/";  // should be /sd/ for SDcard files - not used for local file system
    RdWebServer webServer;
    
    // Add commands to handle the home page and favicon
    webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, "index.htm", true);
    webServer.addCommand("favicon.ico", RdWebServerCmdDef::CMD_LOCALFILE, NULL, NULL, true);
    
    // Add the lightwall control commands
    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);
    webServer.run();
}

void getSystemConfig()
{
    printf("LightWall - Configured for ");
    // Check for a config file on the local file system
    LocalFileSystem local("local");
    FILE* fp = fopen("/local/lights.txt", "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;
            // Read config details from the file
            sscanf(buf, "%s %d %d", systemName, &systemNumLEDS, &systemLEDSSplitPoint);
        }
        fclose(fp);
        printf("%s (%d LEDs, Split at %d)", systemName, systemNumLEDS, systemLEDSSplitPoint);
        printf("\r\n");
    }
}

int main() 
{
    // 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);
    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());

    // Web Server used to run in a thread - but I've found this slows performance a lot as described here:
    // 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_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)
    {
    }
}