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:
Tue Aug 18 16:03:29 2015 +0000
Child:
1:362331cec9b7
Commit message:
Initial - unchanged since 2013

Changed in this revision

Effect.h Show annotated file Show diff for this revision Revisions of this file
EffectSmooth.h Show annotated file Show diff for this revision Revisions of this file
EffectSnake.h Show annotated file 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 annotated file Show diff for this revision Revisions of this file
LedCmdHandler.h Show annotated file Show diff for this revision Revisions of this file
RdWebServer.lib Show annotated file Show diff for this revision Revisions of this file
colourconverters.cpp Show annotated file Show diff for this revision Revisions of this file
colourconverters.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/Effect.h	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,16 @@
+// 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EffectSmooth.h	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,52 @@
+// 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();
+        }
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EffectSnake.h	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,68 @@
+// 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();
+        }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/EthernetInterface/#cba86db5ab96
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LedCmdHandler.cpp	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,55 @@
+// 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LedCmdHandler.h	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,24 @@
+// 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();
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RdWebServer.lib	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/Bobty/code/RdWebServer/#594136d34a32
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/colourconverters.cpp	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,79 @@
+#include "colourconverters.h"
+
+RgbColor HsvToRgb(HsvColor hsv)
+{
+    RgbColor rgb(0,0,0);
+    unsigned char region, remainder, p, q, t;
+
+    if (hsv.s == 0)
+    {
+        rgb.r = hsv.v;
+        rgb.g = hsv.v;
+        rgb.b = hsv.v;
+        return rgb;
+    }
+
+    region = hsv.h / 43;
+    remainder = (hsv.h - (region * 43)) * 6; 
+
+    p = (hsv.v * (255 - hsv.s)) >> 8;
+    q = (hsv.v * (255 - ((hsv.s * remainder) >> 8))) >> 8;
+    t = (hsv.v * (255 - ((hsv.s * (255 - remainder)) >> 8))) >> 8;
+
+    switch (region)
+    {
+        case 0:
+            rgb.r = hsv.v; rgb.g = t; rgb.b = p;
+            break;
+        case 1:
+            rgb.r = q; rgb.g = hsv.v; rgb.b = p;
+            break;
+        case 2:
+            rgb.r = p; rgb.g = hsv.v; rgb.b = t;
+            break;
+        case 3:
+            rgb.r = p; rgb.g = q; rgb.b = hsv.v;
+            break;
+        case 4:
+            rgb.r = t; rgb.g = p; rgb.b = hsv.v;
+            break;
+        default:
+            rgb.r = hsv.v; rgb.g = p; rgb.b = q;
+            break;
+    }
+
+    return rgb;
+}
+
+HsvColor RgbToHsv(RgbColor rgb)
+{
+    HsvColor hsv(0,0,0);
+    unsigned char rgbMin, rgbMax;
+
+    rgbMin = rgb.r < rgb.g ? (rgb.r < rgb.b ? rgb.r : rgb.b) : (rgb.g < rgb.b ? rgb.g : rgb.b);
+    rgbMax = rgb.r > rgb.g ? (rgb.r > rgb.b ? rgb.r : rgb.b) : (rgb.g > rgb.b ? rgb.g : rgb.b);
+
+    hsv.v = rgbMax;
+    if (hsv.v == 0)
+    {
+        hsv.h = 0;
+        hsv.s = 0;
+        return hsv;
+    }
+
+    hsv.s = 255 * long(rgbMax - rgbMin) / hsv.v;
+    if (hsv.s == 0)
+    {
+        hsv.h = 0;
+        return hsv;
+    }
+
+    if (rgbMax == rgb.r)
+        hsv.h = 0 + 43 * (rgb.g - rgb.b) / (rgbMax - rgbMin);
+    else if (rgbMax == rgb.g)
+        hsv.h = 85 + 43 * (rgb.b - rgb.r) / (rgbMax - rgbMin);
+    else
+        hsv.h = 171 + 43 * (rgb.r - rgb.g) / (rgbMax - rgbMin);
+
+    return hsv;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/colourconverters.h	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,37 @@
+#ifndef COLOURCONVERTERS__H
+#define COLOURCONVERTERS__H
+
+typedef struct RgbColor
+{
+    unsigned char r;
+    unsigned char g;
+    unsigned char b;
+    
+    RgbColor(int inr, int ing, int inb)
+    {
+        r = (unsigned char) inr;
+        g = (unsigned char) ing;
+        b = (unsigned char) inb;
+    }
+} RgbColor;
+
+typedef struct HsvColor
+{
+    unsigned char h;
+    unsigned char s;
+    unsigned char v;
+
+    HsvColor(int inh, int ins, int inv)
+    {
+        h = (unsigned char) inh;
+        s = (unsigned char) ins;
+        v = (unsigned char) inv;
+    }
+
+} HsvColor;
+
+RgbColor HsvToRgb(HsvColor hsv);
+
+HsvColor RgbToHsv(RgbColor rgb);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ledstrip.cpp	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,285 @@
+#include "ledstrip.h"
+#include "colourconverters.h"
+#include "stddef.h"
+
+#define SPIF 0              // SPI interrupt flag bit
+#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;
+
+extern "C" void spi0_isr()
+{
+    if (mCurPos0 < mEndPos0)
+    {
+        LPC_SSP0->DR = pLedValues[mCurPos0];  // write to FIFO data register
+        mCurPos0++;
+    }
+    else
+    {
+        // Turn off interrupts
+        LPC_SSP0->IMSC = 0;
+        mShowingLeds0 = false;
+    }
+}
+
+extern "C" void spi1_isr()
+{
+    if (mCurPos1 < mEndPos1)
+    {
+        LPC_SSP1->DR = pLedValues[mCurPos1];  // write to FIFO data register
+        mCurPos1++;
+    }
+    else
+    {
+        // Turn off interrupts
+        LPC_SSP1->IMSC = 0;
+        mShowingLeds1 = false;
+    }
+}
+
+ledstrip::ledstrip(int length, int splitPoint)
+{
+    mpLedValuesA = 0;
+    mpLedValuesB = 0;
+    mpCurLedValues = 0;
+
+    // SPI0 (using SSP 0 in 1768 chip)
+    mpSPI0 = new SPI(p11, NC, p13);
+    mpSPI0->format(8,0);
+    mpSPI0->frequency(500000);    
+    LPC_SSP0->IMSC = 0; // initially no interrupts requested
+    NVIC_SetVector(SSP0_IRQn,( uint32_t ) spi0_isr);
+    NVIC_ClearPendingIRQ(SSP0_IRQn);
+    NVIC_SetPriority(SSP0_IRQn, 2);
+    NVIC_EnableIRQ(SSP0_IRQn);
+
+    // SPI1 (using SSP 1 in 1768 chip)
+    mpSPI1 = new SPI(p5, NC, p7);
+    mpSPI1->format(8,0);
+    mpSPI1->frequency(500000);    
+    LPC_SSP1->IMSC = 0; // initially no interrupts requested
+    NVIC_SetVector(SSP1_IRQn,( uint32_t ) spi1_isr);
+    NVIC_ClearPendingIRQ(SSP1_IRQn);
+    NVIC_SetPriority(SSP1_IRQn, 2);
+    NVIC_EnableIRQ(SSP1_IRQn);
+    
+    // Enable interrupts
+    __enable_irq();
+        
+    // Resize the string length
+    Resize(length, splitPoint);
+}
+
+ledstrip::~ledstrip()
+{
+    delete mpLedValuesA;
+    delete mpLedValuesB;
+}
+
+bool ledstrip::Resize(int length, int splitPoint)
+{
+    if (mShowingLeds0 || mShowingLeds1)
+        return false;
+    if (mpLedValuesA != 0)
+        delete mpLedValuesA;
+    if (mpLedValuesB != 0)
+        delete mpLedValuesB;
+    mLedsBufSize = length*mColoursPerLed;
+    mpLedValuesA = new unsigned char[mLedsBufSize];
+    mpLedValuesB = new unsigned char[mLedsBufSize];
+    mpCurLedValues = mpLedValuesA;
+    mLedsInStrip = length;
+    mSplitPoint = splitPoint;
+    Clear();
+    return true;
+}
+
+void ledstrip::Clear()
+{
+/*    Timer timr;
+    timr.start();
+    for (int i = 0; i < mLedsInStrip*mColoursPerLed; i++)
+        mpCurLedValues[i] = 0;
+    timr.stop();
+    printf("ClearTime loop %d\n", timr.read_us());  // Result is 863uS for 2500 x 3colour LEDS
+    timr.reset();
+    timr.start();
+ */
+    memset(mpCurLedValues, 0, mLedsBufSize);
+ /*   timr.stop();
+    printf("ClearTime memset %d\n", timr.read_us());  // Result is 35uS for 2500 x 3 colour LEDS
+*/
+}
+
+unsigned char* ledstrip::GetBuffer()
+{
+    return mpCurLedValues;
+}
+
+int ledstrip::GetBufferSizeinBytes()
+{
+    return mLedsBufSize;
+}
+
+bool ledstrip::IsBusy()
+{
+    return mShowingLeds0 || mShowingLeds1;
+}
+
+// Fill - solid colour
+void ledstrip::Fill(int startLed, int numLeds, 
+                int r1, int g1, int b1)
+{
+/*    Timer timr;
+    timr.start();
+*/
+    if ((startLed < 0) || (startLed >= mLedsInStrip))
+        return;
+    if (numLeds >= mLedsInStrip - startLed)
+        numLeds = mLedsInStrip - startLed;
+    int pos = startLed * mColoursPerLed;
+    unsigned char* pBuf = GetBuffer();
+    for (int i = 0; i < numLeds; i++)
+    {
+        pBuf[pos] = (unsigned char) r1;
+        pBuf[pos+1] = (unsigned char) g1;
+        pBuf[pos+2] = (unsigned char) b1;
+        pos += mColoursPerLed;
+    }
+/*    timr.stop();
+    printf("Fill solid %d\n", timr.read_us()); // Fill 50 LEDS solid colour = 11uS
+    */
+}
+
+// Fill - with interpolation of colours using HSV colour space
+void ledstrip::Fill(int startLed, int numLeds, 
+                int r1, int g1, int b1, 
+                int r2, int g2, int b2)
+{
+/*    Timer timr;
+    timr.start();
+    */
+    if ((startLed < 0) || (startLed >= mLedsInStrip))
+        return;
+    if (numLeds >= mLedsInStrip - startLed)
+        numLeds = mLedsInStrip - startLed;
+    int pos = startLed * mColoursPerLed;
+    RgbColor startRGB(r1,g1,b1);
+    HsvColor startHsv = RgbToHsv(startRGB);
+    RgbColor endRGB(r2,g2,b2);
+    HsvColor endHsv = RgbToHsv(endRGB);
+    int curH = startHsv.h << 16;
+    int curS = startHsv.s << 16;
+    int curV = startHsv.v << 16;
+    int interpSteps = numLeds - 1;
+    if (interpSteps < 1)
+        interpSteps = 1;
+    int incH = ((endHsv.h - startHsv.h) << 16) / interpSteps;
+    int incS = ((endHsv.s - startHsv.s) << 16) / interpSteps;
+    int incV = ((endHsv.v - startHsv.v) << 16) / interpSteps;
+    // Since H is a polar value we need to find out if it is best to go clockwise or anti-clockwise
+    if (endHsv.h > startHsv.h)
+    {
+        if (endHsv.h-startHsv.h > 128)
+            incH = ((startHsv.h-endHsv.h) << 16) / interpSteps;
+    }
+    else
+    {
+        // Go "round the top" using modulo result
+        if (startHsv.h-endHsv.h > 128)
+            incH = ((endHsv.h + 255 - startHsv.h) << 16) / interpSteps;
+    }
+    
+//    printf("StartHSV %d %d %d EndHSV %d %d %d IncHSV %d %d %d\n", startHsv.h, startHsv.s, startHsv.v, endHsv.h, endHsv.s, endHsv.v, incH, incS, incV);
+    unsigned char* pBuf = GetBuffer();
+    for (int i = 0; i < numLeds; i++)
+    {
+        RgbColor colrVal = HsvToRgb(HsvColor((curH>>16)&0xff,curS>>16,curV>>16));
+        pBuf[pos] = colrVal.r;
+        pBuf[pos+1] = colrVal.g;
+        pBuf[pos+2] = colrVal.b;
+//        printf("HSV %d %d %d RGB %d %d %d\n", curH>>16, curS>>16, curV>>16, colrVal.r, colrVal.g, colrVal.b);
+        pos += mColoursPerLed;
+        curH = curH + incH;
+        curS = curS + incS;
+        curV = curV + incV;
+    }
+    /*
+    timr.stop();
+    printf("Fill gradient %d\n", timr.read_us());  // Fill gradient 50 LEDS = 64uS
+    */
+}
+
+    
+void ledstrip::ShowLeds()
+{
+    // Check if busy
+    while (mShowingLeds0 || mShowingLeds1)
+        ;
+    wait_us(750);
+    
+    // Set up start points
+    mCurPos0 = 0;
+    mEndPos0 = mSplitPoint*mColoursPerLed;
+    mCurPos1 = mSplitPoint*mColoursPerLed;
+    mEndPos1 = mLedsInStrip*mColoursPerLed;
+    
+    // Set the buffer for the ISRs
+    pLedValues = mpCurLedValues;
+    
+    // Flip the current buffer to the alternate one for interleaved writing
+    if (mpCurLedValues == mpLedValuesA)
+        mpCurLedValues = mpLedValuesB;
+    else
+        mpCurLedValues = mpLedValuesA;
+    
+    // Enable interrupts
+    mShowingLeds0 = true;
+    LPC_SSP0->IMSC = (1 << SSP_IMSC_TX_RDY) & SSP_IMSC_BITMASK;
+    
+    // Check if second strip is used
+    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);
+*/
+}    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ledstrip.h	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,42 @@
+#ifndef LEDSTRIP__H
+#define LEDSTRIP__H
+
+#include "mbed.h"
+
+class ledstrip
+{
+    private:
+        unsigned char* mpLedValuesA;
+        unsigned char* mpLedValuesB;
+        unsigned char* mpCurLedValues;
+        int mLedsInStrip;
+        int mSplitPoint;
+        int mLedsBufSize;
+        SPI* mpSPI0;
+        SPI* mpSPI1;
+        
+    public:
+        static const int mColoursPerLed = 3;
+
+    public:
+        ledstrip(int length, int splitPoint);
+        ~ledstrip();
+        unsigned char* GetBuffer();
+        int GetBufferSizeinBytes();
+        bool Resize(int length, int splitPoint);
+        bool IsBusy();
+        int GetNumLeds()
+        {
+            return mLedsInStrip;
+        }
+        void Clear();
+        void Fill(int startLed, int numLeds, 
+                int r1, int g1, int b1, 
+                int r2, int g2, int b2);
+        void Fill(int startLed, int numLeds, 
+                int r1, int g1, int b1);
+        void ShowLeds();
+        
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,170 @@
+/* main.cpp
+   Rob Dobson 2013
+   More details at ???
+*/
+
+#include "mbed.h"
+#include "EthernetInterface.h"
+#include <stdio.h>
+#include <string.h>
+#include "RdWebServer.h"
+#include "ledstrip.h"
+#include "LedCmdHandler.h"
+
+#define PORT   80
+
+Serial pc(USBTX, USBRX);
+
+RdWebServer webServer;
+
+EthernetInterface eth;
+
+DigitalOut led1(LED1); //server listning status
+DigitalOut led2(LED2); //socket connecting status
+
+Ticker ledTick;
+
+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()
+{
+    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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#29007aef10a4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Aug 18 16:03:29 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f
\ No newline at end of file