From a960894d140405e29edb413685e700d2f1714212 Mon Sep 17 00:00:00 2001 From: penfold42 Date: Mon, 16 May 2016 02:39:17 +1000 Subject: [PATCH] Another option for Ws2812 - direct spi from the pi with 1 wire (#631) * Removed -HUP so the default -TERM signal is sent instead. - hyperiond only listens for TERM and INT. HUP is often used to get an exe to reread its config Changed pgrep to add '-x' so it wont partial match on the exe name. - I have multiple instances with multiple hyperiond-instance1 names - this ensures the service script only kills the right process * reversing errant change to hyperion.systemd.sh * This add a new device type - ws2812spi. I've (ab)used the SPI interface to send the correct timing pulses to keep the ws2812 happy. THE RATE IS IMPORTANT! A FIXED CORE_CLK IS IMPORTANT! Attach the SPI MOSI pin on the Pi to the DIN pin on your ws2812 "device" : { "name" : "MyPi", "type" : "ws2812spi", "colorOrder" : "grb", "output" : "/dev/spidev0.0", "rate" : 3800000 }, * updated hyperiond.test-binary * Updated default SPI speed to the "correct" value. My Pi was undervolted so was dropping the core clock confusing everything * Code cleanups explicitly set the final 3 bytes to 0 * Removed latchtime option - not applicable * updated test binary Former-commit-id: d3c19c8374999f7a554bb25ca181a8a483f86289 --- hyperiond.test-binary.REMOVED.git-id | 2 +- libsrc/leddevice/CMakeLists.txt | 2 + libsrc/leddevice/LedDeviceFactory.cpp | 11 +++++ libsrc/leddevice/LedDeviceWs2812SPI.cpp | 57 +++++++++++++++++++++++++ libsrc/leddevice/LedDeviceWs2812SPI.h | 52 ++++++++++++++++++++++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 libsrc/leddevice/LedDeviceWs2812SPI.cpp create mode 100644 libsrc/leddevice/LedDeviceWs2812SPI.h diff --git a/hyperiond.test-binary.REMOVED.git-id b/hyperiond.test-binary.REMOVED.git-id index dc9b6471..007dd52b 100644 --- a/hyperiond.test-binary.REMOVED.git-id +++ b/hyperiond.test-binary.REMOVED.git-id @@ -1 +1 @@ -5d75f380f2bd74d3cd6b574f0a7d05850786216b \ No newline at end of file +23f1b917ec588d71521aa698edf446a2e8c0ea5d \ No newline at end of file diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index 6d89205a..2d2ceba5 100755 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -75,6 +75,7 @@ if(ENABLE_SPIDEV) ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h ${CURRENT_SOURCE_DIR}/LedDeviceP9813.h ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h + ${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.h ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.h ) SET(Leddevice_SOURCES @@ -84,6 +85,7 @@ if(ENABLE_SPIDEV) ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp ${CURRENT_SOURCE_DIR}/LedDeviceP9813.cpp ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.cpp ) endif(ENABLE_SPIDEV) diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index 7cf2385b..689ef91f 100755 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -14,6 +14,7 @@ #include "LedDeviceLpd8806.h" #include "LedDeviceP9813.h" #include "LedDeviceWs2801.h" + #include "LedDeviceWs2812SPI.h" #include "LedDeviceAPA102.h" #endif @@ -142,6 +143,16 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) device = deviceWs2801; } + else if (type == "ws2812spi") + { + const std::string output = deviceConfig["output"].asString(); + const unsigned rate = deviceConfig.get("rate",2857143).asInt(); + + LedDeviceWs2812SPI* deviceWs2812SPI = new LedDeviceWs2812SPI(output, rate); + deviceWs2812SPI->open(); + + device = deviceWs2812SPI; + } #endif #ifdef ENABLE_TINKERFORGE else if (type=="tinkerforge") diff --git a/libsrc/leddevice/LedDeviceWs2812SPI.cpp b/libsrc/leddevice/LedDeviceWs2812SPI.cpp new file mode 100644 index 00000000..7b915595 --- /dev/null +++ b/libsrc/leddevice/LedDeviceWs2812SPI.cpp @@ -0,0 +1,57 @@ + +// STL includes +#include +#include +#include + +// Linux includes +#include +#include + +// hyperion local includes +#include "LedDeviceWs2812SPI.h" + +LedDeviceWs2812SPI::LedDeviceWs2812SPI(const std::string& outputDevice, const unsigned baudrate) : + LedSpiDevice(outputDevice, baudrate, 0), + mLedCount(0) +{ + // empty +} + +int LedDeviceWs2812SPI::write(const std::vector &ledValues) +{ + mLedCount = ledValues.size(); + +// 3 colours, 4 spi bytes per colour + 3 frame end latch bytes +#define COLOURS_PER_LED 3 +#define SPI_BYTES_PER_COLOUR 4 +#define SPI_BYTES_PER_LED COLOURS_PER_LED * SPI_BYTES_PER_COLOUR + + unsigned spi_size = mLedCount * SPI_BYTES_PER_LED + 3; + if(_spiBuffer.size() != spi_size){ + _spiBuffer.resize(spi_size, 0x00); + } + + unsigned spi_ptr = 0; + for (unsigned i=0; i< mLedCount; ++i) { + uint32_t colorBits = ((unsigned int)ledValues[i].red << 16) + | ((unsigned int)ledValues[i].green << 8) + | ledValues[i].blue; + + for (int j=SPI_BYTES_PER_LED - 1; j>=0; j--) { + _spiBuffer[spi_ptr+j] = bitpair_to_byte[ colorBits & 0x3 ]; + colorBits >>= 2; + } + spi_ptr += SPI_BYTES_PER_LED; + } + _spiBuffer[spi_ptr++] = 0; + _spiBuffer[spi_ptr++] = 0; + _spiBuffer[spi_ptr++] = 0; + + return writeBytes(spi_size, _spiBuffer.data()); +} + +int LedDeviceWs2812SPI::switchOff() +{ + return write(std::vector(mLedCount, ColorRgb{0,0,0})); +} diff --git a/libsrc/leddevice/LedDeviceWs2812SPI.h b/libsrc/leddevice/LedDeviceWs2812SPI.h new file mode 100644 index 00000000..e82d9134 --- /dev/null +++ b/libsrc/leddevice/LedDeviceWs2812SPI.h @@ -0,0 +1,52 @@ +#pragma once + +// STL includes +#include + +// hyperion incluse +#include "LedSpiDevice.h" + +/// +/// Implementation of the LedDevice interface for writing to Ws2801 led device. +/// +class LedDeviceWs2812SPI : public LedSpiDevice +{ +public: + /// + /// Constructs the LedDevice for a string containing leds of the type Ws2812SPI + /// + /// @param outputDevice The name of the output device (eg '/etc/SpiDev.0.0') + /// @param baudrate The used baudrate for writing to the output device + /// + LedDeviceWs2812SPI(const std::string& outputDevice, + const unsigned baudrate); + + LedDeviceWs2812SPI(const std::string& outputDevice, + const unsigned baudrate, + const unsigned latchTime); + + /// + /// 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 &ledValues); + + /// Switch the leds off + virtual int switchOff(); + +private: + + /// the number of leds (needed when switching off) + size_t mLedCount; + std::vector _spiBuffer; + + uint8_t bitpair_to_byte[4] = { + 0b10001000, + 0b10001100, + 0b11001000, + 0b11001100, + }; + +};