mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Merge branch 'ws2811' into device_factory
Former-commit-id: 54b5d4a0b1d19aa5ee31a9f43c20af762f9bdb18
This commit is contained in:
commit
9bfaffe93b
BIN
doc/datasheets/WS2811.pdf
Normal file
BIN
doc/datasheets/WS2811.pdf
Normal file
Binary file not shown.
BIN
doc/datasheets/WS2812.pdf
Normal file
BIN
doc/datasheets/WS2812.pdf
Normal file
Binary file not shown.
BIN
doc/datasheets/WS2812B_preliminary.pdf
Normal file
BIN
doc/datasheets/WS2812B_preliminary.pdf
Normal file
Binary file not shown.
@ -37,6 +37,7 @@ SET(Hyperion_HEADERS
|
|||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceTest.h
|
${CURRENT_SOURCE_DIR}/device/LedDeviceTest.h
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceSedu.h
|
${CURRENT_SOURCE_DIR}/device/LedDeviceSedu.h
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2801.h
|
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2801.h
|
||||||
|
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2811.h
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.h
|
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.h
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.h
|
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.h
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceLightpack.h
|
${CURRENT_SOURCE_DIR}/device/LedDeviceLightpack.h
|
||||||
@ -62,6 +63,7 @@ SET(Hyperion_SOURCES
|
|||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceSedu.cpp
|
${CURRENT_SOURCE_DIR}/device/LedDeviceSedu.cpp
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceTest.cpp
|
${CURRENT_SOURCE_DIR}/device/LedDeviceTest.cpp
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2801.cpp
|
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2801.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2811.cpp
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.cpp
|
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.cpp
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.cpp
|
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.cpp
|
||||||
${CURRENT_SOURCE_DIR}/device/LedDeviceAdalight.cpp
|
${CURRENT_SOURCE_DIR}/device/LedDeviceAdalight.cpp
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "device/LedDeviceSedu.h"
|
#include "device/LedDeviceSedu.h"
|
||||||
#include "device/LedDeviceTest.h"
|
#include "device/LedDeviceTest.h"
|
||||||
#include "device/LedDeviceWs2801.h"
|
#include "device/LedDeviceWs2801.h"
|
||||||
|
#include "device/LedDeviceWs2811.h"
|
||||||
#include "device/LedDeviceAdalight.h"
|
#include "device/LedDeviceAdalight.h"
|
||||||
#include "device/LedDevicePaintpack.h"
|
#include "device/LedDevicePaintpack.h"
|
||||||
#include "device/LedDeviceLightpack.h"
|
#include "device/LedDeviceLightpack.h"
|
||||||
@ -51,6 +52,23 @@ LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig)
|
|||||||
|
|
||||||
device = deviceWs2801;
|
device = deviceWs2801;
|
||||||
}
|
}
|
||||||
|
else if (type == "ws2811")
|
||||||
|
{
|
||||||
|
const std::string output = deviceConfig["output"].asString();
|
||||||
|
const std::string outputSpeed = deviceConfig["output"].asString();
|
||||||
|
const std::string timingOption = deviceConfig["timingOption"].asString();
|
||||||
|
|
||||||
|
ws2811::SpeedMode speedMode = (outputSpeed == "high")? ws2811::highspeed : ws2811::lowspeed;
|
||||||
|
if (outputSpeed != "high" && outputSpeed != "low")
|
||||||
|
{
|
||||||
|
std::cerr << "Incorrect speed-mode selected for WS2811: " << outputSpeed << " != {'high', 'low'}" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, ws2811::fromString(timingOption, ws2811::option_2855), speedMode);
|
||||||
|
deviceWs2811->open();
|
||||||
|
|
||||||
|
device = deviceWs2811;
|
||||||
|
}
|
||||||
else if (type == "lpd6803" || type == "ldp6803")
|
else if (type == "lpd6803" || type == "ldp6803")
|
||||||
{
|
{
|
||||||
const std::string output = deviceConfig["output"].asString();
|
const std::string output = deviceConfig["output"].asString();
|
||||||
|
182
libsrc/hyperion/device/LedDeviceWs2811.cpp
Normal file
182
libsrc/hyperion/device/LedDeviceWs2811.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
|
||||||
|
// Local hyperion includes
|
||||||
|
#include "LedDeviceWs2811.h"
|
||||||
|
|
||||||
|
|
||||||
|
ws2811::SignalTiming ws2811::fromString(const std::string& signalTiming, const SignalTiming defaultValue)
|
||||||
|
{
|
||||||
|
SignalTiming result = defaultValue;
|
||||||
|
if (signalTiming == "3755" || signalTiming == "option_3755")
|
||||||
|
{
|
||||||
|
result = option_3755;
|
||||||
|
}
|
||||||
|
else if (signalTiming == "3773" || signalTiming == "option_3773")
|
||||||
|
{
|
||||||
|
result = option_3773;
|
||||||
|
}
|
||||||
|
else if (signalTiming == "2855" || signalTiming == "option_2855")
|
||||||
|
{
|
||||||
|
result = option_2855;
|
||||||
|
}
|
||||||
|
else if (signalTiming == "2882" || signalTiming == "option_2882")
|
||||||
|
{
|
||||||
|
result = option_2882;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ws2811::getBaudrate(const SpeedMode speedMode)
|
||||||
|
{
|
||||||
|
switch (speedMode)
|
||||||
|
{
|
||||||
|
case highspeed:
|
||||||
|
// Bit length: 125ns
|
||||||
|
return 8000000;
|
||||||
|
case lowspeed:
|
||||||
|
// Bit length: 250ns
|
||||||
|
return 4000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
inline unsigned ws2811::getLength(const SignalTiming timing, const TimeOption option)
|
||||||
|
{
|
||||||
|
switch (timing)
|
||||||
|
{
|
||||||
|
case option_3755:
|
||||||
|
// 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_3773:
|
||||||
|
// 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 7; // 700ns +-150ns
|
||||||
|
case T1L:
|
||||||
|
return 3; // 600ns +-150ns
|
||||||
|
}
|
||||||
|
case option_2855:
|
||||||
|
// 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_2882:
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
std::cerr << "Unknown signal timing for ws2811: " << timing << std::endl;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ws2811::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws2811::ByteSignal ws2811::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
LedDeviceWs2811::LedDeviceWs2811(
|
||||||
|
const std::string & outputDevice,
|
||||||
|
const ws2811::SignalTiming signalTiming,
|
||||||
|
const ws2811::SpeedMode speedMode) :
|
||||||
|
LedRs232Device(outputDevice, ws2811::getBaudrate(speedMode))
|
||||||
|
{
|
||||||
|
fillEncodeTable(signalTiming);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceWs2811::write(const std::vector<ColorRgb> & ledValues)
|
||||||
|
{
|
||||||
|
if (_ledBuffer.size() != ledValues.size() * 3)
|
||||||
|
{
|
||||||
|
_ledBuffer.resize(ledValues.size() * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bufIt = _ledBuffer.begin();
|
||||||
|
for (const ColorRgb & color : ledValues)
|
||||||
|
{
|
||||||
|
*bufIt = _byteToSignalTable[color.red ];
|
||||||
|
++bufIt;
|
||||||
|
*bufIt = _byteToSignalTable[color.green];
|
||||||
|
++bufIt;
|
||||||
|
*bufIt = _byteToSignalTable[color.blue ];
|
||||||
|
++bufIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBytes(_ledBuffer.size() * 3, reinterpret_cast<uint8_t *>(_ledBuffer.data()));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LedDeviceWs2811::switchOff()
|
||||||
|
{
|
||||||
|
write(std::vector<ColorRgb>(_ledBuffer.size()/3, ColorRgb::BLACK));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LedDeviceWs2811::fillEncodeTable(const ws2811::SignalTiming ledOption)
|
||||||
|
{
|
||||||
|
_byteToSignalTable.resize(256);
|
||||||
|
for (unsigned byteValue=0; byteValue<256; ++byteValue)
|
||||||
|
{
|
||||||
|
const uint8_t byteVal = uint8_t(byteValue);
|
||||||
|
_byteToSignalTable[byteValue] = ws2811::translate(ledOption, byteVal);
|
||||||
|
}
|
||||||
|
}
|
147
libsrc/hyperion/device/LedDeviceWs2811.h
Normal file
147
libsrc/hyperion/device/LedDeviceWs2811.h
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
// Local hyperion includes
|
||||||
|
#include "LedRs232Device.h"
|
||||||
|
|
||||||
|
namespace ws2811
|
||||||
|
{
|
||||||
|
///
|
||||||
|
/// Enumaration of known signal timings
|
||||||
|
///
|
||||||
|
enum SignalTiming
|
||||||
|
{
|
||||||
|
option_3755,
|
||||||
|
option_3773,
|
||||||
|
option_2855,
|
||||||
|
option_2882,
|
||||||
|
not_a_signaltiming
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Enumaration of the possible speeds on which the ws2811 can operate.
|
||||||
|
///
|
||||||
|
enum SpeedMode
|
||||||
|
{
|
||||||
|
lowspeed,
|
||||||
|
highspeed
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Enumeration of the signal 'parts' (T 0 high, T 1 high, T 0 low, T 1 low).
|
||||||
|
///
|
||||||
|
enum TimeOption
|
||||||
|
{
|
||||||
|
T0H,
|
||||||
|
T1H,
|
||||||
|
T0L,
|
||||||
|
T1L
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Structure holding the signal for a signle byte
|
||||||
|
///
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
// Make sure the structure is exatly the length we require
|
||||||
|
static_assert(sizeof(ByteSignal) == 8, "Incorrect sizeof ByteSignal (expected 8)");
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Translates a string to a signal timing
|
||||||
|
///
|
||||||
|
/// @param signalTiming The string specifying the signal timing
|
||||||
|
/// @param defaultValue The default value (used if the string does not match any known timing)
|
||||||
|
///
|
||||||
|
/// @return The SignalTiming (or not_a_signaltiming if it did not match)
|
||||||
|
///
|
||||||
|
SignalTiming fromString(const std::string& signalTiming, const SignalTiming defaultValue);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the required baudrate for a specific signal-timing
|
||||||
|
///
|
||||||
|
/// @param SpeedMode The WS2811/WS2812 speed mode (WS2812b only has highspeed)
|
||||||
|
///
|
||||||
|
/// @return The required baudrate for the signal timing
|
||||||
|
///
|
||||||
|
unsigned getBaudrate(const SpeedMode speedMode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The number of 'signal units' (bits) For the subpart of a specific timing scheme
|
||||||
|
///
|
||||||
|
/// @param timing The controller option
|
||||||
|
/// @param option The signal part
|
||||||
|
///
|
||||||
|
unsigned getLength(const SignalTiming timing, const TimeOption option);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
uint8_t bitToSignal(unsigned lenHigh);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 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)
|
||||||
|
///
|
||||||
|
ByteSignal translate(SignalTiming ledOption, uint8_t byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LedDeviceWs2811 : public LedRs232Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Constructs the LedDevice with Ws2811 attached via a serial port
|
||||||
|
///
|
||||||
|
/// @param outputDevice The name of the output device (eg '/dev/ttyS0')
|
||||||
|
/// @param signalTiming The timing scheme used by the Ws2811 chip
|
||||||
|
/// @param speedMode The speed modus of the Ws2811 chip
|
||||||
|
///
|
||||||
|
LedDeviceWs2811(const std::string& outputDevice, const ws2811::SignalTiming signalTiming, const ws2811::SpeedMode speedMode);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Writes the led color values to the led-device
|
||||||
|
///
|
||||||
|
/// @param ledValues The color-value per led
|
||||||
|
/// @return Zero on succes else negative
|
||||||
|
///
|
||||||
|
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||||
|
|
||||||
|
/// Switch the leds off
|
||||||
|
virtual int switchOff();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Fill the byte encoding table (_byteToSignalTable) for the specific timing option
|
||||||
|
///
|
||||||
|
/// @param ledOption The timing option
|
||||||
|
///
|
||||||
|
void fillEncodeTable(const ws2811::SignalTiming ledOption);
|
||||||
|
|
||||||
|
/// Translation table of byte to signal///
|
||||||
|
std::vector<ws2811::ByteSignal> _byteToSignalTable;
|
||||||
|
|
||||||
|
/// The buffer containing the packed RGB values
|
||||||
|
std::vector<ws2811::ByteSignal> _ledBuffer;
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user