This is a library for the DIGI-DOT-BOOSTER which can control LED stripes using the single wire protocol - ws2812 and compatible as well as RGBW LEDs like SK6812. Detailed information including the datasheet and protocol description are available here: http://www.led-genial.de/DIGI-DOT-Booster-WS2812-und-SK6812-ueber-SPI-Schnittstelle-ansteuern DIGI-DOT-BOOSTER acts as a SPI slave and waits for commands sent by a SPI master. This Library provides an easy to use abstraction layer for commands supported by the DD-Booster and adds some additional effects.

Dependents:   DD-Booster-waterdrop BLE_DD-Booster

DDBooster.cpp

Committer:
Gamadril
Date:
2017-03-08
Revision:
2:4c1e47117cf8
Parent:
0:9e96b2bb1958

File content as of revision 2:4c1e47117cf8:

/*
 * DDBoster.cpp - Library to control the Digi-Dot-Booster using a high-level API
 *
 * https://github.com/Gamadril/DD-Booster-mbed
 * MIT License
 */

#include "DDBooster.h"

#define BOOSTER_CMD_DELAY    500
#define BOOSTER_LED_DELAY    30

#define BOOSTER_SETRGB       0xA1
#define BOOSTER_SETRGBW      0xA2
#define BOOSTER_SETHSV       0xA3
#define BOOSTER_SETLED       0xA4
#define BOOSTER_SETALL       0xA5
#define BOOSTER_SETRANGE     0xA6
#define BOOSTER_SETRAINBOW   0xA7
#define BOOSTER_GRADIENT     0xA8

#define BOOSTER_INIT         0xB1
#define BOOSTER_SHOW         0xB2
#define BOOSTER_SHIFTUP      0xB3
#define BOOSTER_SHIFTDOWN    0xB4
#define BOOSTER_COPYLED      0xB5
#define BOOSTER_REPEAT       0xB6

#define BOOSTER_RGBORDER     0xC1

DDBooster::DDBooster(PinName MOSI, PinName SCK, PinName CS, PinName RESET)
    : _lastIndex(0)
    , _device(MOSI, NC, SCK)
    , _cs(CS, 1)
    , _reset(RESET, 1)
{
    _device.format(8,0);
    _device.frequency(12000000);
}

void DDBooster::init(uint16_t ledCount, LedType ledType, LedColorOrder colorOrder)
{
    // DD Booster expects the number of LEDs to be an even value (rounded up).
    // 256 is defined as 0 to fit in one byte.
    if (ledCount > 256) {
        ledCount = 256;
    }

    _lastIndex = ledCount - 1;

    uint8_t buffer[4];
    buffer[0] = BOOSTER_INIT;
    buffer[1] = ledCount + (ledCount & 1);
    buffer[2] = ledType;
    sendRawBytes(buffer, 3);

    if (ledType == LED_RGB && colorOrder != ORDER_GRB) {
        buffer[0] = BOOSTER_RGBORDER;
        buffer[1] = 3;
        buffer[2] = 2;
        buffer[3] = 1;
        sendRawBytes(buffer, 4);
    }

    // a delay after init is not documented, but seems to be necessary
    wait_ms(40);
}

void DDBooster::reset()
{
    if (_reset.is_connected()) {
        _reset = 0;
        wait_ms(100);
        _reset = 1;
        wait_ms(100);
    }
}

void DDBooster::setRGB(uint8_t r, uint8_t g, uint8_t b)
{
    uint8_t cmd[] = {
        BOOSTER_SETRGB,
        r,
        g,
        b
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setRGBW(uint8_t r, uint8_t g, uint8_t b, uint8_t w)
{
    uint8_t cmd[] = {
        BOOSTER_SETRGBW,
        r,
        g,
        b,
        w
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setHSV(uint16_t h, uint8_t s, uint8_t v)
{
    if (h > 359) {
        h = 359;
    }
    uint8_t cmd[] = {
        BOOSTER_SETHSV,
        h & 0xFF,
        h >> 8,
        s,
        v
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setLED(uint8_t index)
{
    if (index > _lastIndex) {
        return;
    }
    uint8_t cmd[] = {
        BOOSTER_SETLED,
        index
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::clearLED(uint8_t index)
{
    if (index > _lastIndex) {
        return;
    }
    // optimization by sending two commands in one transaction
    uint8_t cmd[] = {
        BOOSTER_SETRGB,
        0,
        0,
        0,
        BOOSTER_SETLED,
        index
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setAll()
{
    uint8_t cmd[] = {BOOSTER_SETALL};
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::clearAll()
{
    // optimization by sending two commands in one transaction
    uint8_t cmd[] = {
        BOOSTER_SETRGB,
        0,
        0,
        0,
        BOOSTER_SETALL
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setRange(uint8_t start, uint8_t end)
{
    if (start > end || end > _lastIndex || start > _lastIndex) {
        return;
    }
    uint8_t cmd[] = {
        BOOSTER_SETRANGE,
        start,
        end
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setRainbow(uint16_t h, uint8_t s, uint8_t v, uint8_t start, uint8_t end, uint8_t step)
{
    if (start > end || end > _lastIndex || start > _lastIndex) {
        return;
    }
    if (h > 359) {
        h = 359;
    }
    uint8_t cmd[] = {
        BOOSTER_SETRAINBOW,
        h & 0xFF,
        h >> 8,
        s,
        v,
        start,
        end,
        step
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::setGradient(int start, int end, uint8_t from[3], uint8_t to[3])
{
    if (start > end || start > _lastIndex) {
        return;
    }

    uint8_t steps = end - start;
    if (steps == 0) {
        setRGB(from[0], from[1], from[2]);
        return;
    }

    uint8_t s = 0, e = steps;
    if (start < 0) {
        s = 0 - start;
    }
    if (end > _lastIndex) {
        e -= (end - _lastIndex);
    }

    // optimized setRGB(r,g,b) and setLED(start + i) with one transaction and shared memory
    uint8_t cmd[6];
    cmd[0] = BOOSTER_SETRGB;
    cmd[4] = BOOSTER_SETLED;
    for (; s <= e; s++) {
        cmd[1] = from[0] + (to[0] - from[0]) * s / steps;
        cmd[2] = from[1] + (to[1] - from[1]) * s / steps;
        cmd[3] = from[2] + (to[2] - from[2]) * s / steps;
        cmd[5] = start + s;
        sendRawBytes(cmd, sizeof (cmd));
    }
}

void DDBooster::shiftUp(uint8_t start, uint8_t end, uint8_t count)
{
    if (start > end || end > _lastIndex || start > _lastIndex) {
        return;
    }
    uint8_t cmd[4] = {
        BOOSTER_SHIFTDOWN,
        start,
        end,
        count
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::shiftDown(uint8_t start, uint8_t end, uint8_t count)
{
    if (start > end || end > _lastIndex || start > _lastIndex) {
        return;
    }
    uint8_t cmd[4] = {
        BOOSTER_SHIFTDOWN,
        start,
        end,
        count
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::copyLED(uint8_t from, uint8_t to)
{
    if (from > _lastIndex || to > _lastIndex) {
        return;
    }
    uint8_t cmd[] = {
        BOOSTER_COPYLED,
        from,
        to
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::repeat(uint8_t start, uint8_t end, uint8_t count)
{
    if (start > end || end > _lastIndex || start > _lastIndex) {
        return;
    }
    uint8_t cmd[] = {
        BOOSTER_REPEAT,
        start,
        end,
        count
    };
    sendRawBytes(cmd, sizeof (cmd));
}

void DDBooster::show()
{
    uint8_t cmd[] = {BOOSTER_SHOW};
    sendRawBytes(cmd, sizeof (cmd));
    wait_us(BOOSTER_LED_DELAY * (_lastIndex + 1));
}

void DDBooster::sendRawBytes(const uint8_t *buffer, uint8_t length)
{
    _cs = 0;
    for (int i = 0; i < length; i++) {
        _device.write(buffer[i]);
    }
    _cs = 1;
    wait_us(BOOSTER_CMD_DELAY);
}