mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
First working version with some test executables
This commit is contained in:
17
libsrc/hyperion/CMakeLists.txt
Normal file
17
libsrc/hyperion/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion)
|
||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
|
||||
|
||||
add_library(hyperion
|
||||
${CURRENT_HEADER_DIR}/Hyperion.h
|
||||
${CURRENT_HEADER_DIR}/LedDevice.h
|
||||
${CURRENT_HEADER_DIR}/LedString.h
|
||||
${CURRENT_HEADER_DIR}/ImageToLedsMap.h
|
||||
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedString.cpp
|
||||
${CURRENT_SOURCE_DIR}/Hyperion.cpp
|
||||
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
|
||||
)
|
101
libsrc/hyperion/Hyperion.cpp
Normal file
101
libsrc/hyperion/Hyperion.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
// Syslog include
|
||||
#include <syslog.h>
|
||||
|
||||
// JsonSchema include
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// hyperion include
|
||||
#include <hyperion/Hyperion.h>
|
||||
#include <hyperion/LedDevice.h>
|
||||
|
||||
#include "LedDeviceWs2801.h"
|
||||
|
||||
LedDevice* constructDevice(const Json::Value& deviceConfig)
|
||||
{
|
||||
std::cout << "Device configuration: " << deviceConfig << std::endl;
|
||||
LedDevice* device = nullptr;
|
||||
if (deviceConfig["type"].asString() == "ws2801")
|
||||
{
|
||||
const std::string name = "WS-2801";
|
||||
const std::string output = deviceConfig["output"].asString();
|
||||
const unsigned interval = deviceConfig["interval"].asInt();
|
||||
const unsigned rate = deviceConfig["rate"].asInt();
|
||||
|
||||
LedDeviceWs2801* deviceWs2801 = new LedDeviceWs2801(name, output, interval, rate);
|
||||
deviceWs2801->open();
|
||||
|
||||
device = deviceWs2801;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown / Unimplemented device
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||
mLedString(LedString::construct(jsonConfig["leds"], jsonConfig["color"])),
|
||||
mImage(nullptr),
|
||||
mDevice(constructDevice(jsonConfig["device"]))
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
Hyperion::~Hyperion()
|
||||
{
|
||||
// Delete the existing image (or delete nullptr)
|
||||
delete mImage;
|
||||
|
||||
// Delete the Led-String
|
||||
delete mDevice;
|
||||
}
|
||||
|
||||
void Hyperion::setInputSize(const unsigned width, const unsigned height)
|
||||
{
|
||||
// Delete the existing image (or delete nullptr)
|
||||
delete mImage;
|
||||
|
||||
// Create the new image with the mapping to the leds
|
||||
mImage = new RgbImage(width, height);
|
||||
mLedsMap.createMapping(*mImage, mLedString.leds());
|
||||
}
|
||||
|
||||
void Hyperion::commit()
|
||||
{
|
||||
// Derive the color per led
|
||||
const std::vector<RgbColor> ledColors = mLedsMap.getMedianLedColor();
|
||||
// Write the Led colors to the led-string
|
||||
mDevice->write(ledColors);
|
||||
}
|
||||
|
||||
void Hyperion::operator() (const RgbImage& inputImage)
|
||||
{
|
||||
std::cout << "Cached image size: [" << mImage->width() << "x" << mImage->height() << "]. Input image size: [" << inputImage.width() << "x" << inputImage.height() << "]" << std::endl;
|
||||
// Copy the input-image into the buffer
|
||||
mImage->copy(inputImage);
|
||||
|
||||
// Derive the color per led
|
||||
// std::vector<RgbColor> ledColors = mLedsMap.getMeanLedColor();
|
||||
std::vector<RgbColor> ledColors = mLedsMap.getMedianLedColor();
|
||||
applyTransform(ledColors);
|
||||
|
||||
// Write the Led colors to the led-string
|
||||
mDevice->write(ledColors);
|
||||
}
|
||||
|
||||
void Hyperion::setColor(const RgbColor& color)
|
||||
{
|
||||
mDevice->write(std::vector<RgbColor>(mLedString.leds().size(), color));
|
||||
}
|
||||
|
||||
void Hyperion::applyTransform(std::vector<RgbColor>& colors) const
|
||||
{
|
||||
for (RgbColor& color : colors)
|
||||
{
|
||||
color.red = (color.red < mLedString.red.blacklevel)? 0 : mLedString.red.adjust + mLedString.red.gamma * color.red;
|
||||
color.green = (color.green < mLedString.green.blacklevel)? 0 : mLedString.green.adjust + mLedString.green.gamma * color.green;
|
||||
color.blue = (color.blue < mLedString.blue.blacklevel)? 0 : mLedString.blue.adjust + mLedString.blue.gamma * color.blue;
|
||||
}
|
||||
}
|
90
libsrc/hyperion/ImageToLedsMap.cpp
Normal file
90
libsrc/hyperion/ImageToLedsMap.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
// STL includes
|
||||
#include <algorithm>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/ImageToLedsMap.h>
|
||||
|
||||
ImageToLedsMap::ImageToLedsMap()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
void ImageToLedsMap::createMapping(const RgbImage& image, const std::vector<Led>& leds)
|
||||
{
|
||||
mColorsMap.resize(leds.size(), std::vector<const RgbColor*>());
|
||||
|
||||
auto ledColors = mColorsMap.begin();
|
||||
for (auto led = leds.begin(); ledColors != mColorsMap.end() && led != leds.end(); ++ledColors, ++led)
|
||||
{
|
||||
ledColors->clear();
|
||||
|
||||
const unsigned minX_idx = unsigned(image.width() * led->minX_frac);
|
||||
const unsigned maxX_idx = unsigned(image.width() * led->maxX_frac);
|
||||
const unsigned minY_idx = unsigned(image.height() * led->minY_frac);
|
||||
const unsigned maxY_idx = unsigned(image.height() * led->maxY_frac);
|
||||
|
||||
for (unsigned y = minY_idx; y<=maxY_idx && y<image.height(); ++y)
|
||||
{
|
||||
for (unsigned x = minX_idx; x<=maxX_idx && x<image.width(); ++x)
|
||||
{
|
||||
ledColors->push_back(&image(x,y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageToLedsMap::getMeanLedColor()
|
||||
{
|
||||
std::vector<RgbColor> colors;
|
||||
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors)
|
||||
{
|
||||
const RgbColor color = findMeanColor(*ledColors);
|
||||
colors.push_back(color);
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
RgbColor ImageToLedsMap::findMeanColor(const std::vector<const RgbColor*>& colors)
|
||||
{
|
||||
uint_fast16_t cummRed = 0;
|
||||
uint_fast16_t cummGreen = 0;
|
||||
uint_fast16_t cummBlue = 0;
|
||||
for (const RgbColor* color : colors)
|
||||
{
|
||||
cummRed += color->red;
|
||||
cummGreen += color->green;
|
||||
cummBlue += color->blue;
|
||||
}
|
||||
|
||||
const uint8_t avgRed = uint8_t(cummRed/colors.size());
|
||||
const uint8_t avgGreen = uint8_t(cummGreen/colors.size());
|
||||
const uint8_t avgBlue = uint8_t(cummBlue/colors.size());
|
||||
|
||||
return {avgRed, avgGreen, avgBlue};
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageToLedsMap::getMedianLedColor()
|
||||
{
|
||||
std::vector<RgbColor> ledColors;
|
||||
for (std::vector<const RgbColor*>& colors : mColorsMap)
|
||||
{
|
||||
const RgbColor color = findMedianColor(colors);
|
||||
ledColors.push_back(color);
|
||||
}
|
||||
|
||||
return ledColors;
|
||||
}
|
||||
|
||||
RgbColor ImageToLedsMap::findMedianColor(std::vector<const RgbColor*>& colors)
|
||||
{
|
||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->red < rhs->red; });
|
||||
const uint8_t red = colors.at(colors.size()/2)->red;
|
||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->green < rhs->green; });
|
||||
const uint8_t green = colors.at(colors.size()/2)->green;
|
||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->blue < rhs->blue; });
|
||||
const uint8_t blue = colors.at(colors.size()/2)->blue;
|
||||
|
||||
return {red, green, blue};
|
||||
}
|
85
libsrc/hyperion/LedDeviceWs2801.cpp
Normal file
85
libsrc/hyperion/LedDeviceWs2801.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
// STL includes
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
// Linux includes
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
// hyperion local includes
|
||||
#include "LedDeviceWs2801.h"
|
||||
|
||||
LedDeviceWs2801::LedDeviceWs2801(const std::string& name,
|
||||
const std::string& outputDevice,
|
||||
const unsigned interval,
|
||||
const unsigned baudrate) :
|
||||
mDeviceName(outputDevice),
|
||||
mBaudRate_Hz(baudrate),
|
||||
mFid(-1)
|
||||
{
|
||||
memset(&spi, 0, sizeof(spi));
|
||||
|
||||
latchTime.tv_sec = 0;
|
||||
latchTime.tv_nsec = 500000;
|
||||
|
||||
}
|
||||
|
||||
LedDeviceWs2801::~LedDeviceWs2801()
|
||||
{
|
||||
// close(mFid);
|
||||
}
|
||||
|
||||
int LedDeviceWs2801::open()
|
||||
{
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
mFid = ::open(mDeviceName.c_str(), O_RDWR);
|
||||
|
||||
if (mFid < 0)
|
||||
{
|
||||
std::cerr << "Failed to open device('" << mDeviceName << "') " << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mode = SPI_MODE_0;
|
||||
if (ioctl(mFid, SPI_IOC_WR_MODE, &mode) == -1 || ioctl(mFid, SPI_IOC_RD_MODE, &mode) == -1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ioctl(mFid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(mFid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (ioctl(mFid, SPI_IOC_WR_MAX_SPEED_HZ, &mBaudRate_Hz) == -1 || ioctl(mFid, SPI_IOC_RD_MAX_SPEED_HZ, &mBaudRate_Hz) == -1)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceWs2801::write(const std::vector<RgbColor> &ledValues)
|
||||
{
|
||||
if (mFid < 0)
|
||||
{
|
||||
std::cerr << "Can not write to device which is open." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spi.tx_buf = (__u64)ledValues.data();
|
||||
spi.len = ledValues.size() * sizeof(RgbColor);
|
||||
|
||||
int retVal = ioctl(mFid, SPI_IOC_MESSAGE(1), &spi);
|
||||
|
||||
if (retVal == 0)
|
||||
{
|
||||
// Sleep to latch the leds (only if write succesfull)
|
||||
nanosleep(&latchTime, NULL);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
33
libsrc/hyperion/LedDeviceWs2801.h
Normal file
33
libsrc/hyperion/LedDeviceWs2801.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <string>
|
||||
|
||||
// Linux-SPI includes
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
// hyperion incluse
|
||||
#include <hyperion/LedDevice.h>
|
||||
|
||||
class LedDeviceWs2801 : public LedDevice
|
||||
{
|
||||
public:
|
||||
LedDeviceWs2801(const std::string& name,
|
||||
const std::string& outputDevice,
|
||||
const unsigned interval,
|
||||
const unsigned baudrate);
|
||||
|
||||
virtual ~LedDeviceWs2801();
|
||||
|
||||
int open();
|
||||
|
||||
virtual int write(const std::vector<RgbColor> &ledValues);
|
||||
|
||||
private:
|
||||
const std::string mDeviceName;
|
||||
const int mBaudRate_Hz;
|
||||
|
||||
int mFid;
|
||||
spi_ioc_transfer spi;
|
||||
timespec latchTime;
|
||||
};
|
60
libsrc/hyperion/LedString.cpp
Normal file
60
libsrc/hyperion/LedString.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// STL includes
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
// Json includes
|
||||
#include <json/json.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/LedString.h>
|
||||
|
||||
LedString LedString::construct(const Json::Value& ledsConfig, const Json::Value& colorConfig)
|
||||
{
|
||||
LedString ledString;
|
||||
|
||||
const Json::Value& redConfig = colorConfig["red"];
|
||||
const Json::Value& greenConfig = colorConfig["greem"];
|
||||
const Json::Value& blueConfig = colorConfig["blue"];
|
||||
|
||||
ledString.red.gamma = redConfig["gamma"].asDouble();
|
||||
ledString.red.adjust = redConfig["adjust"].asDouble();
|
||||
ledString.red.blacklevel = redConfig["blacklevel"].asDouble();
|
||||
|
||||
ledString.green.gamma = greenConfig["gamma"].asDouble();
|
||||
ledString.green.adjust = colorConfig["adjust"].asDouble();
|
||||
ledString.green.blacklevel = colorConfig["blacklevel"].asDouble();
|
||||
|
||||
ledString.blue.gamma = blueConfig["gamma"].asDouble();
|
||||
ledString.blue.adjust = blueConfig["adjust"].asDouble();
|
||||
ledString.blue.blacklevel = blueConfig["blacklevel"].asDouble();
|
||||
|
||||
for (const Json::Value& ledConfig : ledsConfig)
|
||||
{
|
||||
Led led;
|
||||
led.index = ledConfig["index"].asInt();
|
||||
const Json::Value& hscanConfig = ledConfig["hscan"];
|
||||
const Json::Value& vscanConfig = ledConfig["vscan"];
|
||||
led.minX_frac = std::max(0.0, std::min(100.0, hscanConfig["minimum"].asDouble()))/100.0;
|
||||
led.maxX_frac = std::max(0.0, std::min(100.0, hscanConfig["maximum"].asDouble()))/100.0;
|
||||
led.minY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["maximum"].asDouble()))/100.0;
|
||||
led.maxY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["minimum"].asDouble()))/100.0;
|
||||
|
||||
ledString.mLeds.push_back(led);
|
||||
}
|
||||
return ledString;
|
||||
}
|
||||
|
||||
LedString::LedString()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
LedString::~LedString()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<Led>& LedString::leds() const
|
||||
{
|
||||
return mLeds;
|
||||
}
|
Reference in New Issue
Block a user