Andy A / WS2812Text

Dependencies:   mbed miniFont wsDrive

Files at this revision

API Documentation at this revision

Comitter:
AndyA
Date:
Thu Nov 06 13:55:51 2014 +0000
Child:
1:2014f027ed6f
Commit message:
First commit;

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.lib Show annotated file Show diff for this revision Revisions of this file
miniFont/miniFont.cpp Show annotated file Show diff for this revision Revisions of this file
miniFont/miniFont.h Show annotated file Show diff for this revision Revisions of this file
wsDrive.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Nov 06 13:55:51 2014 +0000
@@ -0,0 +1,286 @@
+#include "mbed.h"
+#include "wsDrive.h"
+#include "miniFont.h"
+
+#define updatePeriodMS 2000
+
+
+/*
+LED config - Assume all LEDs are in one logical chain of len*count leds.
+Physical layout is:
+
+ChainLen = 4, ChainCount = 2, cascadeZigZag undefined
+
+  D1 -> D2 -> D3 -> D4
+  D5 -> D6 -> D7 -> D8
+
+ChainLen = 4, ChainCount = 3, cascadeZigZag defined
+
+  D1 -> D2  -> D3  -> D4
+  D8 <- D7  <- D6  <- D5
+  D9 -> D10 -> D11 -> D12
+
+Text will use the top 5 rows. Text displayed on a chainCount of < 5 will be trimmed.
+Letters are generally 5 pixels wide, numbers and punctuation are 5 or less.
+The default is for a 1 pixel gap between characters so you will need 6 leds per letter displayed.
+
+System uses two buffers, one for that data to display, one to calculate the next data.
+This allows shifts in either direction without overwriting values we haven't used yet.
+Rather than do lots of copying each frame we toggle between which one is being displayed
+and which calculated.
+
+*/
+
+// LED config options:
+
+//#define cascadeZigZag
+
+#define chainLen 35
+#define chainCount 5
+
+// IO setup - currently set for mbuino.
+
+DigitalIn dummy(P0_21,PullDown);
+wsDrive ledDriver(P0_21,P0_22,P1_15);
+DigitalIn progMode(P0_3,PullDown);
+BusOut LEDs(LED1, LED2, LED3, LED4, LED5, LED6, LED7);
+
+
+// globals
+
+miniFont pixelText;
+
+Timer updateRateTimer;
+
+pixelInfo pixelData1[chainLen * chainCount];
+pixelInfo pixelData2[chainLen * chainCount];
+pixelInfo *livePixels;
+pixelInfo *nextPixels;
+
+
+
+inline uint16_t xy2index(uint16_t x, uint16_t y)
+{
+    if (x >= chainLen)
+        x = 0;
+    if (y >= chainCount)
+        y =0;
+#ifdef cascadeZigZag
+    if (y%2)
+        return (y+1)*chainLen - x - 1;
+    else
+        return y*chainLen + x;
+#else
+    return y*chainLen + x;
+#endif
+}
+
+
+void blankBuffer(pixelInfo *Ptr)
+{
+    memset( (void *) Ptr, 00, sizeof(pixelInfo)*chainCount*chainLen );
+}
+
+
+void initColour(pixelInfo *colour)
+{
+    for (int i = 0; i<(chainLen * chainCount); i++) {
+        nextPixels[i].R = colour->R;
+        nextPixels[i].G = colour->G;
+        nextPixels[i].B = colour->B;
+    }
+}
+
+
+uint16_t initText(const char *text, pixelInfo colour, int16_t startPixel = 0, int16_t startRow = 0)
+{
+
+    uint8_t charIndex = 0;
+    uint8_t thisWidth;
+    uint8_t thisHeight;
+    uint16_t pixelY;
+    uint16_t pixelX;
+    uint16_t thisPixIndex;
+    const char *charData;
+
+
+    if (startRow >= chainCount)
+        return startPixel;
+
+    while (*(text+charIndex)) {
+
+
+        if (startPixel >= chainLen)
+            return chainLen;
+
+        thisHeight = pixelText.getPixHeight(*(text+charIndex));
+        thisWidth = pixelText.getPixWidth(*(text+charIndex));
+
+        if (pixelText.getChar(*(text+charIndex),&charData)) {
+
+            if ((startPixel + thisWidth) > chainLen)
+                thisWidth = chainLen - startPixel;
+
+            for (uint8_t row = 0; row < thisHeight; row++) {
+
+                pixelY = row + startRow;
+                if (pixelY >= chainCount)
+                    break;
+
+                for (int16_t col = 0; col < thisWidth; col++) {
+                    pixelX = startPixel + col;
+                    if (pixelX >= chainLen)
+                        break;
+
+                    thisPixIndex = xy2index(pixelX,pixelY);
+
+                    if (*(charData+row) & (1<<(thisWidth-col-1)) ) {
+                        nextPixels[thisPixIndex].R = colour.R;
+                        nextPixels[thisPixIndex].G = colour.G;
+                        nextPixels[thisPixIndex].B = colour.B;
+                    }
+
+                } // end for col
+            } //end for each row
+        } // end if we got data for that character
+        startPixel += thisWidth + 1;
+        charIndex++;
+    } // end while characters left
+    return startPixel;
+}
+
+void initChain ()
+{
+    pixelInfo textColour;
+
+    // optionally use initColour to set a background colour
+
+    // set text colour
+    textColour.R = 0x30;
+    textColour.G = 0x30;
+    textColour.B = 0x00;
+
+    // add text keeping the index for the next character.
+    uint16_t nextChar = initText("H", textColour);
+
+
+    // change the colour
+    textColour.R = 0x10;
+    textColour.G = 0x10;
+    textColour.B = 0x30;
+    // add more text.
+    nextChar = initText("ell", textColour, nextChar);
+
+
+    // one more colour
+    textColour.R = 0x40;
+    textColour.G = 0x00;
+    textColour.B = 0x00;
+    // and a final letter.
+    initText("0", textColour, nextChar);
+
+}
+
+
+// in theory lets you rotate red green and blue independantly an arbitary number of places in either direction.
+// not well tested.
+void rotateChain (int redStep, int greenStep, int blueStep)
+{
+    while (redStep < 0)
+        redStep += chainLen;
+
+    while (greenStep < 0)
+        greenStep += chainLen;
+
+    while (blueStep < 0)
+        blueStep += chainLen;
+
+    uint16_t thisPixIndex;
+    uint16_t redPixIndex;
+    uint16_t bluePixIndex;
+    uint16_t greenPixIndex;
+
+    for (uint16_t col = 0; col<chainLen; col++) {
+        for (uint8_t row = 0; row < chainCount; row++) {
+
+#ifdef cascadeZigZag
+            if (row % 2) {
+                thisPixIndex = chainLen - col - 1 + row*chainLen;
+                redPixIndex = chainLen - redStep - 1 + row*chainLen;
+                greenPixIndex = chainLen - greenStep - 1 + row*chainLen;
+                bluePixIndex = chainLen - blueStep - 1 + row*chainLen;
+            } else
+#endif
+            {
+                thisPixIndex = col + row*chainLen;
+                redPixIndex = redStep + row*chainLen;
+                greenPixIndex = greenStep + row*chainLen;
+                bluePixIndex = blueStep + row*chainLen;
+            }
+
+            nextPixels[thisPixIndex].R = livePixels[redPixIndex].R;
+            nextPixels[thisPixIndex].G = livePixels[greenPixIndex].G;
+            nextPixels[thisPixIndex].B = livePixels[bluePixIndex].B;
+        }
+        redStep = (redStep+1) % chainLen;
+        greenStep = (greenStep+1) % chainLen;
+        blueStep = (blueStep+1) % chainLen;
+    }
+}
+
+void rotateChain (int stepsLeft)
+{
+    rotateChain(stepsLeft,stepsLeft,stepsLeft);
+}
+
+
+void swapBuffer()
+{
+    pixelInfo *tmpPtr = nextPixels;
+    nextPixels = livePixels;
+    livePixels = tmpPtr;
+}
+
+
+int main ()
+{
+    LEDs = 1;
+
+// setup buffers
+    livePixels = pixelData1;
+    nextPixels = pixelData2;
+
+    blankBuffer(livePixels);
+    blankBuffer(nextPixels);
+
+    ledDriver.setData(livePixels, chainLen*chainCount);
+    LEDs = LEDs+1;
+
+// create the data to display
+    initChain();
+    LEDs = LEDs+1;
+
+// set the active buffer to be displayed.
+    swapBuffer();
+    LEDs = LEDs+1;
+
+    updateRateTimer.start();
+    while (true) {
+
+        // update which buffer to use.
+        ledDriver.setData(livePixels, chainLen*chainCount);
+        // send the data
+        ledDriver.sendData();
+
+        LEDs = LEDs + 1;
+
+        // Copy move everthing to the left
+        rotateChain(1);
+
+        // change which buffer to use.
+        swapBuffer();
+        while (updateRateTimer.read_ms() < updatePeriodMS) {
+        }
+        updateRateTimer.reset();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.lib	Thu Nov 06 13:55:51 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/#031413cf7a89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miniFont/miniFont.cpp	Thu Nov 06 13:55:51 2014 +0000
@@ -0,0 +1,167 @@
+#include "miniFont.h"
+
+const char miniFont::dot[5] = { 0x00,0x00,0x00,0x03,0x03};
+const char miniFont::space[5] = { 0x00,0x00,0x00,0x00,0x00};
+const char miniFont::exclam[5] = { 0x01,0x01,0x01,0x00,0x01};
+const char miniFont::quest[5] = { 0x0f,0x09,0x02,0x00,0x02};
+
+const char miniFont::numbers[10][5] = {
+    { 0x0e, 0x11, 0x11, 0x11, 0x08 }, // 0
+    { 0x06, 0x02, 0x02, 0x02, 0x07 }, // 1
+    { 0x1f, 0x01, 0x06, 0x18, 0x1f }, // 2
+    { 0x1f, 0x01, 0x0f, 0x01, 0x1f }, // 3
+    { 0x10, 0x10, 0x14, 0x1f, 0x04 }, // 4
+    { 0x1f, 0x10, 0x1e, 0x01, 0x1e }, // 5
+    { 0x1f, 0x10, 0x1f, 0x11, 0x1f }, // 6
+    { 0x1f, 0x01, 0x01, 0x02, 0x02 }, // 7
+    { 0x1f, 0x11, 0x08, 0x11, 0x1f }, // 8
+    { 0x1f, 0x11, 0x1f, 0x01, 0x1f } // 9
+};
+
+const char miniFont::letters[26][5] = {
+    { 0x1f, 0x11, 0x1f, 0x11, 0x11 }, // A
+    { 0x1e, 0x11, 0x1e, 0x11, 0x1e }, // B
+    { 0x1f, 0x10, 0x10, 0x10, 0x1f }, // C
+    { 0x1e, 0x11, 0x11, 0x11, 0x1e }, // D
+    { 0x1f, 0x10, 0x1e, 0x10, 0x1f }, // E
+    { 0x1f, 0x10, 0x1e, 0x10, 0x10 }, // F
+    { 0x1f, 0x10, 0x13, 0x11, 0x1f }, // G
+    { 0x11, 0x11, 0x1f, 0x11, 0x11 }, // H
+    { 0x07, 0x02, 0x02, 0x02, 0x07 }, // I
+    { 0x01, 0x01, 0x01, 0x11, 0x1f }, // J
+    { 0x11, 0x12, 0x1c, 0x12, 0x11 }, // K
+    { 0x10, 0x10, 0x10, 0x10, 0x1f }, // L
+    { 0x11, 0x1b, 0x15, 0x11, 0x11 }, // M
+    { 0x11, 0x19, 0x15, 0x13, 0x11 }, // N
+    { 0x1f, 0x11, 0x11, 0x11, 0x1f }, // O
+    { 0x1f, 0x11, 0x1f, 0x10, 0x10 }, // P
+    { 0x1f, 0x11, 0x15, 0x1f, 0x04 }, // Q
+    { 0x1f, 0x11, 0x1f, 0x12, 0x11 }, // R
+    { 0x1f, 0x10, 0x1f, 0x01, 0x1F }, // S
+    { 0x1f, 0x04, 0x04, 0x04, 0x04 }, // T
+    { 0x11, 0x11, 0x11, 0x11, 0x1F }, // U
+    { 0x11, 0x11, 0x11, 0x0a, 0x04 }, // V
+    { 0x11, 0x11, 0x15, 0x1b, 0x11 }, // W
+    { 0x11, 0x0a, 0x04, 0x0a, 0x11 }, // X
+    { 0x11, 0x11, 0x1f, 0x04, 0x04 }, // Y
+    { 0x1f, 0x02, 0x04, 0x08, 0x1f } // Z
+};
+
+
+miniFont::miniFont() {
+
+    rotate90 = false;
+    fixedWidth = false;
+     }
+
+
+uint8_t miniFont::getMinPixWidth(char letter)
+{
+    switch(letter) {
+        case '.':
+            return 2;
+        case ' ':
+        case '1':
+        case 'I':
+        case 'i':
+            return 3;
+        case '!':
+            return 1;
+        case '?':
+            return 4;
+        default:
+            return maxWidth;
+    }
+}
+
+
+uint8_t miniFont::getPixWidth(char letter)
+{
+    if (fixedWidth)
+        return maxWidth;
+    else
+        return getMinPixWidth(letter);
+}
+
+uint8_t miniFont::getPixHeight(char letter)
+{
+    return 5;
+}
+
+// gets the proportional letter
+bool miniFont::getRawChar(char letter, const char **rowArray)
+{
+
+    if ((letter>='A') && (letter<='Z')) { // upper
+        *rowArray = letters[letter-'A'];
+        return true;
+    }
+    if ((letter>='a') && (letter<='z')) { // lower
+        *rowArray = letters[letter-'a'];
+        return true;
+    }
+    if ((letter>='0') && (letter <='9')) {
+        *rowArray = numbers[letter-'0'];
+        return true;
+    }
+    if (letter == '.') {
+        *rowArray = dot;
+        return true;
+    }
+    if (letter == '!') {
+        *rowArray = exclam;
+        return true;
+    }
+    if (letter == '?') {
+        *rowArray = quest;
+        return true;
+    }
+    if (letter == ' ') {
+        *rowArray = space;
+        return true;
+    }
+    return false;
+}
+
+// converts to fixed width if needed.
+bool miniFont::getVerticalChar(char letter, const char **rowArray)
+{
+    if (!fixedWidth)
+        return getRawChar(letter,rowArray);
+
+    uint8_t shift = (maxWidth - getMinPixWidth(letter)) / 2;
+    if (shift == 0)
+        return getRawChar(letter,rowArray);
+
+    const char *rawletter;
+    if (getRawChar(letter,&rawletter)) {
+        for (int i = 0; i < maxHeight; i++) {
+            letterBuffer[i] = rawletter[i]<<shift;
+        }
+        *rowArray = (const char *)letterBuffer;
+        return true;
+    }
+    return false;
+}
+
+// rotates if needed.
+bool miniFont::getChar(char letter, const char **rowArray)
+{
+    if (!rotate90) return getVerticalChar(letter,rowArray);
+
+    const char *vertical;
+    if (!getVerticalChar(letter,&vertical))
+        return false;
+
+    for (int i = 0; i < maxWidth; i++) {
+        rotateBuffer[i] = 0;
+    }
+
+    for (int i = 0; i < maxHeight; i++) {
+        for (int j = 0; j < maxWidth; j++) {
+            rotateBuffer[i] = vertical[j] << j;
+        }
+    }
+    *rowArray = vertical;
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/miniFont/miniFont.h	Thu Nov 06 13:55:51 2014 +0000
@@ -0,0 +1,49 @@
+#ifndef __miniFont_h__
+#define __miniFont_h__
+
+#include "mbed.h"
+
+class miniFont
+{
+public:
+
+    miniFont();
+    uint8_t getPixWidth(char letter);
+    uint8_t getPixHeight(char letter);
+    bool getChar(char letter, const char **rowArray);
+    
+    bool isFixedWidth() {return fixedWidth;};
+    void setFixedWidth(bool newValue) {fixedWidth = newValue;};
+    
+    bool isRotated() {return rotate90;};
+    void setRotated(bool newValue) {rotate90 = newValue;};
+
+private:
+
+
+    uint8_t getMinPixWidth(char letter);
+    bool getRawChar(char letter, const char **rowArray);
+    bool getVerticalChar(char letter, const char **rowArray);
+
+    static const uint8_t maxWidth = 5;
+    static const uint8_t maxHeight = 5;
+
+    bool rotate90;
+    bool fixedWidth;
+    char letterBuffer[5];
+    char rotateBuffer[5];
+
+
+    static const char letters[26][5];
+
+    static const char numbers[10][5];
+
+    static const char dot[5];
+    static const char space[5];
+    static const char exclam[5];
+    static const char quest[5];
+
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wsDrive.lib	Thu Nov 06 13:55:51 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/AndyA/code/wsDrive/#b3665f91bedc