mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Updated the ws2811 to allow for different timing schemes
Former-commit-id: b58a9766da9e4f6b2f64683574cddb964aaf3b04
This commit is contained in:
parent
986a7a90fc
commit
5377c5adca
@ -49,10 +49,10 @@ LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig)
|
|||||||
}
|
}
|
||||||
else if (type == "ws2811")
|
else if (type == "ws2811")
|
||||||
{
|
{
|
||||||
|
const std::string type = deviceConfig["type"].asString();
|
||||||
const std::string output = deviceConfig["output"].asString();
|
const std::string output = deviceConfig["output"].asString();
|
||||||
const bool rate = deviceConfig["fast"].asBool();
|
|
||||||
|
|
||||||
LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, rate);
|
LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output);
|
||||||
deviceWs2811->open();
|
deviceWs2811->open();
|
||||||
|
|
||||||
device = deviceWs2811;
|
device = deviceWs2811;
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
// Local hyperion includes
|
// Local hyperion includes
|
||||||
#include "LedDeviceWs2811.h"
|
#include "LedDeviceWs2811.h"
|
||||||
|
|
||||||
LedDeviceWs2811::LedDeviceWs2811(const std::string & deviceName, const bool fastDevice) :
|
LedDeviceWs2811::LedDeviceWs2811(const std::string & deviceName) :
|
||||||
LedRs232Device(deviceName, fastDevice?4000000:2000000)
|
LedRs232Device(deviceName, ws2811::getBaudrate(ws2811::option_1))
|
||||||
{
|
{
|
||||||
fillEncodeTable();
|
fillEncodeTable(ws2811::option_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int LedDeviceWs2811::write(const std::vector<ColorRgb> & ledValues)
|
int LedDeviceWs2811::write(const std::vector<ColorRgb> & ledValues)
|
||||||
@ -37,52 +37,12 @@ int LedDeviceWs2811::switchOff()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDeviceWs2811::fillEncodeTable()
|
void LedDeviceWs2811::fillEncodeTable(const ws2811::SignalTiming ledOption)
|
||||||
{
|
{
|
||||||
|
_byteToSignalTable.resize(256);
|
||||||
for (unsigned byteValue=0; byteValue<256; ++byteValue)
|
for (unsigned byteValue=0; byteValue<256; ++byteValue)
|
||||||
{
|
{
|
||||||
char byteSignal[4];
|
const uint8_t byteVal = uint8_t(byteValue);
|
||||||
for (unsigned iBit=0; iBit<8; iBit=2)
|
_byteToSignalTable[byteValue] = ws2811::translate(ledOption, byteVal);
|
||||||
{
|
|
||||||
// Isolate two bits
|
|
||||||
char bitVal = (byteValue >> (6-iBit)) & 0x03;
|
|
||||||
|
|
||||||
switch (bitVal)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
// _ _
|
|
||||||
// | | _ _ _ _| |_ _ _ _|
|
|
||||||
// <----bits----->
|
|
||||||
byteSignal[iBit/2] = 0x08;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
// _ _ _
|
|
||||||
// | | _ _ _ _| |_ _ _|
|
|
||||||
// <----bits----->
|
|
||||||
byteSignal[iBit/2] = 0x0C;;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
// _ _ _
|
|
||||||
// | |_ _ _| |_ _ _ _|
|
|
||||||
// <----bits----->
|
|
||||||
byteSignal[iBit/2] = 0x88;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// _ _ _ _
|
|
||||||
// | |_ _ _| |_ _ _|
|
|
||||||
// <----bits----->
|
|
||||||
byteSignal[iBit/2] = 0x8C;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Should not happen
|
|
||||||
std::cerr << "two bits evaluated to other value: " << bitVal << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const unsigned byteSignalVal =
|
|
||||||
(byteSignal[0] & 0x00ff) << 0 |
|
|
||||||
(byteSignal[1] & 0x00ff) << 8 |
|
|
||||||
(byteSignal[2] & 0x00ff) << 16 |
|
|
||||||
(byteSignal[3] & 0x00ff) << 24;
|
|
||||||
_byteToSignalTable.push_back(byteSignalVal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,185 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
// Local hyperion includes
|
// Local hyperion includes
|
||||||
#include "LedRs232Device.h"
|
#include "LedRs232Device.h"
|
||||||
|
|
||||||
|
namespace ws2811
|
||||||
|
{
|
||||||
|
enum SignalTiming
|
||||||
|
{
|
||||||
|
option_1,
|
||||||
|
option_2,
|
||||||
|
option_3,
|
||||||
|
option_4
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of the signal 'parts' (T 0 high, T 1 high, T 0 low, T 1 low).
|
||||||
|
*/
|
||||||
|
enum TimeOption
|
||||||
|
{
|
||||||
|
T0H,
|
||||||
|
T1H,
|
||||||
|
T0L,
|
||||||
|
T1L
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the required baudrate for a specific signal-timing
|
||||||
|
*
|
||||||
|
* @param timing The WS2811/WS2812/WS2812b option
|
||||||
|
*
|
||||||
|
* @return The required baudrate for the signal timing
|
||||||
|
*/
|
||||||
|
inline unsigned getBaudrate(const SignalTiming timing)
|
||||||
|
{
|
||||||
|
switch (timing)
|
||||||
|
{
|
||||||
|
case option_1:
|
||||||
|
case option_2:
|
||||||
|
// Bit length: 125ns
|
||||||
|
return 8000000;
|
||||||
|
case option_3:
|
||||||
|
case option_4:
|
||||||
|
// Bit length: 250ns
|
||||||
|
return 4000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of 'signal units' (bits) For the subpart of a specific timing scheme
|
||||||
|
*
|
||||||
|
* @param timing The controller option
|
||||||
|
* @param option The signal part
|
||||||
|
*/
|
||||||
|
inline unsigned getLength(const SignalTiming timing, const TimeOption option)
|
||||||
|
{
|
||||||
|
switch (timing)
|
||||||
|
{
|
||||||
|
case option_1:
|
||||||
|
// Reference: www.adafruit.com/datasheets/WS2812.pdf
|
||||||
|
// Unit length: 125ns
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case T0H:
|
||||||
|
return 3; // 350ns +-150ns
|
||||||
|
case T0L:
|
||||||
|
return 7; // 800ns +-150ns
|
||||||
|
case T1H:
|
||||||
|
return 6; // 700ns +-150ns
|
||||||
|
case T1L:
|
||||||
|
return 4; // 600ns +-150ns
|
||||||
|
}
|
||||||
|
case option_3:
|
||||||
|
// Reference: http://www.mikrocontroller.net/attachment/180459/WS2812B_preliminary.pdf
|
||||||
|
// Unit length: 125ns
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case T0H:
|
||||||
|
return 3; // 400ns +-150ns
|
||||||
|
case T0L:
|
||||||
|
return 7; // 850ns +-150ns
|
||||||
|
case T1H:
|
||||||
|
return 7; // 800ns +-150ns
|
||||||
|
case T1L:
|
||||||
|
return 3; // 450ns +-150ns
|
||||||
|
}
|
||||||
|
case option_2:
|
||||||
|
// Reference: www.adafruit.com/datasheets/WS2811.pdf
|
||||||
|
// Unit length: 250ns
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case T0H:
|
||||||
|
return 2; // 500ns +-150ns
|
||||||
|
case T0L:
|
||||||
|
return 8; // 2000ns +-150ns
|
||||||
|
case T1H:
|
||||||
|
return 5; // 1200ns +-150ns
|
||||||
|
case T1L:
|
||||||
|
return 5; // 1300ns +-150ns
|
||||||
|
}
|
||||||
|
case option_4:
|
||||||
|
// Reference: www.szparkson.net/download/WS2811.pdf
|
||||||
|
// Unit length: 250ns
|
||||||
|
switch (option)
|
||||||
|
{
|
||||||
|
case T0H:
|
||||||
|
return 2; // 500ns +-150ns
|
||||||
|
case T0L:
|
||||||
|
return 8; // 2000ns +-150ns
|
||||||
|
case T1H:
|
||||||
|
return 8; // 2000ns +-150ns
|
||||||
|
case T1L:
|
||||||
|
return 2; // 500ns +-150ns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ByteSignal
|
||||||
|
{
|
||||||
|
uint8_t bit_1;
|
||||||
|
uint8_t bit_2;
|
||||||
|
uint8_t bit_3;
|
||||||
|
uint8_t bit_4;
|
||||||
|
uint8_t bit_5;
|
||||||
|
uint8_t bit_6;
|
||||||
|
uint8_t bit_7;
|
||||||
|
uint8_t bit_8;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(ByteSignal) == 8, "Incorrect sizeof ByteSignal (expected 8)");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a 'bit' based signal with defined 'high' length (and implicite defined 'low'
|
||||||
|
* length. The signal is based on a 10bits bytes (incl. high startbit and low stopbit). The
|
||||||
|
* total length of the high is given as parameter:<br>
|
||||||
|
* lenHigh=7 => |-------|___| => 1 1111 1100 0 => 252 (start and stop bit are implicite)
|
||||||
|
*
|
||||||
|
* @param lenHigh The total length of the 'high' length (incl start-bit)
|
||||||
|
* @return The byte representing the high-low signal
|
||||||
|
*/
|
||||||
|
inline uint8_t bitToSignal(unsigned lenHigh)
|
||||||
|
{
|
||||||
|
// Sanity check on the length of the 'high' signal
|
||||||
|
assert(0 < lenHigh && lenHigh < 10);
|
||||||
|
|
||||||
|
uint8_t result = 0x00;
|
||||||
|
for (unsigned i=1; i<lenHigh; ++i)
|
||||||
|
{
|
||||||
|
result |= (1 << (8-i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate a byte into signal levels for a specific WS2811 option
|
||||||
|
*
|
||||||
|
* @param ledOption The WS2811 configuration
|
||||||
|
* @param byte The byte to translate
|
||||||
|
*
|
||||||
|
* @return The signal for the given byte (one byte per bit)
|
||||||
|
*/
|
||||||
|
inline ByteSignal translate(SignalTiming ledOption, uint8_t byte)
|
||||||
|
{
|
||||||
|
ByteSignal result;
|
||||||
|
result.bit_1 = bitToSignal(getLength(ledOption, (byte & 0x80)?T1H:T0H));
|
||||||
|
result.bit_2 = bitToSignal(getLength(ledOption, (byte & 0x40)?T1H:T0H));
|
||||||
|
result.bit_3 = bitToSignal(getLength(ledOption, (byte & 0x20)?T1H:T0H));
|
||||||
|
result.bit_4 = bitToSignal(getLength(ledOption, (byte & 0x10)?T1H:T0H));
|
||||||
|
result.bit_5 = bitToSignal(getLength(ledOption, (byte & 0x08)?T1H:T0H));
|
||||||
|
result.bit_6 = bitToSignal(getLength(ledOption, (byte & 0x04)?T1H:T0H));
|
||||||
|
result.bit_7 = bitToSignal(getLength(ledOption, (byte & 0x02)?T1H:T0H));
|
||||||
|
result.bit_8 = bitToSignal(getLength(ledOption, (byte & 0x01)?T1H:T0H));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LedDeviceWs2811 : public LedRs232Device
|
class LedDeviceWs2811 : public LedRs232Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -12,7 +189,7 @@ public:
|
|||||||
/// @param outputDevice The name of the output device (eg '/dev/ttyS0')
|
/// @param outputDevice The name of the output device (eg '/dev/ttyS0')
|
||||||
/// @param fastDevice The used baudrate for writing to the output device
|
/// @param fastDevice The used baudrate for writing to the output device
|
||||||
///
|
///
|
||||||
LedDeviceWs2811(const std::string& outputDevice, const bool fastDevice);
|
LedDeviceWs2811(const std::string& outputDevice);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Writes the led color values to the led-device
|
/// Writes the led color values to the led-device
|
||||||
@ -28,11 +205,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void fillEncodeTable();
|
void fillEncodeTable(const ws2811::SignalTiming ledOption);
|
||||||
|
|
||||||
/** Translation table of byte to signal */
|
/** Translation table of byte to signal */
|
||||||
std::vector<unsigned> _byteToSignalTable;
|
std::vector<ws2811::ByteSignal> _byteToSignalTable;
|
||||||
|
|
||||||
/// The buffer containing the packed RGB values
|
/// The buffer containing the packed RGB values
|
||||||
std::vector<unsigned> _ledBuffer;
|
std::vector<ws2811::ByteSignal> _ledBuffer;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user