From 39b98386ddd73fc91318862a966935d345b34c9e Mon Sep 17 00:00:00 2001 From: "T. van der Zwan" Date: Tue, 13 Aug 2013 11:10:45 +0200 Subject: [PATCH] Added simple QT-based grabber. Moved ImageToLedsMap from include to libsrc. Moved instantiation of objects to Hyperion (no JSON required outside this class). --- CMakeLists.txt | 11 +- include/hyperion/DispmanxWrapper.h | 32 +++ include/hyperion/Hyperion.h | 26 +- include/hyperion/ImageProcessor.h | 72 ++++++ include/hyperion/ImageProcessorFactory.h | 26 ++ include/hyperion/ImageToLedsMap.h | 27 --- include/hyperion/LedString.h | 18 +- include/hyperion/PriorityMuxer.h | 55 +++++ include/utils/RgbColor.h | 5 +- libsrc/CMakeLists.txt | 22 +- libsrc/bob2hyperion.cpp | 8 +- libsrc/hyperion/CMakeLists.txt | 44 +++- libsrc/hyperion/ColorTransform.cpp | 97 ++++---- libsrc/hyperion/ColorTransform.h | 52 ++-- libsrc/hyperion/DispmanxFrameGrabber.cpp | 54 +++++ libsrc/hyperion/DispmanxFrameGrabber.h | 35 +++ libsrc/hyperion/DispmanxWrapper.cpp | 46 ++++ libsrc/hyperion/Hyperion.cpp | 104 ++++---- libsrc/hyperion/ImageProcessor.cpp | 65 +++++ libsrc/hyperion/ImageProcessorFactory.cpp | 21 ++ libsrc/hyperion/ImageToLedsMap.cpp | 46 ++-- libsrc/hyperion/ImageToLedsMap.h | 57 +++++ libsrc/hyperion/LedString.cpp | 40 +--- libsrc/hyperion/PriorityMuxer.cpp | 94 ++++++++ src/CMakeLists.txt | 16 +- src/HyperionDispmanX.cpp | 2 +- src/HyperionMain.cpp | 17 ++ src/ViewPng.cpp | 4 +- src/flagmanager.cpp | 274 +++++++++++----------- src/misc.h | 42 ++-- test/TestColorTransform.cpp | 159 +++++++------ test/TestConfigFile.cpp | 2 +- 32 files changed, 1065 insertions(+), 508 deletions(-) create mode 100644 include/hyperion/DispmanxWrapper.h create mode 100644 include/hyperion/ImageProcessor.h create mode 100644 include/hyperion/ImageProcessorFactory.h delete mode 100644 include/hyperion/ImageToLedsMap.h create mode 100644 include/hyperion/PriorityMuxer.h create mode 100644 libsrc/hyperion/DispmanxFrameGrabber.cpp create mode 100644 libsrc/hyperion/DispmanxFrameGrabber.h create mode 100644 libsrc/hyperion/DispmanxWrapper.cpp create mode 100644 libsrc/hyperion/ImageProcessor.cpp create mode 100644 libsrc/hyperion/ImageProcessorFactory.cpp create mode 100644 libsrc/hyperion/ImageToLedsMap.h create mode 100644 libsrc/hyperion/PriorityMuxer.cpp create mode 100644 src/HyperionMain.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d42a4d63..5c5759ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # define the minimum cmake version (as required by cmake) cmake_minimum_required(VERSION 2.8) -#set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake) +set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake) # Define the main-project name project(Hyperion) @@ -28,6 +28,15 @@ set(CMAKE_BUILD_TYPE "Release") # enable C++11 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall") +# Configure the use of QT4 +find_package(Qt4 COMPONENTS QtCore REQUIRED QUIET) + +SET(QT_DONT_USE_QTGUI TRUE) +SET(QT_USE_QTCONSOLE TRUE) +include(${QT_USE_FILE}) +add_definitions(${QT_DEFINITIONS}) +link_directories(${CMAKE_FIND_ROOT_PATH}/lib/arm-linux-gnueabihf) + configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY) configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY) configure_file(config/hyperion.schema.json ${LIBRARY_OUTPUT_PATH} @ONLY) diff --git a/include/hyperion/DispmanxWrapper.h b/include/hyperion/DispmanxWrapper.h new file mode 100644 index 00000000..4d9b5649 --- /dev/null +++ b/include/hyperion/DispmanxWrapper.h @@ -0,0 +1,32 @@ +#pragma once + +// QT includes +#include +#include + +// Forward class declaration +class ImageProcessor; +class DispmanxFrameGrabber; + +class DispmanxWrapper: public QObject +{ + Q_OBJECT +public: + DispmanxWrapper(); + + virtual ~DispmanxWrapper(); + +public slots: + void start(); + + void action(); + + void stop(); + +private: + QTimer _timer; + + DispmanxFrameGrabber* _frameGrabber; + ImageProcessor* _processor; +}; + diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 1f3113de..e278bef3 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -4,9 +4,14 @@ // hyperion-utils includes #include +// Hyperion includes #include -#include #include +#include + +// Forward class declaration +namespace hyperion { class ColorTransform; } + class Hyperion { @@ -15,27 +20,18 @@ public: ~Hyperion(); - void setInputSize(const unsigned width, const unsigned height); - - RgbImage& image() - { - return *mImage; - } - - void commit(); - - void operator() (const RgbImage& inputImage); - - void setColor(const RgbColor& color); + void setValue(int priority, std::vector &ledColors); private: void applyTransform(std::vector& colors) const; LedString mLedString; - RgbImage* mImage; + PriorityMuxer mMuxer; - ImageToLedsMap mLedsMap; + hyperion::ColorTransform* mRedTransform; + hyperion::ColorTransform* mGreenTransform; + hyperion::ColorTransform* mBlueTransform; LedDevice* mDevice; }; diff --git a/include/hyperion/ImageProcessor.h b/include/hyperion/ImageProcessor.h new file mode 100644 index 00000000..26abaa8b --- /dev/null +++ b/include/hyperion/ImageProcessor.h @@ -0,0 +1,72 @@ + +#pragma once + +// Utils includes +#include + +#include +#include + +// Forward class declaration +namespace hyperion { class ImageToLedsMap; + class ColorTransform; } + +/** + * The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is + * performed in two steps. First the average color per led-region is computed. Second a + * color-tranform is applied based on a gamma-correction. + */ +class ImageProcessor +{ +public: + /** + * Processes the image to a list of led colors. This will update the size of the buffer-image + * if required and call the image-to-leds mapping to determine the mean color per led. + * + * @param[in] image The image to translate to led values + * + * @return The color value per led + */ + std::vector process(const RgbImage& image); + + // 'IN PLACE' processing functions + + /** + * Specifies the width and height of 'incomming' images. This will resize the buffer-image to + * match the given size. + * NB All earlier obtained references will be invalid. + * + * @param[in] width The new width of the buffer-image + * @param[in] height The new height of the buffer-image + */ + void setSize(const unsigned width, const unsigned height); + + /** + * Returns a reference of the underlying image-buffer. This can be used to write data directly + * into the buffer, avoiding a copy inside the process method. + * + * @return The reference of the underlying image-buffer. + */ + RgbImage& image(); + + /** + * Determines the led colors of the image in the buffer. + * + * @param[out] ledColors The color value per led + */ + void inplace_process(std::vector& ledColors); + +private: + friend class ImageProcessorFactory; + + ImageProcessor(const LedString &ledString); + + ~ImageProcessor(); + +private: + const LedString mLedString; + + RgbImage *mBuffer; + hyperion::ImageToLedsMap* mImageToLeds; +}; + diff --git a/include/hyperion/ImageProcessorFactory.h b/include/hyperion/ImageProcessorFactory.h new file mode 100644 index 00000000..dc558371 --- /dev/null +++ b/include/hyperion/ImageProcessorFactory.h @@ -0,0 +1,26 @@ +#pragma once + +// STL includes +#include + +// Jsoncpp includes +#include + +#include + +// Forward class declaration +class ImageProcessor; + +class ImageProcessorFactory +{ +public: + static ImageProcessorFactory& getInstance(); + +public: + void init(const LedString& ledString); + + ImageProcessor* newImageProcessor() const; + +private: + LedString _ledString; +}; diff --git a/include/hyperion/ImageToLedsMap.h b/include/hyperion/ImageToLedsMap.h deleted file mode 100644 index cc00972e..00000000 --- a/include/hyperion/ImageToLedsMap.h +++ /dev/null @@ -1,27 +0,0 @@ - -#pragma once - -// hyperion-utils includes -#include - -// hyperion includes -#include - -class ImageToLedsMap -{ -public: - - ImageToLedsMap(); - - void createMapping(const RgbImage& image, const std::vector& leds); - - std::vector getMeanLedColor(); - - RgbColor findMeanColor(const std::vector& colors); - - std::vector getMedianLedColor(); - - RgbColor findMedianColor(std::vector& colors); -private: - std::vector > mColorsMap; -}; diff --git a/include/hyperion/LedString.h b/include/hyperion/LedString.h index cc105b38..cc4962ff 100644 --- a/include/hyperion/LedString.h +++ b/include/hyperion/LedString.h @@ -45,28 +45,16 @@ struct Led class LedString { public: - static LedString construct(const Json::Value& ledConfig, const Json::Value& colorConfig); + static LedString construct(const Json::Value& ledConfig); LedString(); ~LedString(); + std::vector& leds(); + const std::vector& leds() const; private: std::vector mLeds; - -public: - /** - * Color adjustements per color - */ - struct - { - /** The color gradient */ - double gamma; - /** The color offset */ - double adjust; - /** The minimum required level for the led to turn on */ - double blacklevel; - } red, green, blue; }; diff --git a/include/hyperion/PriorityMuxer.h b/include/hyperion/PriorityMuxer.h new file mode 100644 index 00000000..c2e05fdf --- /dev/null +++ b/include/hyperion/PriorityMuxer.h @@ -0,0 +1,55 @@ +#pragma once + +// STL includes +#include +#include +#include +#include + +// QT includes +#include + +// Utils includes +#include + +// Hyperion includes +#include + +class PriorityMuxer +{ +public: + struct InputInfo + { + int priority; + + int64_t timeoutTime_ms; + std::vector ledColors; + }; + + PriorityMuxer(); + + ~PriorityMuxer(); + + int getCurrentPriority() const; + + bool hasPriority(const int priority) const; + + QList getPriorities() const; + + const InputInfo& getInputInfo(const int priority) const; + + void setInput(const int priority, const std::vector& ledColors, const int64_t timeoutTime_ms=-1); + + void clearInput(const int priority); + + void clearAll(); + + void setCurrentTime(const int64_t& now); + +private: + int mCurrentPriority; + + QMap mActiveInputs; + + const static int MAX_PRIORITY = std::numeric_limits::max(); +}; diff --git a/include/utils/RgbColor.h b/include/utils/RgbColor.h index 2b982aa0..50825431 100644 --- a/include/utils/RgbColor.h +++ b/include/utils/RgbColor.h @@ -5,7 +5,6 @@ #include #include - // Forward class declaration struct RgbColor; @@ -21,8 +20,12 @@ struct RgbColor static RgbColor BLUE; static RgbColor YELLOW; static RgbColor WHITE; + }; +static_assert(sizeof(RgbColor) == 3, "Incorrect size of RgbColor"); + + inline std::ostream& operator<<(std::ostream& os, const RgbColor& color) { os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}"; diff --git a/libsrc/CMakeLists.txt b/libsrc/CMakeLists.txt index 06ea26d4..ac0c6c2b 100644 --- a/libsrc/CMakeLists.txt +++ b/libsrc/CMakeLists.txt @@ -10,18 +10,22 @@ target_link_libraries(bob2hyperion hyperion hyperion-utils) +add_subdirectory(hyperion) +add_subdirectory(utils) + # Find the libPNG find_package(PNG REQUIRED QUIET) -# Add additional includes dirs -include_directories(${PNG_INCLUDE_DIR}) +if (PNG_FOUND) + # Add additional includes dirs + include_directories(${PNG_INCLUDE_DIR}) -add_library(bob2hyperion-png SHARED - hyperion-png.cpp) + add_library(bob2hyperion-png SHARED + hyperion-png.cpp) -target_link_libraries(bob2hyperion-png - hyperion-png) + target_link_libraries(bob2hyperion-png + hyperion-png) + + add_subdirectory(hyperionpng) +endif(PNG_FOUND) -add_subdirectory(hyperion) -add_subdirectory(hyperionpng) -add_subdirectory(utils) diff --git a/libsrc/bob2hyperion.cpp b/libsrc/bob2hyperion.cpp index f46fb251..f76ed71e 100644 --- a/libsrc/bob2hyperion.cpp +++ b/libsrc/bob2hyperion.cpp @@ -51,7 +51,7 @@ void boblight_destroy(void* hyperion_ptr) Hyperion* raspiLight = rasp_cast(hyperion_ptr); // Switch all leds to black (off) - raspiLight->setColor(RgbColor::BLACK); +// raspiLight->setColor(RgbColor::BLACK); delete raspiLight; @@ -64,20 +64,20 @@ void boblight_setscanrange(void* hyperion_ptr, int width, int height) syslog(LOG_INFO, "Configuring scan range [%dx%d]", width, height); Hyperion* raspiLight = rasp_cast(hyperion_ptr); - raspiLight->setInputSize(width, height); +// raspiLight->setInputSize(width, height); } void boblight_addpixelxy(void* hyperion_ptr, int x, int y, int* rgb) { Hyperion* raspiLight = rasp_cast(hyperion_ptr); const RgbColor color = {uint8_t(rgb[0]), uint8_t(rgb[1]), uint8_t(rgb[2])}; - raspiLight->image().setPixel(x, y, color); +// raspiLight->image().setPixel(x, y, color); } int boblight_sendrgb(void* hyperion_ptr, int sync, int* outputused) { Hyperion* raspiLight = rasp_cast(hyperion_ptr); - raspiLight->commit(); +// raspiLight->commit(); return 1; } diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 94ab7525..eedf202e 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -1,22 +1,52 @@ +# Find the BCM-package (VC control) +find_package(BCM REQUIRED) +include_directories(${BCM_INCLUDE_DIRS}) + # 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 +SET(Hyperion_HEADERS ${CURRENT_HEADER_DIR}/Hyperion.h ${CURRENT_HEADER_DIR}/LedDevice.h ${CURRENT_HEADER_DIR}/LedString.h - ${CURRENT_HEADER_DIR}/ImageToLedsMap.h + ${CURRENT_HEADER_DIR}/ImageProcessor.h + ${CURRENT_HEADER_DIR}/ImageProcessorFactory.h + ${CURRENT_HEADER_DIR}/PriorityMuxer.h + ${CURRENT_HEADER_DIR}/DispmanxWrapper.h + + ${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.h ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h - ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp + ${CURRENT_SOURCE_DIR}/ImageToLedsMap.h + ${CURRENT_SOURCE_DIR}/ColorTransform.h +) + +SET(Hyperion_SOURCES ${CURRENT_SOURCE_DIR}/LedString.cpp ${CURRENT_SOURCE_DIR}/Hyperion.cpp - ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp - ${CURRENT_SOURCE_DIR}/ColorTransform.h - ${CURRENT_SOURCE_DIR}/ColorTransform.cpp + ${CURRENT_SOURCE_DIR}/ImageProcessor.cpp + ${CURRENT_SOURCE_DIR}/ImageProcessorFactory.cpp + ${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp + + ${CURRENT_SOURCE_DIR}/DispmanxWrapper.cpp + ${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.cpp + + ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp + ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp + ${CURRENT_SOURCE_DIR}/ColorTransform.cpp +) + +QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_HEADERS}) + +add_library(hyperion + ${Hyperion_HEADERS} + ${Hyperion_HEADERS_MOC} + ${Hyperion_SOURCES} ) target_link_libraries(hyperion - hyperion-utils) + hyperion-utils + ${QT_LIBRARIES} + ${BCM_LIBRARIES}) diff --git a/libsrc/hyperion/ColorTransform.cpp b/libsrc/hyperion/ColorTransform.cpp index 7a02fc0d..b77b8b24 100644 --- a/libsrc/hyperion/ColorTransform.cpp +++ b/libsrc/hyperion/ColorTransform.cpp @@ -1,23 +1,26 @@ +// STL includes #include #include "ColorTransform.h" +using namespace hyperion; + ColorTransform::ColorTransform() : - _threshold(0), - _gamma(1.0), - _blacklevel(0.0), - _whitelevel(1.0) + _threshold(0), + _gamma(1.0), + _blacklevel(0.0), + _whitelevel(1.0) { - initializeMapping(); + initializeMapping(); } ColorTransform::ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel) : - _threshold(threshold), - _gamma(gamma), - _blacklevel(blacklevel), - _whitelevel(whitelevel) + _threshold(threshold), + _gamma(gamma), + _blacklevel(blacklevel), + _whitelevel(whitelevel) { - initializeMapping(); + initializeMapping(); } ColorTransform::~ColorTransform() @@ -26,77 +29,77 @@ ColorTransform::~ColorTransform() double ColorTransform::getThreshold() const { - return _threshold; + return _threshold; } void ColorTransform::setThreshold(double threshold) { - _threshold = threshold; - initializeMapping(); + _threshold = threshold; + initializeMapping(); } double ColorTransform::getGamma() const { - return _gamma; + return _gamma; } void ColorTransform::setGamma(double gamma) { - _gamma = gamma; - initializeMapping(); + _gamma = gamma; + initializeMapping(); } double ColorTransform::getBlacklevel() const { - return _blacklevel; + return _blacklevel; } void ColorTransform::setBlacklevel(double blacklevel) { - _blacklevel = blacklevel; - initializeMapping(); + _blacklevel = blacklevel; + initializeMapping(); } double ColorTransform::getWhitelevel() const { - return _whitelevel; + return _whitelevel; } void ColorTransform::setWhitelevel(double whitelevel) { - _whitelevel = whitelevel; - initializeMapping(); + _whitelevel = whitelevel; + initializeMapping(); } void ColorTransform::initializeMapping() { - // initialize the mapping as a linear array - for (int i = 0; i < 256; ++i) - { - double output = i / 255.0; + // initialize the mapping as a linear array + for (int i = 0; i < 256; ++i) + { + double output = i / 255.0; - // apply linear transform - if (output < _threshold) - { - output = 0.0; - } + // apply linear transform + if (output < _threshold) + { + output = 0.0; + } - // apply gamma correction - output = std::pow(output, _gamma); + // apply gamma correction + output = std::pow(output, _gamma); - // apply blacklevel and whitelevel - output = _blacklevel + (_whitelevel - _blacklevel) * output; + // apply blacklevel and whitelevel + output = _blacklevel + (_whitelevel - _blacklevel) * output; - // calc mapping - int mappingValue = output * 255; - if (mappingValue < 0) - { - mappingValue = 0; - } - else if (mappingValue > 255) - { - mappingValue = 255; - } - _mapping[i] = mappingValue; - } + // calc mapping + int mappingValue = output * 255; + if (mappingValue < 0) + { + mappingValue = 0; + } + else if (mappingValue > 255) + { + mappingValue = 255; + } + _mapping[i] = mappingValue; + } } diff --git a/libsrc/hyperion/ColorTransform.h b/libsrc/hyperion/ColorTransform.h index 7a67e36e..946665d4 100644 --- a/libsrc/hyperion/ColorTransform.h +++ b/libsrc/hyperion/ColorTransform.h @@ -1,6 +1,10 @@ #pragma once -#include "stdint.h" +// STL includes +#include + +namespace hyperion +{ /// Transform for a single color byte value /// @@ -14,36 +18,38 @@ class ColorTransform { public: - ColorTransform(); - ColorTransform(double threshold, double gamma, double whitelevel, double blacklevel); - ~ColorTransform(); + ColorTransform(); + ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel); + ~ColorTransform(); - double getThreshold() const; - void setThreshold(double threshold); + double getThreshold() const; + void setThreshold(double threshold); - double getGamma() const; - void setGamma(double gamma); + double getGamma() const; + void setGamma(double gamma); - double getBlacklevel() const; - void setBlacklevel(double blacklevel); + double getBlacklevel() const; + void setBlacklevel(double blacklevel); - double getWhitelevel() const; - void setWhitelevel(double whitelevel); + double getWhitelevel() const; + void setWhitelevel(double whitelevel); - /// get the transformed value for the given byte value - uint8_t transform(uint8_t input) const - { - return _mapping[input]; - } + /// get the transformed value for the given byte value + uint8_t transform(uint8_t input) const + { + return _mapping[input]; + } private: - void initializeMapping(); + void initializeMapping(); private: - double _threshold; - double _gamma; - double _blacklevel; - double _whitelevel; + double _threshold; + double _gamma; + double _blacklevel; + double _whitelevel; - uint8_t _mapping[256]; + uint8_t _mapping[256]; }; + +} // end namespace hyperion diff --git a/libsrc/hyperion/DispmanxFrameGrabber.cpp b/libsrc/hyperion/DispmanxFrameGrabber.cpp new file mode 100644 index 00000000..27d67f96 --- /dev/null +++ b/libsrc/hyperion/DispmanxFrameGrabber.cpp @@ -0,0 +1,54 @@ + +#include "DispmanxFrameGrabber.h" + +DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned height) : + _display(0), + _resource(0), + _width(width), + _height(height) +{ + // Initiase BCM + bcm_host_init(); + + // Open the connection to the displaydisplay + _display = vc_dispmanx_display_open(0); + int ret = vc_dispmanx_display_get_info(_display, &_info); + assert(ret == 0); + + // Create the resources for capturing image + _resource = vc_dispmanx_resource_create( + VC_IMAGE_RGB888, + width, + height, + &_vc_image_ptr); + assert(_resource); + + // Define the capture rectangle with the same size + vc_dispmanx_rect_set(&_rectangle, 0, 0, width, height); + _pitch = width * 3; +} + +DispmanxFrameGrabber::~DispmanxFrameGrabber() +{ + // Clean up resources + vc_dispmanx_resource_delete(_resource); + + // Close the displaye + vc_dispmanx_display_close(_display); + + // De-init BCM + bcm_host_deinit(); +} + +void DispmanxFrameGrabber::grabFrame(RgbImage& image) +{ + // Sanity check of the given image size + assert(image.width() == _width && image.height() == _height); + + void* image_ptr = image.memptr(); + + // Create the snapshot + vc_dispmanx_snapshot(_display, _resource, VC_IMAGE_ROT0); + // Read the snapshot into the memory (incl down-scaling) + vc_dispmanx_resource_read_data(_resource, &_rectangle, image_ptr, _pitch); +} diff --git a/libsrc/hyperion/DispmanxFrameGrabber.h b/libsrc/hyperion/DispmanxFrameGrabber.h new file mode 100644 index 00000000..088f6189 --- /dev/null +++ b/libsrc/hyperion/DispmanxFrameGrabber.h @@ -0,0 +1,35 @@ +#pragma once + +// BCM includes +#include + +// STL includes +#include + +// Utils includes +#include + +/// +/// The DispmanxFrameGrabber grabs +/// +class DispmanxFrameGrabber +{ +public: + DispmanxFrameGrabber(const unsigned width, const unsigned height); + ~DispmanxFrameGrabber(); + + void grabFrame(RgbImage& image); + +private: + DISPMANX_DISPLAY_HANDLE_T _display; + DISPMANX_MODEINFO_T _info; + + DISPMANX_RESOURCE_HANDLE_T _resource; + + uint32_t _vc_image_ptr; + + VC_RECT_T _rectangle; + unsigned _width; + unsigned _height; + uint32_t _pitch; +}; diff --git a/libsrc/hyperion/DispmanxWrapper.cpp b/libsrc/hyperion/DispmanxWrapper.cpp new file mode 100644 index 00000000..ed73c728 --- /dev/null +++ b/libsrc/hyperion/DispmanxWrapper.cpp @@ -0,0 +1,46 @@ +// QT includes +#include +#include + +// Hyperion includes +#include +#include + + +// Local-Hyperion includes +#include "DispmanxFrameGrabber.h" + +DispmanxWrapper::DispmanxWrapper() : + _timer(), + _processor(ImageProcessorFactory::getInstance().newImageProcessor()), + _frameGrabber(new DispmanxFrameGrabber(64, 64)) +{ + _timer.setInterval(100); + _timer.setSingleShot(false); + + QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(action())); +} + +DispmanxWrapper::~DispmanxWrapper() +{ + delete _frameGrabber; + delete _processor; +} + +void DispmanxWrapper::start() +{ + _timer.start(); +} + +void DispmanxWrapper::action() +{ + qDebug() << "[" << QDateTime::currentDateTimeUtc() << "] Grabbing frame"; + RgbImage image(64, 64); + _frameGrabber->grabFrame(image); + + //_processor-> +} +void DispmanxWrapper::stop() +{ + _timer.stop(); +} diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index dcc83e54..182e024e 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -10,6 +10,9 @@ #include #include "LedDeviceWs2801.h" +#include "ColorTransform.h" + +using namespace hyperion; LedDevice* constructDevice(const Json::Value& deviceConfig) { @@ -34,9 +37,41 @@ LedDevice* constructDevice(const Json::Value& deviceConfig) return device; } +ColorTransform* createColorTransform(const Json::Value& colorConfig) +{ + const double threshold = colorConfig["threshold"].asDouble(); + const double gamma = colorConfig["gamma"].asDouble(); + const double blacklevel = colorConfig["blacklevel"].asDouble(); + const double whitelevel = colorConfig["whitelevel"].asDouble(); + + ColorTransform* transform = new ColorTransform(threshold, gamma, blacklevel, whitelevel); + return transform; +} +LedString createLedString(const Json::Value& ledsConfig) +{ + LedString ledString; + + 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.leds().push_back(led); + } + return ledString; +} + Hyperion::Hyperion(const Json::Value &jsonConfig) : - mLedString(LedString::construct(jsonConfig["leds"], jsonConfig["color"])), - mImage(nullptr), + mLedString(createLedString(jsonConfig["leds"])), + mRedTransform( createColorTransform(jsonConfig["color"]["red"])), + mGreenTransform(createColorTransform(jsonConfig["color"]["green"])), + mBlueTransform( createColorTransform(jsonConfig["color"]["blue"])), mDevice(constructDevice(jsonConfig["device"])) { // empty @@ -45,58 +80,29 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) : Hyperion::~Hyperion() { - // Delete the existing image (or delete nullptr) - delete mImage; - // Delete the Led-String delete mDevice; + + // Delete the color-transform + delete mBlueTransform; + delete mGreenTransform; + delete mRedTransform; } -void Hyperion::setInputSize(const unsigned width, const unsigned height) +void Hyperion::setValue(int priority, std::vector& ledColors) { - // 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 - std::vector ledColors = mLedsMap.getMeanLedColor(); -// const std::vector ledColors = mLedsMap.getMedianLedColor(); - - // Write the Led colors to the led-string - mDevice->write(ledColors); -} - -void Hyperion::operator() (const RgbImage& inputImage) -{ - // Copy the input-image into the buffer - mImage->copy(inputImage); - - // Derive the color per led - std::vector ledColors = mLedsMap.getMeanLedColor(); -// std::vector 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(mLedString.leds().size(), color)); -} - -void Hyperion::applyTransform(std::vector& colors) const -{ - for (RgbColor& color : colors) + // Apply the transform to each led and color-channel + for (RgbColor& color : ledColors) { - 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; + color.red = mRedTransform->transform(color.red); + color.green = mGreenTransform->transform(color.green); + color.blue = mBlueTransform->transform(color.blue); + } + + mMuxer.setInput(priority, ledColors); + + if (priority == mMuxer.getCurrentPriority()) + { + mDevice->write(ledColors); } } diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp new file mode 100644 index 00000000..df508212 --- /dev/null +++ b/libsrc/hyperion/ImageProcessor.cpp @@ -0,0 +1,65 @@ +#include + + +#include "ImageToLedsMap.h" +#include "ColorTransform.h" + +using namespace hyperion; + +ImageProcessor::ImageProcessor(const LedString& ledString) : + mLedString(ledString), + mBuffer(nullptr), + mImageToLeds(nullptr) +{ + // empty +} + +ImageProcessor::~ImageProcessor() +{ + delete mImageToLeds; + delete mBuffer; +} + +std::vector ImageProcessor::process(const RgbImage& image) +{ + // Ensure that the buffer-image is the proper size + setSize(image.width(), image.height()); + + // Copy the data of the given image into the mapped-image + mBuffer->copy(image); + + // Create a result vector and call the 'in place' functionl + std::vector colors(mLedString.leds().size(), RgbColor::BLACK); + inplace_process(colors); + + // return the computed colors + return colors; +} + +void ImageProcessor::setSize(const unsigned width, const unsigned height) +{ + // Check if the existing buffer-image is already the correct dimensions + if (mBuffer && mBuffer->width() == width && mBuffer->height() == height) + { + return; + } + + // Clean up the old buffer and mapping + delete mImageToLeds; + delete mBuffer; + + // Construct a new buffer and mapping + mBuffer = new RgbImage(width, height); + mImageToLeds = new ImageToLedsMap(*mBuffer, mLedString.leds()); +} + +RgbImage& ImageProcessor::image() +{ + return *mBuffer; +} + +void ImageProcessor::inplace_process(std::vector& ledColors) +{ + // Determine the mean-colors of each led (using the existing mapping) + mImageToLeds->getMeanLedColor(ledColors); +} diff --git a/libsrc/hyperion/ImageProcessorFactory.cpp b/libsrc/hyperion/ImageProcessorFactory.cpp new file mode 100644 index 00000000..52837c6a --- /dev/null +++ b/libsrc/hyperion/ImageProcessorFactory.cpp @@ -0,0 +1,21 @@ + +// Hyperion includes +#include +#include + +ImageProcessorFactory& ImageProcessorFactory::getInstance() +{ + static ImageProcessorFactory instance; + // Return the singleton instance + return instance; +} + +void ImageProcessorFactory::init(const LedString& ledString) +{ + _ledString = ledString; +} + +ImageProcessor* ImageProcessorFactory::newImageProcessor() const +{ + return new ImageProcessor(_ledString); +} diff --git a/libsrc/hyperion/ImageToLedsMap.cpp b/libsrc/hyperion/ImageToLedsMap.cpp index 2acd9a17..98e25425 100644 --- a/libsrc/hyperion/ImageToLedsMap.cpp +++ b/libsrc/hyperion/ImageToLedsMap.cpp @@ -3,14 +3,11 @@ #include // hyperion includes -#include +#include "ImageToLedsMap.h" -ImageToLedsMap::ImageToLedsMap() -{ - // empty -} +using namespace hyperion; -void ImageToLedsMap::createMapping(const RgbImage& image, const std::vector& leds) +ImageToLedsMap::ImageToLedsMap(const RgbImage& image, const std::vector& leds) { mColorsMap.resize(leds.size(), std::vector()); @@ -46,6 +43,19 @@ std::vector ImageToLedsMap::getMeanLedColor() return colors; } +void ImageToLedsMap::getMeanLedColor(std::vector& ledColors) +{ + // Sanity check for the number of leds + assert(mColorsMap.size() == ledColors.size()); + + auto led = ledColors.begin(); + for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors, ++led) + { + const RgbColor color = findMeanColor(*ledColors); + *led = color; + } +} + RgbColor ImageToLedsMap::findMeanColor(const std::vector& colors) { uint_fast16_t cummRed = 0; @@ -64,27 +74,3 @@ RgbColor ImageToLedsMap::findMeanColor(const std::vector& color return {avgRed, avgGreen, avgBlue}; } - -std::vector ImageToLedsMap::getMedianLedColor() -{ - std::vector ledColors; - for (std::vector& colors : mColorsMap) - { - const RgbColor color = findMedianColor(colors); - ledColors.push_back(color); - } - - return ledColors; -} - -RgbColor ImageToLedsMap::findMedianColor(std::vector& 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}; -} diff --git a/libsrc/hyperion/ImageToLedsMap.h b/libsrc/hyperion/ImageToLedsMap.h new file mode 100644 index 00000000..5e4a4e9c --- /dev/null +++ b/libsrc/hyperion/ImageToLedsMap.h @@ -0,0 +1,57 @@ + +#pragma once + +// hyperion-utils includes +#include + +// hyperion includes +#include + +namespace hyperion +{ + +class ImageToLedsMap +{ +public: + + /** + * Constructs an mapping from the colors in the image to each led based on the border + * definition given in the list of leds. The map holds pointers to the given image and its + * lifetime should never exceed that of the given image + * + * @param[in] image The RGB image + * @param[in] leds The list with led specifications + */ + ImageToLedsMap(const RgbImage& image, const std::vector& leds); + + /** + * Determines the mean-color for each led using the mapping the image given + * at construction. + * + * @return ledColors The vector containing the output + */ + std::vector getMeanLedColor(); + + /** + * Determines the mean-color for each led using the mapping the image given + * at construction. + * + * @param[out] ledColors The vector containing the output + */ + void getMeanLedColor(std::vector& ledColors); + +private: + std::vector > mColorsMap; + + /** + * Finds the 'mean color' of the given list. This is the mean over each color-channel (red, + * green, blue) + * + * @param colors The list with colors + * + * @return The mean of the given list of colors (or black when empty) + */ + RgbColor findMeanColor(const std::vector& colors); +}; + +} // end namespace hyperion diff --git a/libsrc/hyperion/LedString.cpp b/libsrc/hyperion/LedString.cpp index fadb260e..38c1b8f9 100644 --- a/libsrc/hyperion/LedString.cpp +++ b/libsrc/hyperion/LedString.cpp @@ -9,41 +9,6 @@ // hyperion includes #include -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() { @@ -54,6 +19,11 @@ LedString::~LedString() { } +std::vector& LedString::leds() +{ + return mLeds; +} + const std::vector& LedString::leds() const { return mLeds; diff --git a/libsrc/hyperion/PriorityMuxer.cpp b/libsrc/hyperion/PriorityMuxer.cpp new file mode 100644 index 00000000..2321cccd --- /dev/null +++ b/libsrc/hyperion/PriorityMuxer.cpp @@ -0,0 +1,94 @@ + +// STL includes +#include +#include + +// Hyperion includes +#include + +PriorityMuxer::PriorityMuxer() : + mCurrentPriority(MAX_PRIORITY) +{ + // empty +} + +PriorityMuxer::~PriorityMuxer() +{ + // empty +} + +int PriorityMuxer::getCurrentPriority() const +{ + return mCurrentPriority; +} + +QList PriorityMuxer::getPriorities() const +{ + return mActiveInputs.keys(); +} + +bool PriorityMuxer::hasPriority(const int priority) const +{ + return mActiveInputs.contains(priority); +} + +const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) const +{ + auto elemIt = mActiveInputs.find(priority); + if (elemIt == mActiveInputs.end()) + { + throw std::runtime_error("no such priority"); + } + return elemIt.value(); +} + +void PriorityMuxer::setInput(const int priority, const std::vector& ledColors, const int64_t timeoutTime_ms) +{ + InputInfo& input = mActiveInputs[priority]; + input.priority = priority; + input.timeoutTime_ms = timeoutTime_ms; + input.ledColors = ledColors; + + mCurrentPriority = std::min(mCurrentPriority, priority); +} + +void PriorityMuxer::clearInput(const int priority) +{ + mActiveInputs.remove(priority); + if (mCurrentPriority == priority) + { + if (mActiveInputs.empty()) + { + mCurrentPriority = MAX_PRIORITY; + } + else + { + QList keys = mActiveInputs.keys(); + mCurrentPriority = *std::min_element(keys.begin(), keys.end()); + } + } +} + +void PriorityMuxer::clearAll() +{ + mActiveInputs.clear(); + mCurrentPriority = MAX_PRIORITY; +} + +void PriorityMuxer::setCurrentTime(const int64_t& now) +{ + mCurrentPriority = MAX_PRIORITY; + + for (auto infoIt = mActiveInputs.begin(); infoIt != mActiveInputs.end();) + { + if (infoIt->timeoutTime_ms != -1 && infoIt->timeoutTime_ms <= now) + { + infoIt = mActiveInputs.erase(infoIt); + } + else + { + mCurrentPriority = std::min(mCurrentPriority, infoIt->priority); + ++infoIt; + } + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dbf76456..a6083718 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,12 @@ add_executable(WriteConfig WriteConfig.cpp) +add_executable(HyperionDispmanx + HyperionMain.cpp) + +target_link_libraries(HyperionDispmanx + hyperion) + add_executable(boblight-dispmanx boblight-dispmanx.cpp flagmanager.h @@ -27,12 +33,12 @@ target_link_libraries(boblight-dispmanx bob2hyperion ${BCM_LIBRARIES}) -add_executable(HyperionDispmanX - HyperionDispmanX.cpp) +#add_executable(HyperionDispmanX +# HyperionDispmanX.cpp) -target_link_libraries(HyperionDispmanX - hyperion - ${BCM_LIBRARIES}) +#target_link_libraries(HyperionDispmanX +# hyperion +# ${BCM_LIBRARIES}) # Find the libPNG diff --git a/src/HyperionDispmanX.cpp b/src/HyperionDispmanX.cpp index 69b5c942..8af333eb 100644 --- a/src/HyperionDispmanX.cpp +++ b/src/HyperionDispmanX.cpp @@ -43,7 +43,7 @@ int main(int /*argc*/, char** /*argv*/) } Hyperion hyperion(raspiConfig); - dispmanx_process(hyperion, sRunning); +// dispmanx_process(hyperion, sRunning); return 0; } diff --git a/src/HyperionMain.cpp b/src/HyperionMain.cpp new file mode 100644 index 00000000..988db273 --- /dev/null +++ b/src/HyperionMain.cpp @@ -0,0 +1,17 @@ + +// QT includes +#include + +// Hyperion includes +#include + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + + DispmanxWrapper dispmanx; + dispmanx.start(); + + app.exec(); +} diff --git a/src/ViewPng.cpp b/src/ViewPng.cpp index 917a4976..04e0ccd1 100644 --- a/src/ViewPng.cpp +++ b/src/ViewPng.cpp @@ -144,10 +144,10 @@ int main(int argc, char** argv) FbWriter fbWriter; Hyperion raspiLight(raspiConfig); - raspiLight.setInputSize(image->width(), image->height()); +// raspiLight.setInputSize(image->width(), image->height()); fbWriter.writeImage(*image); - raspiLight(*image); +// raspiLight(*image); sleep(5); diff --git a/src/flagmanager.cpp b/src/flagmanager.cpp index de5623e8..cf3a608b 100644 --- a/src/flagmanager.cpp +++ b/src/flagmanager.cpp @@ -1,17 +1,17 @@ /* * boblight - * Copyright (C) Bob 2009 - * + * Copyright (C) Bob 2009 + * * boblight is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * boblight is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ @@ -35,16 +35,16 @@ CArguments::CArguments(int argc, char** argv) if (m_argc == 0) { - m_argv = NULL; + m_argv = NULL; } else { - m_argv = new char*[m_argc]; - for (int i = 0; i < m_argc; i++) - { - m_argv[i] = new char[strlen(argv[i]) + 1]; - strcpy(m_argv[i], argv[i]); - } + m_argv = new char*[m_argc]; + for (int i = 0; i < m_argc; i++) + { + m_argv[i] = new char[strlen(argv[i]) + 1]; + strcpy(m_argv[i], argv[i]); + } } } @@ -53,11 +53,11 @@ CArguments::~CArguments() { if (m_argv) { - for (int i = 0; i < m_argc; i++) - { - delete[] m_argv[i]; - } - delete[] m_argv; + for (int i = 0; i < m_argc; i++) + { + delete[] m_argv[i]; + } + delete[] m_argv; } } @@ -87,75 +87,75 @@ void CFlagManager::ParseFlags(int tempargc, char** tempargv) int c; opterr = 0; //we don't want to print error messages - + while ((c = getopt(argc, argv, m_flags.c_str())) != -1) { - if (c == 'p') //priority - { - option = optarg; - if (!StrToInt(option, m_priority) || m_priority < 0 || m_priority > 255) - { - throw string("Wrong option " + string(optarg) + " for argument -p"); - } - } - else if (c == 's') //address[:port] - { - option = optarg; - //store address in string and set the char* to it - m_straddress = option.substr(0, option.find(':')); - m_address = m_straddress.c_str(); + if (c == 'p') //priority + { + option = optarg; + if (!StrToInt(option, m_priority) || m_priority < 0 || m_priority > 255) + { + throw string("Wrong option " + string(optarg) + " for argument -p"); + } + } + else if (c == 's') //address[:port] + { + option = optarg; + //store address in string and set the char* to it + m_straddress = option.substr(0, option.find(':')); + m_address = m_straddress.c_str(); - if (option.find(':') != string::npos) //check if we have a port - { - option = option.substr(option.find(':') + 1); - string word; - if (!StrToInt(option, m_port) || m_port < 0 || m_port > 65535) - { - throw string("Wrong option " + string(optarg) + " for argument -s"); - } - } - } - else if (c == 'o') //option for libboblight - { - m_options.push_back(optarg); - } - else if (c == 'l') //list libboblight options - { - m_printboblightoptions = true; - return; - } - else if (c == 'h') //print help message - { - m_printhelp = true; - return; - } - else if (c == 'f') - { - m_fork = true; - } - else if (c == 'y') - { - if (!StrToBool(optarg, m_sync)) - { - throw string("Wrong value " + string(optarg) + " for sync mode"); - } - } - else if (c == '?') //unknown option - { - //check if we know this option, but expected an argument - if (m_flags.find(ToString((char)optopt) + ":") != string::npos) - { - throw string("Option " + ToString((char)optopt) + "requires an argument"); - } - else - { - throw string("Unkown option " + ToString((char)optopt)); - } - } - else - { - ParseFlagsExtended(argc, argv, c, optarg); //pass our argument to a derived class - } + if (option.find(':') != string::npos) //check if we have a port + { + option = option.substr(option.find(':') + 1); + string word; + if (!StrToInt(option, m_port) || m_port < 0 || m_port > 65535) + { + throw string("Wrong option " + string(optarg) + " for argument -s"); + } + } + } + else if (c == 'o') //option for libboblight + { + m_options.push_back(optarg); + } + else if (c == 'l') //list libboblight options + { + m_printboblightoptions = true; + return; + } + else if (c == 'h') //print help message + { + m_printhelp = true; + return; + } + else if (c == 'f') + { + m_fork = true; + } + else if (c == 'y') + { + if (!StrToBool(optarg, m_sync)) + { + throw string("Wrong value " + string(optarg) + " for sync mode"); + } + } + else if (c == '?') //unknown option + { + //check if we know this option, but expected an argument + if (m_flags.find(ToString((char)optopt) + ":") != string::npos) + { + throw string("Option " + ToString((char)optopt) + "requires an argument"); + } + else + { + throw string("Unkown option " + ToString((char)optopt)); + } + } + else + { + ParseFlagsExtended(argc, argv, c, optarg); //pass our argument to a derived class + } } PostGetopt(optind, argc, argv); //some postprocessing @@ -169,7 +169,7 @@ void CFlagManager::PrintBoblightOptions() for (int i = 0; i < nroptions; i++) { - cout << boblight_getoptiondescript(boblight, i) << "\n"; + cout << boblight_getoptiondescript(boblight, i) << "\n"; } boblight_destroy(boblight); @@ -178,74 +178,74 @@ void CFlagManager::PrintBoblightOptions() void CFlagManager::ParseBoblightOptions(void* boblight) { int nrlights = boblight_getnrlights(boblight); - - for (int i = 0; i < m_options.size(); i++) + + for (size_t i = 0; i < m_options.size(); i++) { - string option = m_options[i]; - string lightname; - string optionname; - string optionvalue; - int lightnr = -1; + string option = m_options[i]; + string lightname; + string optionname; + string optionvalue; + int lightnr = -1; - //check if we have a lightname, otherwise we use all lights - if (option.find(':') != string::npos) - { - lightname = option.substr(0, option.find(':')); - if (option.find(':') == option.size() - 1) //check if : isn't the last char in the string - { - throw string("wrong option \"" + option + "\", syntax is [light:]option=value"); - } - option = option.substr(option.find(':') + 1); //shave off the lightname + //check if we have a lightname, otherwise we use all lights + if (option.find(':') != string::npos) + { + lightname = option.substr(0, option.find(':')); + if (option.find(':') == option.size() - 1) //check if : isn't the last char in the string + { + throw string("wrong option \"" + option + "\", syntax is [light:]option=value"); + } + option = option.substr(option.find(':') + 1); //shave off the lightname - //check which light this is - bool lightfound = false; - for (int j = 0; j < nrlights; j++) - { - if (lightname == boblight_getlightname(boblight, j)) - { - lightfound = true; - lightnr = j; - break; - } - } - if (!lightfound) - { - throw string("light \"" + lightname + "\" used in option \"" + m_options[i] + "\" doesn't exist"); - } - } + //check which light this is + bool lightfound = false; + for (int j = 0; j < nrlights; j++) + { + if (lightname == boblight_getlightname(boblight, j)) + { + lightfound = true; + lightnr = j; + break; + } + } + if (!lightfound) + { + throw string("light \"" + lightname + "\" used in option \"" + m_options[i] + "\" doesn't exist"); + } + } - //check if '=' exists and it's not at the end of the string - if (option.find('=') == string::npos || option.find('=') == option.size() - 1) - { - throw string("wrong option \"" + option + "\", syntax is [light:]option=value"); - } + //check if '=' exists and it's not at the end of the string + if (option.find('=') == string::npos || option.find('=') == option.size() - 1) + { + throw string("wrong option \"" + option + "\", syntax is [light:]option=value"); + } - optionname = option.substr(0, option.find('=')); //option name is everything before = (already shaved off the lightname here) - optionvalue = option.substr(option.find('=') + 1); //value is everything after = + optionname = option.substr(0, option.find('=')); //option name is everything before = (already shaved off the lightname here) + optionvalue = option.substr(option.find('=') + 1); //value is everything after = - option = optionname + " " + optionvalue; //libboblight wants syntax without = + option = optionname + " " + optionvalue; //libboblight wants syntax without = - //bitch if we can't set this option - if (!boblight_setoption(boblight, lightnr, option.c_str())) - { - throw string(boblight_geterror(boblight)); - } + //bitch if we can't set this option + if (!boblight_setoption(boblight, lightnr, option.c_str())) + { + throw string(boblight_geterror(boblight)); + } } } bool CFlagManager::SetVideoGamma() { - for (int i = 0; i < m_options.size(); i++) + for (size_t i = 0; i < m_options.size(); i++) { - string option = m_options[i]; - if (option.find(':') != string::npos) - option = option.substr(option.find(':') + 1); //shave off the lightname + string option = m_options[i]; + if (option.find(':') != string::npos) + option = option.substr(option.find(':') + 1); //shave off the lightname - if (option.find('=') != string::npos) - { - if (option.substr(0, option.find('=')) == "gamma") - return false; //gamma set by user, don't override - } + if (option.find('=') != string::npos) + { + if (option.substr(0, option.find('=')) == "gamma") + return false; //gamma set by user, don't override + } } m_options.push_back("gamma=" + ToString(VIDEOGAMMA)); diff --git a/src/misc.h b/src/misc.h index f6ef4f3c..76593a46 100644 --- a/src/misc.h +++ b/src/misc.h @@ -1,17 +1,17 @@ /* * boblight - * Copyright (C) Bob 2009 - * + * Copyright (C) Bob 2009 + * * boblight is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * boblight is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ @@ -96,15 +96,15 @@ inline A Round(B value) { if (value == 0.0) { - return 0; + return 0; } else if (value > 0.0) { - return (A)(value + 0.5); + return (A)(value + 0.5); } else { - return (A)(value - 0.5); + return (A)(value - 0.5); } } @@ -135,7 +135,7 @@ inline bool StrToInt(const std::string& data, int& value) inline bool StrToInt(const std::string& data, int64_t& value) { - return sscanf(data.c_str(), "%ld", &value) == 1; + return sscanf(data.c_str(), "%lld", &value) == 1; } inline bool HexStrToInt(const std::string& data, int& value) @@ -145,7 +145,7 @@ inline bool HexStrToInt(const std::string& data, int& value) inline bool HexStrToInt(const std::string& data, int64_t& value) { - return sscanf(data.c_str(), "%x", &value) == 1; + return sscanf(data.c_str(), "%llx", &value) == 1; } inline bool StrToFloat(const std::string& data, float& value) @@ -163,26 +163,26 @@ inline bool StrToBool(const std::string& data, bool& value) std::string data2 = data; std::string word; if (!GetWord(data2, word)) - return false; - + return false; + if (word == "1" || word == "true" || word == "on" || word == "yes") { - value = true; - return true; + value = true; + return true; } else if (word == "0" || word == "false" || word == "off" || word == "no") { - value = false; - return true; + value = false; + return true; } else { - int ivalue; - if (StrToInt(word, ivalue)) - { - value = ivalue != 0; - return true; - } + int ivalue; + if (StrToInt(word, ivalue)) + { + value = ivalue != 0; + return true; + } } return false; diff --git a/test/TestColorTransform.cpp b/test/TestColorTransform.cpp index 376ac6bd..ebaaf475 100644 --- a/test/TestColorTransform.cpp +++ b/test/TestColorTransform.cpp @@ -1,93 +1,96 @@ +// STL includes #include #include -#include +#include <../../libsrc/hyperion/ColorTransform.h> + +using namespace hyperion; int main() { - { - std::cout << "Testing linear transform" << std::endl; - ColorTransform t; - for (int i = 0; i < 256; ++i) - { - uint8_t input = i; - uint8_t output = t.transform(input); - uint8_t expected = input; + { + std::cout << "Testing linear transform" << std::endl; + ColorTransform t; + for (int i = 0; i < 256; ++i) + { + uint8_t input = i; + uint8_t output = t.transform(input); + uint8_t expected = input; - if (output != expected) - { - std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; - return 1; - } - else - { - std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; - } - } - } + if (output != expected) + { + std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; + return 1; + } + else + { + std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; + } + } + } - { - std::cout << "Testing threshold" << std::endl; - ColorTransform t(.10, 1.0, 0.0, 1.0); - for (int i = 0; i < 256; ++i) - { - uint8_t input = i; - uint8_t output = t.transform(input); - uint8_t expected = ((i/255.0) < t.getThreshold() ? 0 : output); + { + std::cout << "Testing threshold" << std::endl; + ColorTransform t(.10, 1.0, 0.0, 1.0); + for (int i = 0; i < 256; ++i) + { + uint8_t input = i; + uint8_t output = t.transform(input); + uint8_t expected = ((i/255.0) < t.getThreshold() ? 0 : output); - if (output != expected) - { - std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; - return 1; - } - else - { - std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; - } - } - } + if (output != expected) + { + std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; + return 1; + } + else + { + std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; + } + } + } - { - std::cout << "Testing blacklevel and whitelevel" << std::endl; - ColorTransform t(0, 1.0, 0.2, 0.8); - for (int i = 0; i < 256; ++i) - { - uint8_t input = i; - uint8_t output = t.transform(input); - uint8_t expected = (uint8_t)(input * (t.getWhitelevel()-t.getBlacklevel()) + 255 * t.getBlacklevel()); + { + std::cout << "Testing blacklevel and whitelevel" << std::endl; + ColorTransform t(0, 1.0, 0.2, 0.8); + for (int i = 0; i < 256; ++i) + { + uint8_t input = i; + uint8_t output = t.transform(input); + uint8_t expected = (uint8_t)(input * (t.getWhitelevel()-t.getBlacklevel()) + 255 * t.getBlacklevel()); - if (output != expected) - { - std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; - return 1; - } - else - { - std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; - } - } - } + if (output != expected) + { + std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; + return 1; + } + else + { + std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; + } + } + } - { - std::cout << "Testing gamma" << std::endl; - ColorTransform t(0, 2.0, 0.0, 1.0); - for (int i = 0; i < 256; ++i) - { - uint8_t input = i; - uint8_t output = t.transform(input); - uint8_t expected = (uint8_t)(255 * std::pow(i / 255.0, 2)); + { + std::cout << "Testing gamma" << std::endl; + ColorTransform t(0, 2.0, 0.0, 1.0); + for (int i = 0; i < 256; ++i) + { + uint8_t input = i; + uint8_t output = t.transform(input); + uint8_t expected = (uint8_t)(255 * std::pow(i / 255.0, 2)); - if (output != expected) - { - std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; - return 1; - } - else - { - std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; - } - } - } + if (output != expected) + { + std::cerr << "ERROR: input (" << (int)input << ") => output (" << (int)output << ") : expected (" << (int) expected << ")" << std::endl; + return 1; + } + else + { + std::cerr << "OK: input (" << (int)input << ") => output (" << (int)output << ")" << std::endl; + } + } + } - return 0; + return 0; } diff --git a/test/TestConfigFile.cpp b/test/TestConfigFile.cpp index cb330de3..41e9d5cf 100644 --- a/test/TestConfigFile.cpp +++ b/test/TestConfigFile.cpp @@ -32,7 +32,7 @@ int main() 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); +// LedString ledString = LedString::construct(ledConfig, colorConfig); return 0; }