mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Add new WS281x driver
Add a new WS281x driver which is a wrapper around jgarff's ws281x library which works on Pi B+, Pi 2, Pi Zero and probably Pi 3 as well. jgarff's ws281x library is included as a submodule Former-commit-id: e473dfd36d31b14598da5e56e4b8bf9f2aa7bb24
This commit is contained in:
parent
14fc1d9bb6
commit
78e606a1c4
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "dependencies/external/protobuf"]
|
[submodule "dependencies/external/protobuf"]
|
||||||
path = dependencies/external/protobuf
|
path = dependencies/external/protobuf
|
||||||
url = https://github.com/tvdzwan/protobuf.git
|
url = https://github.com/tvdzwan/protobuf.git
|
||||||
|
[submodule "dependencies/external/rpi_ws281x"]
|
||||||
|
path = dependencies/external/rpi_ws281x
|
||||||
|
url = https://github.com/jgarff/rpi_ws281x
|
||||||
|
@ -34,6 +34,9 @@ message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2})
|
|||||||
option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" OFF)
|
option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" OFF)
|
||||||
message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM})
|
message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM})
|
||||||
|
|
||||||
|
option(ENABLE_WS281XPWM "Enable the WS281x-PWM device" OFF)
|
||||||
|
message(STATUS "ENABLE_WS281XPWM = " ${ENABLE_WS281XPWM})
|
||||||
|
|
||||||
option(ENABLE_X11 "Enable the X11 grabber" OFF)
|
option(ENABLE_X11 "Enable the X11 grabber" OFF)
|
||||||
message(STATUS "ENABLE_X11 = " ${ENABLE_X11})
|
message(STATUS "ENABLE_X11 = " ${ENABLE_X11})
|
||||||
|
|
||||||
@ -56,6 +59,10 @@ if(ENABLE_OSX AND ENABLE_DISPMANX)
|
|||||||
message(FATAL_ERROR "dispmanx grabber and osx grabber cannot be used at the same time")
|
message(FATAL_ERROR "dispmanx grabber and osx grabber cannot be used at the same time")
|
||||||
endif(ENABLE_OSX AND ENABLE_DISPMANX)
|
endif(ENABLE_OSX AND ENABLE_DISPMANX)
|
||||||
|
|
||||||
|
if(ENABLE_WS2812BPWM AND ENABLE_WS281XPWM)
|
||||||
|
message(FATAL_ERROR "WS2812b and WS281x drivers cannot be used at the same time")
|
||||||
|
endif(ENABLE_WS2812BPWM AND ENABLE_WS281XPWM)
|
||||||
|
|
||||||
#if(ENABLE_QT5)
|
#if(ENABLE_QT5)
|
||||||
# TODO vs ENABLE_QT4?
|
# TODO vs ENABLE_QT4?
|
||||||
#endif(ENABLE_QT5)
|
#endif(ENABLE_QT5)
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
// Define to enable the ws2812b-pwm-device
|
// Define to enable the ws2812b-pwm-device
|
||||||
#cmakedefine ENABLE_WS2812BPWM
|
#cmakedefine ENABLE_WS2812BPWM
|
||||||
|
|
||||||
|
// Define to enable the ws281x-pwm-via-dma-device using jgarff's library
|
||||||
|
#cmakedefine ENABLE_WS281XPWM
|
||||||
|
|
||||||
// Define to enable the spi-device
|
// Define to enable the spi-device
|
||||||
#cmakedefine ENABLE_TINKERFORGE
|
#cmakedefine ENABLE_TINKERFORGE
|
||||||
|
|
||||||
|
7
dependencies/CMakeLists.txt
vendored
7
dependencies/CMakeLists.txt
vendored
@ -4,6 +4,13 @@ add_subdirectory(build/jsoncpp)
|
|||||||
add_subdirectory(build/serial)
|
add_subdirectory(build/serial)
|
||||||
add_subdirectory(build/tinkerforge)
|
add_subdirectory(build/tinkerforge)
|
||||||
|
|
||||||
|
if(ENABLE_WS281XPWM)
|
||||||
|
add_library(ws281x
|
||||||
|
external/rpi_ws281x/mailbox.c external/rpi_ws281x/ws2811.c
|
||||||
|
external/rpi_ws281x/pwm.c external/rpi_ws281x/dma.c
|
||||||
|
external/rpi_ws281x/rpihw.c)
|
||||||
|
endif(ENABLE_WS281XPWM)
|
||||||
|
|
||||||
if(ENABLE_PROTOBUF)
|
if(ENABLE_PROTOBUF)
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared protobuf library")
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared protobuf library")
|
||||||
add_subdirectory(external/protobuf)
|
add_subdirectory(external/protobuf)
|
||||||
|
1
dependencies/external/rpi_ws281x
vendored
Submodule
1
dependencies/external/rpi_ws281x
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 34c917e25044a7aca4f6dc9326c48c1474b8f28c
|
@ -97,6 +97,18 @@ SET(Leddevice_SOURCES
|
|||||||
)
|
)
|
||||||
endif(ENABLE_WS2812BPWM)
|
endif(ENABLE_WS2812BPWM)
|
||||||
|
|
||||||
|
if(ENABLE_WS281XPWM)
|
||||||
|
include_directories(../../dependencies/external/rpi_ws281x)
|
||||||
|
SET(Leddevice_HEADERS
|
||||||
|
${Leddevice_HEADERS}
|
||||||
|
${CURRENT_SOURCE_DIR}/LedDeviceWS281x.h
|
||||||
|
)
|
||||||
|
SET(Leddevice_SOURCES
|
||||||
|
${Leddevice_SOURCES}
|
||||||
|
${CURRENT_SOURCE_DIR}/LedDeviceWS281x.cpp
|
||||||
|
)
|
||||||
|
endif(ENABLE_WS281XPWM)
|
||||||
|
|
||||||
if(ENABLE_TINKERFORGE)
|
if(ENABLE_TINKERFORGE)
|
||||||
SET(Leddevice_HEADERS
|
SET(Leddevice_HEADERS
|
||||||
${Leddevice_HEADERS}
|
${Leddevice_HEADERS}
|
||||||
@ -138,6 +150,10 @@ if(ENABLE_TINKERFORGE)
|
|||||||
target_link_libraries(leddevice tinkerforge)
|
target_link_libraries(leddevice tinkerforge)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_WS281XPWM)
|
||||||
|
target_link_libraries(leddevice ws281x)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(leddevice hidapi-mac)
|
target_link_libraries(leddevice hidapi-mac)
|
||||||
else()
|
else()
|
||||||
|
@ -42,6 +42,10 @@
|
|||||||
#include "LedDeviceWS2812b.h"
|
#include "LedDeviceWS2812b.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_WS281XPWM
|
||||||
|
#include "LedDeviceWS281x.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
|
LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
|
||||||
{
|
{
|
||||||
std::cout << "Device configuration: " << deviceConfig << std::endl;
|
std::cout << "Device configuration: " << deviceConfig << std::endl;
|
||||||
@ -285,6 +289,18 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
|
|||||||
LedDeviceWS2812b * ledDeviceWS2812b = new LedDeviceWS2812b();
|
LedDeviceWS2812b * ledDeviceWS2812b = new LedDeviceWS2812b();
|
||||||
device = ledDeviceWS2812b;
|
device = ledDeviceWS2812b;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_WS281XPWM
|
||||||
|
else if (type == "ws281x")
|
||||||
|
{
|
||||||
|
const int gpio = deviceConfig.get("gpio", 18).asInt();
|
||||||
|
const int leds = deviceConfig.get("leds", 12).asInt();
|
||||||
|
const uint32_t freq = deviceConfig.get("freq", (Json::UInt)800000ul).asInt();
|
||||||
|
const int dmanum = deviceConfig.get("dmanum", 5).asInt();
|
||||||
|
|
||||||
|
LedDeviceWS281x * ledDeviceWS281x = new LedDeviceWS281x(gpio, leds, freq, dmanum);
|
||||||
|
device = ledDeviceWS281x;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
78
libsrc/leddevice/LedDeviceWS281x.cpp
Normal file
78
libsrc/leddevice/LedDeviceWS281x.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "LedDeviceWS281x.h"
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
LedDeviceWS281x::LedDeviceWS281x(const int gpio, const int leds, const uint32_t freq, const int dmanum)
|
||||||
|
{
|
||||||
|
initialized = false;
|
||||||
|
led_string.freq = freq;
|
||||||
|
led_string.dmanum = dmanum;
|
||||||
|
led_string.channel[0].gpionum = gpio;
|
||||||
|
led_string.channel[0].invert = 0;
|
||||||
|
led_string.channel[0].count = leds;
|
||||||
|
led_string.channel[0].brightness = 255;
|
||||||
|
led_string.channel[0].strip_type = WS2811_STRIP_RGB;
|
||||||
|
|
||||||
|
led_string.channel[1].gpionum = 0;
|
||||||
|
led_string.channel[1].invert = 0;
|
||||||
|
led_string.channel[1].count = 0;
|
||||||
|
led_string.channel[1].brightness = 0;
|
||||||
|
led_string.channel[0].strip_type = WS2811_STRIP_RGB;
|
||||||
|
if (ws2811_init(&led_string) < 0) {
|
||||||
|
std::cout << "Unable to initialize ws281x library." << std::endl;
|
||||||
|
throw -1;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send new values down the LED chain
|
||||||
|
int LedDeviceWS281x::write(const std::vector<ColorRgb> &ledValues)
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (const ColorRgb& color : ledValues)
|
||||||
|
{
|
||||||
|
if (idx >= led_string.channel[0].count)
|
||||||
|
break;
|
||||||
|
led_string.channel[0].leds[idx++] = ((uint32_t)color.red << 16) + ((uint32_t)color.green << 8) + color.blue;
|
||||||
|
}
|
||||||
|
while (idx < led_string.channel[0].count)
|
||||||
|
led_string.channel[0].leds[idx++] = 0;
|
||||||
|
|
||||||
|
if (ws2811_render(&led_string))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn off the LEDs by sending 000000's
|
||||||
|
// TODO Allow optional power switch out another gpio, if this code handles it can
|
||||||
|
// make it more likely we don't accidentally drive data into an off strip
|
||||||
|
int LedDeviceWS281x::switchOff()
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
while (idx < led_string.channel[0].count)
|
||||||
|
led_string.channel[0].leds[idx++] = 0;
|
||||||
|
|
||||||
|
if (ws2811_render(&led_string))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
LedDeviceWS281x::~LedDeviceWS281x()
|
||||||
|
{
|
||||||
|
if (initialized)
|
||||||
|
{
|
||||||
|
std::cout << "Shutdown WS281x PWM and DMA channel" << std::endl;
|
||||||
|
ws2811_fini(&led_string);
|
||||||
|
}
|
||||||
|
initialized = false;
|
||||||
|
}
|
43
libsrc/leddevice/LedDeviceWS281x.h
Normal file
43
libsrc/leddevice/LedDeviceWS281x.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef LEDDEVICEWS281X_H_
|
||||||
|
#define LEDDEVICEWS281X_H_
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <leddevice/LedDevice.h>
|
||||||
|
#include <ws2811.h>
|
||||||
|
|
||||||
|
class LedDeviceWS281x : public LedDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
///
|
||||||
|
/// Constructs the LedDevice for WS281x (one wire 800kHz)
|
||||||
|
///
|
||||||
|
/// @param gpio The gpio pin to use (BCM chip counting, default is 18)
|
||||||
|
/// @param leds The number of leds attached to the gpio pin
|
||||||
|
/// @param freq The target frequency for the data line, default is 800000
|
||||||
|
/// @param dmanum The DMA channel to use, default is 5
|
||||||
|
///
|
||||||
|
LedDeviceWS281x(const int gpio, const int leds, const uint32_t freq, int dmanum);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Destructor of the LedDevice, waits for DMA to complete and then cleans up
|
||||||
|
///
|
||||||
|
~LedDeviceWS281x();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 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:
|
||||||
|
ws2811_t led_string;
|
||||||
|
bool initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LEDDEVICEWS281X_H_ */
|
Loading…
Reference in New Issue
Block a user