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/
Revision 1:362331cec9b7, committed 2015-08-20
- 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
--- /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