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/

Files at this revision

API Documentation at this revision

Comitter:
Bobty
Date:
Thu Aug 20 07:41:02 2015 +0000
Parent:
0:887096209439
Child:
2:99eb4c6e9ea4
Commit message:
Implemented a command protocol using HTTP POST

Changed in this revision

DrawingManager.cpp Show annotated file Show diff for this revision Revisions of this file
DrawingManager.h Show annotated file Show diff for this revision Revisions of this file
Effect.h Show diff for this revision Revisions of this file
EffectSmooth.h Show diff for this revision Revisions of this file
EffectSnake.h Show diff for this revision Revisions of this file
EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
LedCmdHandler.cpp Show diff for this revision Revisions of this file
LedCmdHandler.h Show diff for this revision Revisions of this file
RdWebServer.lib Show annotated file Show diff for this revision Revisions of this file
cmdmsg.cpp Show annotated file Show diff for this revision Revisions of this file
cmdmsg.h Show annotated file Show diff for this revision Revisions of this file
ledstrip.cpp Show annotated file Show diff for this revision Revisions of this file
ledstrip.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DrawingManager.cpp	Thu Aug 20 07:41:02 2015 +0000
@@ -0,0 +1,32 @@
+//
+// Drawing Manager for Pancake Drawbot
+// Rob Dobson 2015
+//
+
+#include "DrawingManager.h"
+#include "rtos.h"
+
+DrawingManager::DrawingManager(int numLeds, int splitPoint)
+{
+    pLedStrip = new ledstrip(numLeds, splitPoint);
+    isBusy = false;
+}
+
+void DrawingManager::init()
+{
+}
+
+char* DrawingManager::start(const unsigned char* cmdBuf, int cmdLen)
+{
+    if (isBusy)
+        return "BUSY";
+    isBusy = true;
+    char* respStr = cmdmsg::Interpret(cmdBuf, cmdLen, pLedStrip);
+    pLedStrip->ShowLeds();
+    isBusy = false;
+    return respStr;
+}
+
+void DrawingManager::service()
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DrawingManager.h	Thu Aug 20 07:41:02 2015 +0000
@@ -0,0 +1,21 @@
+#ifndef DRAWING_MANAGER
+#define DRAWING_MANAGER
+
+#include "mbed.h"
+#include "ledstrip.h"
+#include "cmdmsg.h"
+
+class DrawingManager
+{
+public:
+    DrawingManager(int numLeds, int splitPoint);
+    void init();
+    void service();
+    char* start(const unsigned char* cmdBuf, int cmdLen);
+
+private:
+    ledstrip* pLedStrip;
+    bool isBusy;
+};
+
+#endif
--- a/Effect.h	Tue Aug 18 16:03:29 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-// Base class for led effects
-
-#ifndef EFFECT__H
-#define EFFECT__H
-
-class Effect
-{
-    public:
-        Effect() {}
-        virtual char* GetName() = 0;
-        virtual void Init(char* argStr) = 0;
-        virtual void NextGen() = 0;
-        virtual void Stop() = 0;
-};
-
-#endif
\ No newline at end of file
--- a/EffectSmooth.h	Tue Aug 18 16:03:29 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-// Smooth transition effect
-#include "Effect.h"
-#include "colourconverters.h"
-
-class EffectSmooth : public virtual Effect
-{
-    private:
-        int genCount;
-        ledstrip* pLedStrip;
-        HsvColor curHsv;
-        
-    public:
-        EffectSmooth(ledstrip* pleds) : Effect(), curHsv(0,0,0)
-        {
-            genCount = 0;
-            pLedStrip = pleds;
-        }
-        
-        virtual char* GetName()
-        {
-            return "smooth";
-        }
-        
-        virtual void Init(char* argStr)
-        {
-            return;
-            genCount = 0;
-            pLedStrip->Clear();
-            pLedStrip->ShowLeds();
-            RgbColor startRGB(60,0,0);
-            curHsv = RgbToHsv(startRGB);
-        }
-        
-        virtual void NextGen()
-        {
-            return;
-            pLedStrip->Clear();
-            RgbColor colrVal = HsvToRgb(curHsv);
-            pLedStrip->Fill(0,pLedStrip->GetNumLeds(),colrVal.r, colrVal.g, colrVal.b);
-            pLedStrip->ShowLeds();
-            curHsv.h++;
-        }
-        
-        virtual void Stop()
-        {
-                    return;
-
-            pLedStrip->Clear();
-            pLedStrip->ShowLeds();
-        }
-};
-
--- a/EffectSnake.h	Tue Aug 18 16:03:29 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-// Snake transition effect
-#include "Effect.h"
-#include "colourconverters.h"
-
-class EffectSnake : public virtual Effect
-{
-    private:
-        int snakeLen;
-        int snakeHead;
-        int snakeDir;
-        ledstrip* pLedStrip;
-        RgbColor curColour;
-        
-    public:
-        EffectSnake(ledstrip* pleds) : Effect(), curColour(0,0,0)
-        {
-            snakeLen = 10;
-            snakeHead = 0;
-            snakeDir = 0;
-            pLedStrip = pleds;
-        }
-        
-        virtual char* GetName()
-        {
-            return "snake";
-        }
-        
-        virtual void Init(char* argStr)
-        {
-            return;
-            snakeLen = 0;
-            snakeHead = 0;
-            snakeDir = 0;
-            pLedStrip->Clear();
-            pLedStrip->ShowLeds();
-            curColour = RgbColor(60,60,0);
-        }
-        
-        virtual void NextGen()
-        {
-            return;
-            pLedStrip->Clear();
-            pLedStrip->Fill(snakeHead,snakeLen,curColour.r, curColour.g, curColour.b);
-            pLedStrip->ShowLeds();
-            if (snakeDir == 0)
-            {
-                snakeHead++;
-                if (snakeHead > pLedStrip->GetNumLeds() - snakeLen)
-                    snakeDir = 1;
-            }
-            else
-            {
-                snakeHead--;
-                if (snakeHead <= 0)
-                {
-                    snakeHead = 0;
-                    snakeDir = 0;
-                }
-            }
-        }
-        
-        virtual void Stop()
-        {
-            return;
-            pLedStrip->Clear();
-            pLedStrip->ShowLeds();
-        }
-};
--- a/EthernetInterface.lib	Tue Aug 18 16:03:29 2015 +0000
+++ b/EthernetInterface.lib	Thu Aug 20 07:41:02 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/EthernetInterface/#cba86db5ab96
+http://mbed.org/users/mbed_official/code/EthernetInterface/#2fc406e2553f
--- a/LedCmdHandler.cpp	Tue Aug 18 16:03:29 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-// Handle Led Commands
-
-#include "mbed.h"
-#include <stdio.h>
-#include <string.h>
-#include "ledstrip.h"
-#include "LedCmdHandler.h"
-#include "EffectSmooth.h"
-#include "EffectSnake.h"
-
-void LedCmdHandler::AddEffects()
-{
-    effects.push_back(new EffectSmooth(pLedStrip));
-    effects.push_back(new EffectSnake(pLedStrip));
-}
-
-void LedCmdHandler::DoCommand(char* cmdStr)
-{
-    // Stop any existing command
-    Stop();
-    
-    printf("Cmd %s\n\r", cmdStr);
-    // Extract command
-    char* pch = strtok (cmdStr,"/");
-    if (pch == NULL)
-        return;
-
-    // Find a matching command
-    list<Effect*>::iterator iter;
-    for(iter = effects.begin(); iter != effects.end(); ++iter)
-    {
-        printf("Trying %s vs %s\n\r", (*iter)->GetName(), pch);
-        wait_ms(1000);
-        if (strcmp((*iter)->GetName(), pch) == 0)
-        {
-            pCurEffect = *iter;
-            printf("Command = %s", pCurEffect->GetName());
-            pCurEffect->Init(cmdStr);
-            break;
-        }
-    }
-}
-
-void LedCmdHandler::NextGen()
-{
-    if (pCurEffect != NULL)
-        pCurEffect->NextGen();    
-}
-
-void LedCmdHandler::Stop()
-{
-    if (pCurEffect != NULL)
-        pCurEffect->Stop();
-    pCurEffect = NULL;
-}
\ No newline at end of file
--- a/LedCmdHandler.h	Tue Aug 18 16:03:29 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-// Led Command Handler
-#include <list>
-#include "ledstrip.h"
-#include "Effect.h"
-
-class LedCmdHandler
-{
-    private:
-        std::list<Effect*> effects;
-        ledstrip* pLedStrip;
-        Effect* pCurEffect;
-        
-    public:
-        LedCmdHandler(ledstrip* pleds)
-        {
-            pLedStrip = pleds;
-            AddEffects();
-            pCurEffect = NULL;
-        }
-        void AddEffects();
-        void DoCommand(char* cmdStr);
-        void NextGen();
-        void Stop();
-};
--- a/RdWebServer.lib	Tue Aug 18 16:03:29 2015 +0000
+++ b/RdWebServer.lib	Thu Aug 20 07:41:02 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/Bobty/code/RdWebServer/#594136d34a32
+http://mbed.org/users/Bobty/code/RdWebServer/#2dfb56648b93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmdmsg.cpp	Thu Aug 20 07:41:02 2015 +0000
@@ -0,0 +1,317 @@
+#include "mbed.h"
+#include "cmdmsg.h"
+#include "ledstrip.h"
+//#define DETECT_LEDS
+#ifdef DETECT_LEDS
+#include "detectled.h"
+#endif
+//#define USE_SPIDEY_GEOM
+#ifdef USE_SPIDEY_GEOM
+#include "spideyGeometry.h"
+#endif
+/*
+
+Message format is:
+    <SEQ><CMD><CMD><CMD> ... <ZERO>
+    
+Where:
+    <SEQ> is a two byte sequence count
+    <CMD> is a series of bytes as follows:
+        <LEN><COD><PARAMS>
+        
+Where:
+    <LEN> is a two byte with value 1..65535 depicting msg len
+    <COD> is a one byte command code - see below
+    <PARAMS> are a series of bytes containing the parameters for the command
+    
+<COD> values:
+
+    NOTE MSB of COD is used to indicate that no response is required on success
+         i.e. if MSB of COD is 1 then no response is required on success
+         
+    (COD & 0x7f) ....
+    0x01:
+        Clear the entire strip
+    0x02:
+        Fill a series of leds with RGB values
+        <PARAMS> := <START><NUM><RGB1><RGB2>
+        Where:
+            <START> is a two byte value (bigendian) for led to start series
+            <NUM> is a two byte (bigendian) number of leds to set
+            <RGB1> is the starting RGB value (24bits)
+            <RGB2> is the ending RGB value (24bits) - OPTIONAL
+        The RGB2 value is optional - the LEN value determines whether it is present or not
+        - if present the colour values are interpolated (HSV) between RGB1 and RGB2
+        - if not present all leds are set to colour RGB1
+    0x03:
+        Detect LED with opto-sensor (put opto-sensor on LED and run command)
+        Sensor must be attached to p20 - currently using BPX65 with 470K pullup
+        Returns string with LED number
+    0x04:
+        Set number of leds and split point
+        <PARAMS> := <NUMLEDS><SPLITPOINT>
+        Where:
+            <NUMLEDS> is a two byte (bigendian) value for number of leds in strip
+            <SPLITPOINT> is a two byte (bigendian) value for point at which DigitalOut(p10) is used instead of p12 for data
+                    (this is because the spidey wall is two parallel chains of LEDS)
+    0x05:
+        Raw RGB values for a series of leds
+        <PARAMS> := <START><NUM><RGB1><RGB2><RGB2>....<RGBn>
+        Where:
+            <START> is a two byte value (bigendian) for led to start series
+            <NUM> is a two byte (bigendian) number of leds to set
+            <RGB1> is the RGB value for 1st LED (24bits)
+            <RGB2> is the RGB value for 2nd LED (24bits)
+            <RGBn> is the RGB value for nth LED (24bits)
+    0x06:
+        Set colour for leds on a pad
+        <PARAMS> := <PAD><RGB1><RGB2>
+        Where:
+            <PAD> is the pad number (1 byte)
+            <RGB1> is the starting RGB value (24bits)
+            <RGB2> is the ending RGB value (24bits) - OPTIONAL
+        The RGB2 value is optional - the LEN value determines whether it is present or not
+        - if present the colour values are interpolated (HSV) between RGB1 and RGB2
+        - if not present all leds are set to colour RGB1
+    0x07:
+        Set node and link info
+        <PARAMS> := <NODE><NODEFLAGS><NODERGB><LINKIDX><LINKLEDSTART><LINKNUMLEDS><LINKRGB>
+        Where:
+            <NODE> is the node number (1 byte)
+            <NODEFLAGS> LSB is 0 if the RGB value for the node is not to be changed, or 1 otherwise (1 byte)
+            <NODERGB> is the RBG value for the leds in the node itself (3 bytes)
+            <LINKIDX> is the index of the link (edge) from this node to control (1 byte)
+            <LINKLEDSTART> is the LED along the link to start controlling (1 byte)
+            <LINKNUMLEDS> is the number of LEDs to control (1 byte)
+            <LINKRGB> is the colour to make the link LEDs (3 bytes)
+        
+*/
+
+#ifdef USE_SPIDEY_GEOM
+int cmdmsg::getLedNumFromSeq(const int* edgeLeds, int numLedsInSeq, int seqIdx)
+{
+    if (seqIdx >= numLedsInSeq)
+        return -1;
+    int curSeqPos = 0;
+    bool reverseSeq = false;
+    for (int i = 0; i < MAX_SPIDEY_LINK_ELS/2; i++)
+    {
+        int startLedIdx = edgeLeds[i * 2];
+        int endLedIdx = edgeLeds[i * 2 + 1];
+        int nLeds = endLedIdx - startLedIdx + 1;
+        if (startLedIdx > endLedIdx)
+        {
+            reverseSeq = true;
+            nLeds = startLedIdx - endLedIdx + 1;
+        }
+        if (seqIdx - curSeqPos < nLeds)
+        {
+            if (reverseSeq)
+                return startLedIdx - seqIdx;
+            return startLedIdx + seqIdx;
+        }
+        curSeqPos = nLeds;
+    }
+    return -1;
+}
+#endif
+
+char* cmdmsg::Interpret(const unsigned char* msg, int msgLen, ledstrip* pLedStrip)
+{
+    // Get message details
+    static char responseStr[50];
+    unsigned char* ledStrip = pLedStrip->GetBuffer();
+    int nBytesLeft = msgLen - 2;
+    int seqCount = (msg[0] * 256) + msg[1];
+    msg += 2;
+    while (nBytesLeft > 0)
+    {
+        // Length of chunk
+        int chunkLen = (msg[0] * 256) + msg[1];
+        if (chunkLen == 0)
+            break;
+        
+        // Params length
+        int paramsLen = chunkLen - 1;
+//        printf("Chunklen = %d, Paramslen = %d\r\n", chunkLen, paramsLen);
+        
+        // Command and whether response required on success
+        int cmdCode = msg[2];
+        if ((cmdCode & 0x80) == 0)
+            sprintf(responseStr, "%04x OK", seqCount);
+        else
+            strcpy(responseStr, "");
+        
+        // Move message pointer to assist in decoding the payload
+        msg += 3;
+        switch(cmdCode & 0x7f)
+        {
+            case 0x01: // Clear
+            {
+//                printf("Clear - nextbyte %d\r\n", msg[0]);
+                pLedStrip->Clear();
+                break;
+            }
+            case 0x02: // Fill
+            {
+//                printf("Fill\r\n");
+
+                int startLed = (msg[0] * 256) + msg[1];
+                int numLeds = (msg[2] * 256) + msg[3];
+//                printf("F Q%04x S%d N%d Pa%d Ln%d\r\n", seqCount, startLed, numLeds, paramsLen, msgLen);
+                if (paramsLen == 10)  // RGB2 is provided
+                {
+                    pLedStrip->Fill(startLed, numLeds, msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
+                } else if (paramsLen == 7) // only RGB1 - so solid colour fill
+                {
+                    pLedStrip->Fill(startLed, numLeds, msg[4], msg[5], msg[6]);
+                }
+                break;
+            }
+            case 0x03: // Detect LED
+            {
+#ifdef DETECT_LEDS
+                detectled ledDetector(p20);
+                int selectedLed = ledDetector.DetectSelectedLed(pLedStrip);
+                sprintf(responseStr, "%02x OK LED %d", seqCount, selectedLed);
+#endif
+                break;
+            }
+            case 0x04: // Set numleds and splitpoint
+            {
+//                printf("Set numleds and splitpoint\r\n");
+
+                if (paramsLen == 4)
+                {
+                    int numLeds = (msg[0] * 256) + msg[1];
+                    int splitPoint = (msg[2] * 256) + msg[3];
+                    pLedStrip->Resize(numLeds, splitPoint);
+                }
+                sprintf(responseStr, "%04x OK Resized", seqCount);
+                break;
+            }
+            case 0x05: // Raw - set LEDs to RGB values from buffer
+            {
+                if (paramsLen > 4)
+                {
+                    int startLed = (msg[0] * 256) + msg[1];
+                    int numLeds = (msg[2] * 256) + msg[3];
+                    if (paramsLen >= numLeds * 3 + 4)
+                    {
+                        pLedStrip->RawFill(startLed, numLeds, msg+4);
+//                        printf("R Q%04x S%d N%d Pa%d Ln%d\r\n", seqCount, startLed, numLeds, paramsLen, mMsgLen);
+                    }
+                    else
+                    {
+                        sprintf(responseStr, "%04x RAW FILL - BufLengthMismatch %d", seqCount, paramsLen);
+                    }
+                }
+                else
+                {
+                    sprintf(responseStr, "%04x RAW FILL - ParamsLen Error %d", seqCount, paramsLen);            
+                }
+                break;
+            }
+            case 0x06: // Set pad leds to a colour
+            {
+#ifdef USE_SPIDEY_GEOM
+                printf("Pad\r\n");
+
+                if (paramsLen > 2)
+                {
+                    int padIdx = msg[0];
+                    if (padIdx < sizeof(_spideyPads)/sizeof(SpideyPadInfo))
+                    {
+                        int firstLed = _spideyPads[padIdx].padLeds[0];
+                        int numLeds = _spideyPads[padIdx].padLeds[1] - _spideyPads[padIdx].padLeds[0] + 1;
+                        if (paramsLen == 4) // Only 1 RGB value
+                            pLedStrip->Fill(firstLed, numLeds, msg[1], msg[2], msg[3]);
+                        else if (paramsLen == 7) // Two RGB values
+                            pLedStrip->Fill(firstLed, numLeds, msg[1], msg[2], msg[3], msg[4], msg[5], msg[6]);
+                    }
+                }
+#endif
+                break;
+            }
+            case 0x07: // Control node
+            {
+#ifdef USE_SPIDEY_GEOM
+                printf("Node\r\n");
+
+                if (paramsLen == 11)
+                {
+                    int nodeIdx = msg[0];
+                    if (nodeIdx < sizeof(_spideyNodes)/sizeof(SpideyNodeInfo))
+                    {
+                        const SpideyNodeInfo& sni = _spideyNodes[nodeIdx];
+                        
+                        // Handle the node leds
+                        printf("Node %d leds %d colour %d,%d,%d ... ", nodeIdx, sni.numNodeLeds, msg[2], msg[3], msg[4]);
+                        bool setNodeRGB = ((msg[1] & 0x01) != 0);
+                        if (setNodeRGB)
+                        {
+                            for (int i = 0; (i < sni.numNodeLeds) && (i < MAX_SPIDEY_NODE_LEDS); i++)
+                            {
+                                pLedStrip->Fill(sni.nodeLeds[i], 1, msg[2], msg[3], msg[4]);
+                                printf("Led %d", sni.nodeLeds[i]);
+                            }
+                        }
+                        printf("\r\n");
+                        
+                        // Handle the link leds
+                        int linkIdx = msg[5];
+                        int linkLedStart = msg[6];
+                        int linkNumLeds = msg[7];
+                        printf("Link %d st %d num %d colour %d,%d,%d ... ", linkIdx, linkLedStart, linkNumLeds, msg[8], msg[9], msg[10]);
+                        if ((linkIdx < sni.numLinks) && (linkIdx < MAX_SPIDEY_NODE_LINKS))
+                        {
+                            const SpideyLinkInfo* pSli = sni.nodeLinks[linkIdx];
+                            for (int i = 0; i < linkNumLeds; i++)
+                            {
+                                int ledIdx = linkLedStart + i;
+                                int ledNumA = getLedNumFromSeq(pSli->edgeLedsA, pSli->edgeLengthA, ledIdx);
+                                if (ledNumA >= 0)
+                                {
+                                    pLedStrip->Fill(ledNumA, 1, msg[8], msg[9], msg[10]);
+                                    printf("A=%d/", ledNumA);
+                                }
+                                int ledNumB = getLedNumFromSeq(pSli->edgeLedsB, pSli->edgeLengthB, ledIdx);
+                                if (ledNumB >= 0)
+                                {
+                                    pLedStrip->Fill(ledNumB, 1, msg[8], msg[9], msg[10]);
+                                    printf("B=%d, ", ledNumB);
+                                }
+                            }
+                        }
+                        else
+                        {
+                            sprintf(responseStr, "%04x NODE - linkInvalid %d", seqCount, linkIdx);                    
+                        }
+                        printf("\r\n");
+                    }
+                    else
+                    {
+                        sprintf(responseStr, "%04x NODE - nodeInvalid %d", seqCount, nodeIdx);                    
+                    }
+                }
+                else
+                {
+                    sprintf(responseStr, "%04x NODE - BufLengthMismatch %d", seqCount, paramsLen);                    
+                }
+#endif
+                break;
+            }
+            default:
+            {
+                sprintf(responseStr, "%04x CMD %02x UNKNOWN", seqCount, cmdCode);
+                break;
+            }
+        }
+        
+        // Move to next chunk
+        nBytesLeft = nBytesLeft - chunkLen - 2;
+        msg += paramsLen;
+//        printf("Bytesleft = %d, msg[0] = %d\r\n", nBytesLeft, msg[0]);
+   }
+   return responseStr;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmdmsg.h	Thu Aug 20 07:41:02 2015 +0000
@@ -0,0 +1,44 @@
+
+class ledstrip;
+
+class cmdmsg
+{
+    private:
+//        static char responseStr[50];
+//        unsigned char* mpMsgBuf;
+//        int mMaxMsgLen;
+//        int mMsgLen;
+        int getLedNumFromSeq(const int* edgeLeds, int numLedsInSeq, int seqIdx);
+        
+    public:
+        cmdmsg()
+        {
+//            mMsgLen = 0;
+//            mMaxMsgLen = 5200;
+//            mpMsgBuf = new unsigned char [mMaxMsgLen]();
+//            responseStr[0] = 0;
+        }
+        
+//        ~cmdmsg()
+//        {
+//            delete mpMsgBuf;
+//        }
+//        
+//        char* GetBuffer()
+//        {
+//            return (char*)mpMsgBuf;
+//        }
+//        int GetMaxMsgLen()
+//        {
+//            return mMaxMsgLen;
+//        }
+//        
+//        void SetMsgLen(int n)
+//        {
+//            mMsgLen = n;
+//        }
+//        char* Interpret(ledstrip* pLedStrip);
+//        
+        static char* Interpret(const unsigned char* msgBuf, int msgLen, ledstrip* pLedStrip);
+};
+
--- a/ledstrip.cpp	Tue Aug 18 16:03:29 2015 +0000
+++ b/ledstrip.cpp	Thu Aug 20 07:41:02 2015 +0000
@@ -1,3 +1,7 @@
+// LED Strip using WS2801 with two ISRs for two SPI connected 
+// LED strips running in parallel
+// Rob Dobson 2013-2014
+
 #include "ledstrip.h"
 #include "colourconverters.h"
 #include "stddef.h"
@@ -6,50 +10,51 @@
 #define SSP_IMSC_TX_RDY 3
 #define SSP_IMSC_BITMASK 0x0f
 
-volatile int mCurPos0;
-int mEndPos0;
-volatile int mCurPos1;
-int mEndPos1;
-volatile bool mShowingLeds0;
-volatile bool mShowingLeds1;
-unsigned char* pLedValues;
-bool inISR;
+volatile int mCurPos0 = 0;
+int mEndPos0 = 0;
+volatile bool isr0Busy = false;
+unsigned char* pLedValues0 = NULL;
 
 extern "C" void spi0_isr()
 {
     if (mCurPos0 < mEndPos0)
     {
-        LPC_SSP0->DR = pLedValues[mCurPos0];  // write to FIFO data register
+        LPC_SSP0->DR = pLedValues0[mCurPos0];  // write to FIFO data register
         mCurPos0++;
     }
     else
     {
         // Turn off interrupts
         LPC_SSP0->IMSC = 0;
-        mShowingLeds0 = false;
+        isr0Busy = false;
     }
 }
 
+volatile int mCurPos1 = 0;
+int mEndPos1 = 0;
+volatile bool isr1Busy = false;
+unsigned char* pLedValues1 = NULL;
+
 extern "C" void spi1_isr()
 {
     if (mCurPos1 < mEndPos1)
     {
-        LPC_SSP1->DR = pLedValues[mCurPos1];  // write to FIFO data register
+        LPC_SSP1->DR = pLedValues1[mCurPos1];  // write to FIFO data register
         mCurPos1++;
     }
     else
     {
         // Turn off interrupts
         LPC_SSP1->IMSC = 0;
-        mShowingLeds1 = false;
+        isr1Busy = false;
     }
 }
 
 ledstrip::ledstrip(int length, int splitPoint)
 {
-    mpLedValuesA = 0;
-    mpLedValuesB = 0;
-    mpCurLedValues = 0;
+    mpLedValuesA = NULL;
+    mpLedValuesB = NULL;
+    mpCurLedValues = NULL;
 
     // SPI0 (using SSP 0 in 1768 chip)
     mpSPI0 = new SPI(p11, NC, p13);
@@ -70,10 +75,7 @@
     NVIC_ClearPendingIRQ(SSP1_IRQn);
     NVIC_SetPriority(SSP1_IRQn, 2);
     NVIC_EnableIRQ(SSP1_IRQn);
-    
-    // Enable interrupts
-    __enable_irq();
-        
+
     // Resize the string length
     Resize(length, splitPoint);
 }
@@ -86,11 +88,11 @@
 
 bool ledstrip::Resize(int length, int splitPoint)
 {
-    if (mShowingLeds0 || mShowingLeds1)
+    if (isr0Busy || isr1Busy)
         return false;
-    if (mpLedValuesA != 0)
+    if (mpLedValuesA != NULL)
         delete mpLedValuesA;
-    if (mpLedValuesB != 0)
+    if (mpLedValuesB != NULL)
         delete mpLedValuesB;
     mLedsBufSize = length*mColoursPerLed;
     mpLedValuesA = new unsigned char[mLedsBufSize];
@@ -131,9 +133,20 @@
 
 bool ledstrip::IsBusy()
 {
-    return mShowingLeds0 || mShowingLeds1;
+    return isr0Busy || isr1Busy;
 }
 
+void ledstrip::RawFill(int startLed, int numLeds, const unsigned char* pLedVals)
+{
+    if ((startLed < 0) || (startLed >= mLedsInStrip))
+        return;
+    if (numLeds >= mLedsInStrip - startLed)
+        numLeds = mLedsInStrip - startLed;
+    int pos = startLed * mColoursPerLed;
+    unsigned char* pBuf = GetBuffer() + pos;
+    memcpy(pBuf, pLedVals, numLeds * mColoursPerLed);
+}
+    
 // Fill - solid colour
 void ledstrip::Fill(int startLed, int numLeds, 
                 int r1, int g1, int b1)
@@ -218,13 +231,12 @@
     */
 }
 
-    
 void ledstrip::ShowLeds()
 {
     // Check if busy
-    while (mShowingLeds0 || mShowingLeds1)
-        ;
-    wait_us(750);
+    while (isr0Busy || isr1Busy)
+        wait_us(2000);
+    wait_us(2000);
     
     // Set up start points
     mCurPos0 = 0;
@@ -233,53 +245,28 @@
     mEndPos1 = mLedsInStrip*mColoursPerLed;
     
     // Set the buffer for the ISRs
-    pLedValues = mpCurLedValues;
-    
+    pLedValues0 = mpCurLedValues;
+    pLedValues1 = mpCurLedValues;
+
     // Flip the current buffer to the alternate one for interleaved writing
     if (mpCurLedValues == mpLedValuesA)
+    {
+        memcpy(mpLedValuesB, mpLedValuesA, mLedsBufSize);
         mpCurLedValues = mpLedValuesB;
+    }
     else
+    {
+        memcpy(mpLedValuesA, mpLedValuesB, mLedsBufSize);
         mpCurLedValues = mpLedValuesA;
+    }
     
     // Enable interrupts
-    mShowingLeds0 = true;
-    LPC_SSP0->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
+    isr0Busy = true;
+    if (mSplitPoint < mLedsInStrip)
+        isr1Busy = true;
     
     // Check if second strip is used
+    LPC_SSP0->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
     if (mSplitPoint < mLedsInStrip)
-    {
         LPC_SSP1->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
-        mShowingLeds1 = true;
-    }
- //   for (int q = 0; q < mLedsInStrip*3; q+=3)
- //       printf("%d %02x%02x%02x\n", q/3, mpLedValues[q], mpLedValues[q+1], mpLedValues[q+2]);
-/*
-    int pos1 = 0;
-    int pos2 = mSplitPoint * mColoursPerLed;
-    for (int j = 0; j < mMaxChainLength; j++)
-    {
-        for (int k = 0; k < mColoursPerLed; k++)
-        {
-            unsigned char tval1 = 0;
-            if (pos1 + k < mLedsBufSize)
-                tval1 = mpLedValues[pos1 + k];
-            unsigned char tval2 = 0;
-            if (pos2 + k < mLedsBufSize)
-                tval2 = mpLedValues[pos2 + k];
-            for (int i = 0; i < 8; i++)
-            {
-                dat1 = (tval1 & 0x80) != 0;
-                tval1 = tval1 << 1;
-                dat2 = (tval2 & 0x80) != 0;
-                tval2 = tval2 << 1;
-                clk = 1;
-                clk = 0;
-                wait_us(1);
-            }
-        }
-        pos1 += mColoursPerLed;
-        pos2 += mColoursPerLed;
-    }
-    wait_us(750);
-*/
 }    
--- a/ledstrip.h	Tue Aug 18 16:03:29 2015 +0000
+++ b/ledstrip.h	Thu Aug 20 07:41:02 2015 +0000
@@ -30,6 +30,7 @@
             return mLedsInStrip;
         }
         void Clear();
+        void RawFill(int startLed, int numLeds, const unsigned char* pLedVals);
         void Fill(int startLed, int numLeds, 
                 int r1, int g1, int b1, 
                 int r2, int g2, int b2);
--- a/main.cpp	Tue Aug 18 16:03:29 2015 +0000
+++ b/main.cpp	Thu Aug 20 07:41:02 2015 +0000
@@ -1,170 +1,230 @@
-/* main.cpp
-   Rob Dobson 2013
-   More details at ???
-*/
+// 
+// Spidey Wall WebServer
+// 
+// Rob Dobson 2015
 
 #include "mbed.h"
 #include "EthernetInterface.h"
-#include <stdio.h>
+#include "RdWebServer.h"
+#include "DrawingManager.h"
 #include <string.h>
-#include "RdWebServer.h"
-#include "ledstrip.h"
-#include "LedCmdHandler.h"
+
+// Web port
+const int WEBPORT = 80; // Port for web server
 
-#define PORT   80
-
-Serial pc(USBTX, USBRX);
+// Debugging and status
+RawSerial pc(USBTX, USBRX);
+DigitalOut led1(LED1); // ticking (flashes)
+DigitalOut led2(LED2); //
+DigitalOut led3(LED3); //
+DigitalOut led4(LED4); // web server status
 
-RdWebServer webServer;
-
-EthernetInterface eth;
+// Drawing Manager
+DrawingManager drawingManager(1686, 780);
 
-DigitalOut led1(LED1); //server listning status
-DigitalOut led2(LED2); //socket connecting status
-
-Ticker ledTick;
+//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);
+//}
+//
+//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();
+//}
 
-char nameOfLights[50];
-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()
+// Handle a command
+char* lightwallCmd(int method, char* cmdStr, char* argStr, char* msgBuf)
 {
-    if(webServer.isListening())
+    int cmdLen = RdWebServer::getPayloadLengthFromMsg(msgBuf);
+    unsigned char* cmdBuf = RdWebServer::getPayloadDataFromMsg(msgBuf);
+    pc.printf("Command Payload Len %d\r\n", cmdLen);
+    if (cmdLen == 256)
     {
-        blinkCtr++;
-        if (blinkCtr > 1)
-        {
-            led1 = !led1;
-            blinkCtr = 0;
-        }
-    }
-    else
-    {
-        led1 = false;
+        for (int i = 0; i < cmdLen; i++)
+            if (cmdBuf[i] != i)
+            {
+                printf("Binary content err at %d\r\n", i);
+                break;
+            }
     }
-    
-    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);
-    }    
+    char* respStr = "";
+    respStr = drawingManager.start(cmdBuf, cmdLen);
+    return respStr;
 }
 
-void reRunLastCommand()
+// Create, configure and run the web server
+void http_thread(void const* arg)
 {
-    // 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++;
-    }
+    pc.printf("Starting web server\r\n");
+    char* baseWebFolder = "/sd/";  // should be /sd/ for SDcard files - not used for local file system
+    RdWebServer webServer;
+    webServer.addCommand("", RdWebServerCmdDef::CMD_LOCALFILE, NULL, "index.htm", true);
+    webServer.addCommand("favicon.ico", RdWebServerCmdDef::CMD_LOCALFILE, NULL, NULL, true);
+    webServer.addCommand("cmd", RdWebServerCmdDef::CMD_CALLBACK, &lightwallCmd);
+    webServer.init(WEBPORT, &led4, baseWebFolder);
+    webServer.run();
 }
 
-void setLightsConfig()
+int main() 
 {
-    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");
-    }
+    // Init
+    pc.baud(115200);
+    pc.printf("Light Wall - Rob Dobson 2015\r\n");
+
+    // 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");
+    EthernetInterface::init();
+    EthernetInterface::connect();
+    pc.printf("IP Address: %s\r\n", EthernetInterface::getIPAddress());
+
+    // Web Server
+    Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 4));
     
-    // Leds setup
-    pLedStrip = new ledstrip(ledsCount, ledSplitPoint);
-    wait_ms(100);
-    pLedStrip->Clear();
-    pLedStrip->ShowLeds();
-
-    // Cmd handler
-    pLedCmdHandler = new LedCmdHandler(pLedStrip);
-}
+    // Home
+    drawingManager.init();
 
-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();
+    while(true)
+    {
+//        led1=!led1;
+        // Service drawing manager
+        drawingManager.service();
+//        Thread::wait(500);
+    }
 }
--- a/mbed-rtos.lib	Tue Aug 18 16:03:29 2015 +0000
+++ b/mbed-rtos.lib	Thu Aug 20 07:41:02 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed-rtos/#29007aef10a4
+http://mbed.org/users/mbed_official/code/mbed-rtos/#21b438192b0f
--- a/mbed.bld	Tue Aug 18 16:03:29 2015 +0000
+++ b/mbed.bld	Thu Aug 20 07:41:02 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file
+http://mbed.org/users/mbed_official/code/mbed/builds/8ed44a420e5c
\ No newline at end of file