diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 07ee4335..11766e86 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -49,10 +49,10 @@ LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig) } else if (type == "ws2811") { + const std::string type = deviceConfig["type"].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(); device = deviceWs2811; diff --git a/libsrc/hyperion/device/LedDeviceWs2811.cpp b/libsrc/hyperion/device/LedDeviceWs2811.cpp index 4e905e7a..2f5a4cf7 100644 --- a/libsrc/hyperion/device/LedDeviceWs2811.cpp +++ b/libsrc/hyperion/device/LedDeviceWs2811.cpp @@ -2,10 +2,10 @@ // Local hyperion includes #include "LedDeviceWs2811.h" -LedDeviceWs2811::LedDeviceWs2811(const std::string & deviceName, const bool fastDevice) : - LedRs232Device(deviceName, fastDevice?4000000:2000000) +LedDeviceWs2811::LedDeviceWs2811(const std::string & deviceName) : + LedRs232Device(deviceName, ws2811::getBaudrate(ws2811::option_1)) { - fillEncodeTable(); + fillEncodeTable(ws2811::option_1); } int LedDeviceWs2811::write(const std::vector & ledValues) @@ -37,52 +37,12 @@ int LedDeviceWs2811::switchOff() return 0; } -void LedDeviceWs2811::fillEncodeTable() +void LedDeviceWs2811::fillEncodeTable(const ws2811::SignalTiming ledOption) { + _byteToSignalTable.resize(256); for (unsigned byteValue=0; byteValue<256; ++byteValue) { - char byteSignal[4]; - for (unsigned iBit=0; iBit<8; iBit=2) - { - // 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); + const uint8_t byteVal = uint8_t(byteValue); + _byteToSignalTable[byteValue] = ws2811::translate(ledOption, byteVal); } } diff --git a/libsrc/hyperion/device/LedDeviceWs2811.h b/libsrc/hyperion/device/LedDeviceWs2811.h index dfca9354..532c59be 100644 --- a/libsrc/hyperion/device/LedDeviceWs2811.h +++ b/libsrc/hyperion/device/LedDeviceWs2811.h @@ -1,8 +1,185 @@ #pragma once +// STL includes +#include + // Local hyperion includes #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:
+ * 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 _byteToSignalTable; + std::vector _byteToSignalTable; /// The buffer containing the packed RGB values - std::vector _ledBuffer; + std::vector _ledBuffer; };