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:
44
src/CMakeLists.txt
Normal file
44
src/CMakeLists.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
# Find the libPNG
|
||||
find_package(PNG REQUIRED QUIET)
|
||||
|
||||
# Add additional includes dirs
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
|
||||
# Add the simple test executable 'TestSpi'
|
||||
add_executable(TestSpi
|
||||
TestSpi.cpp)
|
||||
|
||||
target_link_libraries(TestSpi
|
||||
hyperion
|
||||
hyperion-utils)
|
||||
|
||||
add_executable(TestHyperionPng
|
||||
TestHyperionPng.cpp)
|
||||
|
||||
target_link_libraries(TestHyperionPng
|
||||
hyperion-png)
|
||||
|
||||
add_executable(WriteConfig
|
||||
WriteConfig.cpp)
|
||||
|
||||
add_executable(TestConfigFile
|
||||
TestConfigFile.cpp)
|
||||
|
||||
target_link_libraries(TestConfigFile
|
||||
hyperion-utils
|
||||
hyperion)
|
||||
|
||||
add_executable(ViewPng
|
||||
ViewPng.cpp)
|
||||
|
||||
target_link_libraries(ViewPng
|
||||
hyperion
|
||||
hyperion-utils
|
||||
${PNG_LIBRARIES})
|
||||
|
||||
add_executable(Test2BobLight
|
||||
Test2BobLight.cpp)
|
||||
|
||||
target_link_libraries(Test2BobLight
|
||||
bob2hyperion)
|
115
src/FbWriter.h
Normal file
115
src/FbWriter.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
class FbWriter
|
||||
{
|
||||
public:
|
||||
FbWriter()
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
|
||||
~FbWriter()
|
||||
{
|
||||
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo))
|
||||
{
|
||||
printf("Error re-setting variable information.\n");
|
||||
}
|
||||
|
||||
close(fbfd);
|
||||
}
|
||||
|
||||
int initialise()
|
||||
{
|
||||
// Open the file for reading and writing
|
||||
fbfd = open("/dev/fb0", O_RDWR);
|
||||
if (!fbfd)
|
||||
{
|
||||
printf("Error: cannot open framebuffer device.\n");
|
||||
return(-1);
|
||||
}
|
||||
printf("The framebuffer device was opened successfully.\n");
|
||||
|
||||
// Get fixed screen information
|
||||
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
|
||||
{
|
||||
printf("Error reading fixed information.\n");
|
||||
}
|
||||
// Get variable screen information
|
||||
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &orig_vinfo))
|
||||
{
|
||||
printf("Error reading variable information.\n");
|
||||
}
|
||||
printf("Original %dx%d, %dbpp\n", orig_vinfo.xres, orig_vinfo.yres, orig_vinfo.bits_per_pixel );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writeImage(const RgbImage& image)
|
||||
{
|
||||
std::cout << "Writing image [" << image.width() << "x" << image.height() << "]" << std::endl;
|
||||
|
||||
// Make a copy of the original screen-info
|
||||
fb_var_screeninfo vinfo = orig_vinfo;
|
||||
// memcpy(&vinfo, &orig_vinfo, sizeof(fb_var_screeninfo));
|
||||
|
||||
// Configure the frame-buffer for the new image
|
||||
vinfo.xres = image.width();
|
||||
vinfo.yres = image.height();
|
||||
vinfo.bits_per_pixel = 24;
|
||||
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
|
||||
{
|
||||
printf("Error configuring frame-buffer");
|
||||
}
|
||||
|
||||
ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
||||
std::cout << "New set resolution: " << vinfo.xres << "x" << vinfo.yres << std::endl;
|
||||
|
||||
// map fb to user mem
|
||||
long screensize = vinfo.yres * finfo.line_length;//vinfo.yres * vinfo.bits_per_pixel / 8;
|
||||
char* fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
|
||||
if (!fbp)
|
||||
{
|
||||
// Failed to create memory map
|
||||
std::cout << "Failed to create the memory map" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << "Screensize : " << screensize << std::endl;
|
||||
std::cout << "Max fb-index: " << (image.width()-1)*3 + (image.height()-1)*finfo.line_length << std::endl;
|
||||
std::cout << "[" << vinfo.xres << "x" << vinfo.yres << "] == [" << image.width() << "x" << image.height() << "]" << std::endl;
|
||||
|
||||
for (unsigned iY=0; iY<image.height(); ++iY)
|
||||
{
|
||||
memcpy(fbp + iY*finfo.line_length, &(image(0, iY)), image.width()*3);
|
||||
// for (unsigned iX=0; iX<image.width(); ++iX)
|
||||
// {
|
||||
// const unsigned pixOffset = iX*3 + iY*finfo.line_length;
|
||||
// fbp[pixOffset ] = image(iX, iY).red;
|
||||
// fbp[pixOffset+1] = image(iX, iY).green;
|
||||
// fbp[pixOffset+2] = image(iX, iY).blue;
|
||||
// }
|
||||
}
|
||||
std::cout << "FINISHED COPYING IMAGE TO FRAMEBUFFER" << std::endl;
|
||||
// cleanup
|
||||
munmap(fbp, screensize);
|
||||
}
|
||||
|
||||
// The identifier of the FrameBuffer File-Device
|
||||
int fbfd;
|
||||
// The 'Fixed' screen information
|
||||
fb_fix_screeninfo finfo;
|
||||
// The original 'Variable' screen information
|
||||
fb_var_screeninfo orig_vinfo;
|
||||
};
|
39
src/Test2BobLight.cpp
Normal file
39
src/Test2BobLight.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
void* boblight_ptr = boblight_init();
|
||||
if (!boblight_ptr)
|
||||
{
|
||||
std::cerr << "Failed to initialise bob-light" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const unsigned width = 112;
|
||||
const unsigned height = 63;
|
||||
|
||||
boblight_setscanrange(boblight_ptr, width, height);
|
||||
|
||||
std::vector<int> rgbColor = { 255, 255, 0 };
|
||||
for (unsigned iY=0; iY<height; ++iY)
|
||||
{
|
||||
for (unsigned iX=0; iX<width; ++iX)
|
||||
{
|
||||
boblight_addpixelxy(boblight_ptr, iX, iY, rgbColor.data());
|
||||
}
|
||||
}
|
||||
boblight_sendrgb(boblight_ptr, 0, nullptr);
|
||||
|
||||
//sleep(5);
|
||||
|
||||
boblight_destroy(boblight_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
16
src/TestBoblightOrig.cpp
Normal file
16
src/TestBoblightOrig.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "TestBoblightOrig started" << std::endl;
|
||||
|
||||
std::cout << "TestBoblightOrig finished" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
38
src/TestConfigFile.cpp
Normal file
38
src/TestConfigFile.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
// STL includes
|
||||
#include <cstdlib>
|
||||
|
||||
// JsonSchema includes
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/LedString.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string homeDir = getenv("RASPILIGHT_HOME");
|
||||
|
||||
const std::string schemaFile = homeDir + "/hyperion.schema.json";
|
||||
const std::string configFile = homeDir + "/hyperion.config.json";
|
||||
|
||||
Json::Value config;
|
||||
if (JsonFactory::load(schemaFile, configFile, config) < 0)
|
||||
{
|
||||
std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Json::Value& deviceConfig = config["device"];
|
||||
const Json::Value& ledConfig = config["leds"];
|
||||
const Json::Value& colorConfig = config["color"];
|
||||
|
||||
std::cout << "COLOR CONFIGURATION: " << colorConfig.toStyledString() << std::endl;
|
||||
|
||||
const Json::Value& redConfig = colorConfig["red"];
|
||||
double redGamma = redConfig["gamma"].asDouble();
|
||||
std::cout << "RED GAMMA = " << redGamma << std::endl;
|
||||
std::cout << "RED GAMMA = " << colorConfig["red.gamma"].asDouble() << std::endl;
|
||||
LedString ledString = LedString::construct(ledConfig, colorConfig);
|
||||
|
||||
return 0;
|
||||
}
|
43
src/TestHyperionPng.cpp
Normal file
43
src/TestHyperionPng.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "Initialisaing Boblight" << std::endl;
|
||||
void* blPng = boblight_init();
|
||||
|
||||
int width = 112;
|
||||
int height = 64;
|
||||
std::cout << "Defining scan range (" << width << "x" << height << ")" << std::endl;
|
||||
boblight_setscanrange(blPng, width, height);
|
||||
|
||||
int colorPtr[3];
|
||||
colorPtr[0] = 255;
|
||||
colorPtr[1] = 0;
|
||||
colorPtr[2] = 0;
|
||||
std::cout << "Using color [" << colorPtr[0] << "; " << colorPtr[1] << "; " << colorPtr[2] << "]" << std::endl;
|
||||
|
||||
int nrOfFrames = 150;
|
||||
std::cout << "Generating " << nrOfFrames << " frames" << std::endl;
|
||||
for (int iFrame=0; iFrame<nrOfFrames; ++iFrame)
|
||||
{
|
||||
for (int iWidth=0; iWidth<width; ++iWidth)
|
||||
{
|
||||
for (int iHeight=0; iHeight<height; ++iHeight)
|
||||
{
|
||||
boblight_addpixelxy(blPng, iWidth, iHeight, colorPtr);
|
||||
}
|
||||
}
|
||||
|
||||
boblight_sendrgb(blPng, 0, NULL);
|
||||
}
|
||||
|
||||
std::cout << "Destroying Boblight" << std::endl;
|
||||
boblight_destroy(blPng);
|
||||
|
||||
return 0;
|
||||
}
|
161
src/TestSpi.cpp
Normal file
161
src/TestSpi.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
// STL includes
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
// Local includes
|
||||
#include <utils/RgbColor.h>
|
||||
|
||||
#include "../libsrc/hyperion/LedDeviceWs2801.h"
|
||||
|
||||
void setColor(char* colorStr)
|
||||
{
|
||||
RgbColor color = RgbColor::BLACK;
|
||||
std::cout << "Switching all leds to: ";
|
||||
if (strncmp("red", colorStr, 3) == 0)
|
||||
{
|
||||
std::cout << "red";
|
||||
color = RgbColor::RED;
|
||||
}
|
||||
else if (strncmp("green", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "green";
|
||||
color = RgbColor::GREEN;
|
||||
}
|
||||
else if (strncmp("blue", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "blue";
|
||||
color = RgbColor::BLUE;
|
||||
}
|
||||
else if (strncmp("cyan", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "cyan";
|
||||
}
|
||||
else if (strncmp("gray", colorStr, 4) == 0)
|
||||
{
|
||||
std::cout << "gray";
|
||||
}
|
||||
else if (strncmp("white", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "white";
|
||||
color = RgbColor::WHITE;
|
||||
}
|
||||
else if (strncmp("black", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "black";
|
||||
color = RgbColor::BLACK;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
unsigned ledCnt = 50;
|
||||
std::vector<RgbColor> buff(ledCnt, color);
|
||||
|
||||
LedDeviceWs2801 ledDevice("SpiPi", "/dev/spidev0.0", 20000, 40000);
|
||||
ledDevice.open();
|
||||
ledDevice.write(buff);
|
||||
}
|
||||
|
||||
bool _running = true;
|
||||
void doCircle()
|
||||
{
|
||||
RgbColor color_1 = RgbColor::RED;
|
||||
RgbColor color_2 = RgbColor::YELLOW;
|
||||
|
||||
unsigned ledCnt = 50;
|
||||
std::vector<RgbColor> data(ledCnt, RgbColor::BLACK);
|
||||
|
||||
LedDeviceWs2801 ledDevice("SpiPi", "/dev/spidev0.0", 20000, 40000);
|
||||
ledDevice.open();
|
||||
|
||||
timespec loopTime;
|
||||
loopTime.tv_sec = 0;
|
||||
loopTime.tv_nsec = 100000000; // 100 ms
|
||||
|
||||
int curLed_1 = 0;
|
||||
int nextLed_1 = 1;
|
||||
|
||||
int curLed_2 = 49;
|
||||
int nextLed_2 = 48;
|
||||
|
||||
|
||||
while (_running)
|
||||
{
|
||||
data[curLed_1] = RgbColor::BLACK;
|
||||
data[curLed_2] = RgbColor::BLACK;
|
||||
|
||||
// Move the current and the next pointer
|
||||
curLed_1 = nextLed_1;
|
||||
curLed_2 = nextLed_2;
|
||||
++nextLed_1;
|
||||
--nextLed_2;
|
||||
if (nextLed_1 == int(ledCnt))
|
||||
{
|
||||
nextLed_1 = 0;
|
||||
}
|
||||
if (nextLed_2 < 0)
|
||||
{
|
||||
nextLed_2 = 49;
|
||||
}
|
||||
|
||||
data[curLed_1] = color_1;
|
||||
|
||||
data[curLed_2] = color_2;
|
||||
|
||||
ledDevice.write(data);
|
||||
|
||||
nanosleep(&loopTime, NULL);
|
||||
}
|
||||
|
||||
// Switch the current leds off
|
||||
data[curLed_1] = RgbColor::BLACK;
|
||||
data[curLed_2] = RgbColor::BLACK;
|
||||
|
||||
ledDevice.write(data);
|
||||
}
|
||||
|
||||
#include <csignal>
|
||||
|
||||
void signal_handler(int signum)
|
||||
{
|
||||
_running = false;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (sizeof(RgbColor) != 3)
|
||||
{
|
||||
std::cout << "sizeof(RgbColor) = " << sizeof(RgbColor) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Install signal handlers to stop loops
|
||||
signal(SIGTERM, &signal_handler);
|
||||
signal(SIGINT, &signal_handler);
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cerr << "Missing argument" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp("fixed", argv[1], 5) == 0)
|
||||
{
|
||||
setColor(argv[2]);
|
||||
return 0;
|
||||
}
|
||||
else if (strncmp("circle", argv[1], 6) == 0)
|
||||
{
|
||||
doCircle();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unknown option: " << argv[1] << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
155
src/ViewPng.cpp
Normal file
155
src/ViewPng.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
// LibPNG includes
|
||||
#include <png.h>
|
||||
|
||||
// Utils includes
|
||||
#include <utils/RgbImage.h>
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// Raspilight includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
|
||||
// Local includes
|
||||
#include "FbWriter.h"
|
||||
|
||||
bool read_png(std::string file_name, RgbImage*& rgbImage)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen(file_name.c_str(), "rb")) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
if (png_ptr == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_SWAP_ALPHA | PNG_TRANSFORM_EXPAND, NULL);
|
||||
|
||||
png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
|
||||
png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
png_uint_32 channels = png_get_channels(png_ptr, info_ptr);
|
||||
png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
|
||||
std::cout << "BitDepth" << std::endl;
|
||||
std::cout << bitdepth << std::endl;
|
||||
std::cout << "Channels" << std::endl;
|
||||
std::cout << channels << std::endl;
|
||||
std::cout << "ColorType" << std::endl;
|
||||
std::cout << color_type << std::endl;
|
||||
|
||||
png_bytepp row_pointers;
|
||||
row_pointers = png_get_rows(png_ptr, info_ptr);
|
||||
|
||||
rgbImage = new RgbImage(width, height);
|
||||
|
||||
for (unsigned iRow=0; iRow<height; ++iRow)
|
||||
{
|
||||
if (color_type == PNG_COLOR_TYPE_RGB)
|
||||
{
|
||||
RgbColor* rowPtr = reinterpret_cast<RgbColor*>(row_pointers[iRow]);
|
||||
for (unsigned iCol=0; iCol<width; ++iCol)
|
||||
{
|
||||
rgbImage->setPixel(iCol, iRow, rowPtr[iCol]);
|
||||
}
|
||||
}
|
||||
else if (color_type == PNG_COLOR_TYPE_RGBA)
|
||||
{
|
||||
unsigned* rowPtr = reinterpret_cast<unsigned*>(row_pointers[iRow]);
|
||||
for (unsigned iCol=0; iCol<width; ++iCol)
|
||||
{
|
||||
const unsigned argbValue = rowPtr[iCol];
|
||||
rgbImage->setPixel(iCol, iRow, {uint8_t((argbValue >> 16) & 0xFF), uint8_t((argbValue >> 8) & 0xFF), uint8_t((argbValue) & 0xFF)});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown/Unimplemented color-format
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
// Missing required argument
|
||||
std::cout << "Missing PNG-argumet. Usage: 'ViewPng [png-file]" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string pngFilename = argv[1];
|
||||
|
||||
RgbImage* image = nullptr;
|
||||
if (!read_png(pngFilename, image) || image == nullptr)
|
||||
{
|
||||
std::cout << "Failed to load image" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* homeDir = getenv("RASPILIGHT_HOME");
|
||||
if (!homeDir)
|
||||
{
|
||||
homeDir = "/home/pi";
|
||||
}
|
||||
|
||||
std::cout << "RASPILIGHT HOME DIR: " << homeDir << std::endl;
|
||||
|
||||
const std::string schemaFile = std::string(homeDir) + "/hyperion.schema.json";
|
||||
const std::string configFile = std::string(homeDir) + "/hyperion.config.json";
|
||||
|
||||
Json::Value raspiConfig;
|
||||
if (JsonFactory::load(schemaFile, configFile, raspiConfig) < 0)
|
||||
{
|
||||
std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "Loaded configuration: " << raspiConfig << std::endl;
|
||||
|
||||
FbWriter fbWriter;
|
||||
|
||||
Hyperion raspiLight(raspiConfig);
|
||||
raspiLight.setInputSize(image->width(), image->height());
|
||||
|
||||
fbWriter.writeImage(*image);
|
||||
raspiLight(*image);
|
||||
|
||||
sleep(5);
|
||||
|
||||
delete image;
|
||||
}
|
198
src/WriteConfig.cpp
Normal file
198
src/WriteConfig.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
// STL includes
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ofstream& indent(ofstream& ofs, unsigned indent)
|
||||
{
|
||||
for (unsigned i=0; i<indent; ++i)
|
||||
{
|
||||
ofs << '\t';
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
|
||||
struct LedFrame
|
||||
{
|
||||
unsigned topLedCnt = 17;
|
||||
unsigned rightLedCnt = 8;
|
||||
unsigned bottomLedCnt = 17;
|
||||
unsigned leftLedCnt = 8;
|
||||
|
||||
unsigned topLeftOffset = 17;
|
||||
|
||||
unsigned borderWidth = 10;
|
||||
unsigned borderHeight = 10;
|
||||
|
||||
unsigned totalLedCnt() const
|
||||
{
|
||||
return topLeftOffset + rightLedCnt + bottomLedCnt + leftLedCnt;
|
||||
}
|
||||
};
|
||||
|
||||
struct Led
|
||||
{
|
||||
unsigned index;
|
||||
double minX;
|
||||
double maxX;
|
||||
double minY;
|
||||
double maxY;
|
||||
};
|
||||
|
||||
void determineBoundaries(const LedFrame& ledFrame, const unsigned iLed, double& minX, double& maxX, double& minY, double& maxY)
|
||||
{
|
||||
if (iLed < ledFrame.topLedCnt)
|
||||
{
|
||||
// TOP of screen
|
||||
minX = iLed * 100.0/ledFrame.topLedCnt;
|
||||
maxX = (iLed+1) * 100.0/ledFrame.topLedCnt;
|
||||
|
||||
minY = 100.0 - ledFrame.borderHeight;
|
||||
maxY = 100.0;
|
||||
}
|
||||
else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt))
|
||||
{
|
||||
// RIGHT of screen
|
||||
minX = 100.0 - ledFrame.borderWidth;
|
||||
maxX = 100.0;
|
||||
|
||||
minY = 100.0 - (iLed-15) * 100.0/(ledFrame.rightLedCnt+2);
|
||||
maxY = 100.0 - (iLed-16) * 100.0/(ledFrame.rightLedCnt+2);
|
||||
}
|
||||
else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt+ledFrame.bottomLedCnt))
|
||||
{
|
||||
// BOTTOM of screen
|
||||
minX = 100.0 - (iLed-24) * 100.0/ledFrame.bottomLedCnt;
|
||||
maxX = 100.0 - (iLed-25) * 100.0/ledFrame.bottomLedCnt;
|
||||
|
||||
minY = 0.0;
|
||||
maxY = ledFrame.borderHeight;
|
||||
}
|
||||
else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt+ledFrame.bottomLedCnt+ledFrame.leftLedCnt))
|
||||
{
|
||||
// LEFT of screen
|
||||
minX = 0.0;
|
||||
maxX = ledFrame.borderWidth;
|
||||
|
||||
minY = (iLed-41) * 100.0/(ledFrame.leftLedCnt+2);
|
||||
maxY = (iLed-40) * 100.0/(ledFrame.leftLedCnt+2);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Requested led index(" << iLed << ") out of bound" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Led> createLedMapping(const LedFrame ledFrame)
|
||||
{
|
||||
std::vector<Led> leds;
|
||||
for (unsigned iLed=0; iLed<ledFrame.totalLedCnt(); ++iLed)
|
||||
{
|
||||
Led led;
|
||||
|
||||
led.index = (iLed + ledFrame.topLeftOffset)%ledFrame.totalLedCnt();
|
||||
determineBoundaries(ledFrame, iLed, led.minX, led.maxX, led.minY, led.maxY);
|
||||
|
||||
leds.push_back(led);
|
||||
}
|
||||
|
||||
std::sort(leds.begin(), leds.end(), [](const Led& lhs, const Led& rhs){ return lhs.index < rhs.index; });
|
||||
|
||||
return leds;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const std::string filename = "hyperion.config.json";
|
||||
|
||||
LedFrame myFrame;
|
||||
std::vector<Led> leds = createLedMapping(myFrame);
|
||||
ofstream configOfs(filename.c_str());
|
||||
|
||||
configOfs << "// Automatically generated configuration file for 'Hyperion'" << endl;
|
||||
configOfs << "// Generation script: " << argv[0] << endl;
|
||||
configOfs << endl;
|
||||
configOfs << "{" << endl;
|
||||
|
||||
// Write the device section
|
||||
indent(configOfs, 1) << R"("device" : )" << endl;
|
||||
indent(configOfs, 1) << "{" << endl;
|
||||
indent(configOfs, 2) << R"("name" : "MyPi",)" << endl;
|
||||
indent(configOfs, 2) << R"("type" : "ws2801",)" << endl;
|
||||
indent(configOfs, 2) << R"("output" : "/dev/spidev0.0",)" << endl;
|
||||
indent(configOfs, 2) << R"("interval" : 20000,)" << endl;
|
||||
indent(configOfs, 2) << R"("rate" : 48000)" << endl;
|
||||
indent(configOfs, 1) << "}," << endl;
|
||||
|
||||
// Write the color-correction section
|
||||
indent(configOfs, 1) << R"("color" : )" << endl;
|
||||
indent(configOfs, 1) << "{" << endl;
|
||||
indent(configOfs, 2) << R"("red" : )" << endl;
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("gamma" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("adjust" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl;
|
||||
indent(configOfs, 2) << "}," << endl;
|
||||
indent(configOfs, 2) << R"("green" : )" << endl;
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("gamma" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("adjust" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl;
|
||||
indent(configOfs, 2) << "}," << endl;
|
||||
indent(configOfs, 2) << R"("blue" : )" << endl;
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("gamma" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("adjust" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl;
|
||||
indent(configOfs, 2) << "}" << endl;
|
||||
indent(configOfs, 1) << "}," << endl;
|
||||
|
||||
// Write the leds section
|
||||
indent(configOfs, 1) << R"("leds" : )" << endl;
|
||||
indent(configOfs, 1) << "[" << endl;
|
||||
for (const Led& led : leds)
|
||||
{
|
||||
// Add comments indicating the corners of the configuration
|
||||
if (led.minX == 0.0)
|
||||
{
|
||||
if (led.minY == 0.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// TOP-LEFT Corner" << endl;
|
||||
}
|
||||
else if (led.maxY == 100.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// BOTTOM-LEFT Corner" << endl;
|
||||
}
|
||||
}
|
||||
else if (led.maxX == 100.0)
|
||||
{
|
||||
if (led.minY == 0.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// TOP-RIGHT Corner" << endl;
|
||||
}
|
||||
else if (led.maxY == 100.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// BOTTOM-RIGHT Corner" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the configuration of the led
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("index" : )" << led.index << "," << endl;
|
||||
indent(configOfs, 3) << R"("hscan" : { "minimum" : )" << led.minX << R"(, "maximum" : )" << led.maxX << R"( },)" << endl;
|
||||
indent(configOfs, 3) << R"("vscan" : { "minimum" : )" << led.minY << R"(, "maximum" : )" << led.maxY << R"( })" << endl;
|
||||
indent(configOfs, 2) << "}";
|
||||
if (led.index != leds.back().index)
|
||||
{
|
||||
configOfs << ",";
|
||||
}
|
||||
configOfs << endl;
|
||||
}
|
||||
indent(configOfs, 1) << "]" << endl;
|
||||
|
||||
configOfs << "}" << endl;
|
||||
}
|
Reference in New Issue
Block a user