diff --git a/CMakeLists.txt b/CMakeLists.txt index d8f15681..72f48018 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,8 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall") 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) +configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY) +configure_file(config/hyperion.schema.json ${LIBRARY_OUTPUT_PATH} @ONLY) # Add the source/lib directories add_subdirectory(dependencies) diff --git a/config/Hyperion.config.json b/config/hyperion.config.json similarity index 100% rename from config/Hyperion.config.json rename to config/hyperion.config.json diff --git a/config/Hyperion.schema.json b/config/hyperion.schema.json similarity index 100% rename from config/Hyperion.schema.json rename to config/hyperion.schema.json diff --git a/libsrc/bob2hyperion.cpp b/libsrc/bob2hyperion.cpp index a772b95a..f46fb251 100644 --- a/libsrc/bob2hyperion.cpp +++ b/libsrc/bob2hyperion.cpp @@ -20,7 +20,8 @@ inline Hyperion* rasp_cast(void* hyperion_ptr) void* boblight_init() { - syslog(LOG_INFO, __PRETTY_FUNCTION__); + std::cout << __PRETTY_FUNCTION__ << std::endl; +// syslog(LOG_INFO, __PRETTY_FUNCTION__); const char* homeDir = getenv("RASPILIGHT_HOME"); if (!homeDir) @@ -83,6 +84,7 @@ int boblight_sendrgb(void* hyperion_ptr, int sync, int* outputused) int boblight_connect(void* hyperion_ptr, const char* address, int port, int usectimeout) { + std::cout << "SUCCESFULL NO CONNECTION WITH BOBLIGHT" << std::endl; return 1; } @@ -93,6 +95,7 @@ const char* boblight_geterror(void* hyperion_ptr) int boblight_setpriority(void* hyperion_ptr, int priority) { + std::cout << __PRETTY_FUNCTION__ << std::endl; return 1; } diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index e8fd7e6a..dcc83e54 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -65,20 +65,21 @@ void Hyperion::setInputSize(const unsigned width, const unsigned height) void Hyperion::commit() { // Derive the color per led - const std::vector ledColors = mLedsMap.getMedianLedColor(); + 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) { - 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 ledColors = mLedsMap.getMeanLedColor(); - std::vector ledColors = mLedsMap.getMedianLedColor(); + std::vector ledColors = mLedsMap.getMeanLedColor(); +// std::vector ledColors = mLedsMap.getMedianLedColor(); applyTransform(ledColors); // Write the Led colors to the led-string diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ae953450..18ea1512 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,3 +42,37 @@ add_executable(Test2BobLight target_link_libraries(Test2BobLight bob2hyperion) + +add_executable(boblight-dispmanx + boblight-dispmanx.cpp + flagmanager.h + flagmanager.cpp + flagmanager-dispmanx.h + flagmanager-dispmanx.cpp + grabber-dispmanx.h + grabber-dispmanx.cpp + misc.h + misc.cpp + timer.h + timer.cpp + timeutils.h + timeutils.cpp) + +SET(VC_INCLUDE_DIRS + /opt/vc/include + /opt/vc/include/interface/vcos/pthreads + /opt/vc/include/interface/vmcs_host/linux) +SET(VC_LIBS + /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libbcm_host.so) +# /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libGLESv2.so +# /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libEGL.so +# /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libopenmaxil.so +# /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libvcos.so +# /home/pi/.xbmc-current/xbmc-bin/lib/xbmc/system/libvchiq_arm.so) + +include_directories(${VC_INCLUDE_DIRS}) + +target_link_libraries(boblight-dispmanx +# hyperion-png + bob2hyperion + ${VC_LIBS}) diff --git a/src/WriteConfig.cpp b/src/WriteConfig.cpp index 3278821b..6b362b2e 100644 --- a/src/WriteConfig.cpp +++ b/src/WriteConfig.cpp @@ -18,15 +18,29 @@ ofstream& indent(ofstream& ofs, unsigned indent) struct LedFrame { - unsigned topLedCnt = 17; - unsigned rightLedCnt = 8; - unsigned bottomLedCnt = 17; - unsigned leftLedCnt = 8; + unsigned topLedCnt; + unsigned rightLedCnt; + unsigned bottomLedCnt; + unsigned leftLedCnt; - unsigned topLeftOffset = 17; + unsigned topLeftOffset; - unsigned borderWidth = 10; - unsigned borderHeight = 10; + unsigned borderWidth; + unsigned borderHeight; + + LedFrame() : + topLedCnt(17), + rightLedCnt(8), + bottomLedCnt(17), + leftLedCnt(8), + + topLeftOffset(17), + + borderWidth(10), + borderHeight(10) + { + // empty + } unsigned totalLedCnt() const { diff --git a/src/boblight-dispmanx.cpp b/src/boblight-dispmanx.cpp new file mode 100644 index 00000000..720d4fdf --- /dev/null +++ b/src/boblight-dispmanx.cpp @@ -0,0 +1,179 @@ +/* + * boblight + * 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 . + */ + +//#define BOBLIGHT_DLOPEN +#include "boblight.h" + +#include +#include +#include +#include +#include + +//#include "config.h" +#include "misc.h" +#include "flagmanager-dispmanx.h" +#include "grabber-dispmanx.h" + +//OpenMax includes +#include "bcm_host.h" +#include + +using namespace std; + +#define TEST_SAVE_IMAGE 0 +#define PRINT_RET_VAL(ret, func, ...) ret = func(__VA_ARGS__); printf(#func " returned %d\n", ret); + +int Run(); +void SignalHandler(int signum); + +volatile bool stop = false; + +CFlagManagerDispmanX g_flagmanager; + +int main(int argc, char *argv[]) +{ + std::cout << "HACKED VERSION WITH TIMOLIGHT" << std::endl; + //load the boblight lib, if it fails we get a char* from dlerror() +// char* boblight_error = boblight_loadlibrary(NULL); +// if (boblight_error) +// { +// PrintError(boblight_error); +// return 1; +// } + + //try to parse the flags and bitch to stderr if there's an error + try + { + g_flagmanager.ParseFlags(argc, argv); + } + catch (string error) + { + PrintError(error); + g_flagmanager.PrintHelpMessage(); + return 1; + } + + if (g_flagmanager.m_printhelp) //print help message + { + g_flagmanager.PrintHelpMessage(); + return 1; + } + + if (g_flagmanager.m_printboblightoptions) //print boblight options (-o [light:]option=value) + { + g_flagmanager.PrintBoblightOptions(); + return 1; + } + + if (g_flagmanager.m_fork) + { + if (fork()) + return 0; + } + + //set up signal handlers + signal(SIGTERM, SignalHandler); + signal(SIGINT, SignalHandler); + + //keep running until we want to quit + return Run(); +} + +int Run() +{ + while(!stop) + { + //init boblight + void* boblight = boblight_init(); + + cout << "Connecting to boblightd\n"; + + //try to connect, if we can't then bitch to stderr and destroy boblight + if (!boblight_connect(boblight, g_flagmanager.m_address, g_flagmanager.m_port, 5000000) || + !boblight_setpriority(boblight, g_flagmanager.m_priority)) + { + PrintError(boblight_geterror(boblight)); + cout << "Waiting 10 seconds before trying again\n"; + boblight_destroy(boblight); + sleep(10); + continue; + } + + cout << "Connection to boblightd opened\n"; + + //try to parse the boblight flags and bitch to stderr if we can't + try + { + g_flagmanager.ParseBoblightOptions(boblight); + } + catch (string error) + { + PrintError(error); + return 1; + } + + CGrabberDispmanX *grabber = new CGrabberDispmanX(boblight, stop, g_flagmanager.m_sync); + + grabber->SetInterval(g_flagmanager.m_interval); + grabber->SetSize(g_flagmanager.m_pixels); + + if (!grabber->Setup()) //just exit if we can't set up the grabber + { + PrintError(grabber->GetError()); + delete grabber; + boblight_destroy(boblight); + return 1; + } + + if (!grabber->Run()) //just exit if some unrecoverable error happens + { + PrintError(grabber->GetError()); + delete grabber; + boblight_destroy(boblight); + return 1; + } + else //boblightd probably timed out, so just try to reconnect + { + if (!grabber->GetError().empty()) + PrintError(grabber->GetError()); + } + + delete grabber; + + boblight_destroy(boblight); + } + + cout << "Exiting\n"; + + return 0; +} + +void SignalHandler(int signum) +{ + if (signum == SIGTERM) + { + cout << "caught SIGTERM\n"; + stop = true; + } + else if (signum == SIGINT) + { + cout << "caught SIGINT\n"; + stop = true; + } +} diff --git a/src/flagmanager-dispmanx.cpp b/src/flagmanager-dispmanx.cpp new file mode 100644 index 00000000..83bcaf66 --- /dev/null +++ b/src/flagmanager-dispmanx.cpp @@ -0,0 +1,106 @@ +/* + * boblight + * 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 . + */ + +#include + +#include "flagmanager-dispmanx.h" +//#include "config.h" +#include "misc.h" + +using namespace std; + +CFlagManagerDispmanX::CFlagManagerDispmanX() +{ + //extend the base getopt flags + //i = interval, u = pixels, x = xgetimage, d = debug + m_flags += "i:u:d::"; + + m_interval = 0.1; //default interval is 100 milliseconds + m_pixels = 64; //-1 says to the capture classes to use default + m_debug = false; //no debugging by default + m_debugdpy = NULL; //default debug dpy is system default + m_sync = true; //sync mode enabled by default +} + +void CFlagManagerDispmanX::ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg) //we load our own flags here +{ + if (c == 'i') //interval + { + bool vblank = false; + + if (optarg[0] == 'v') //starting interval with v means vblank interval + { + #ifdef HAVE_LIBGL + optarg++; + vblank = true; + #else + throw string("Compiled without opengl support"); + #endif + } + + if (!StrToFloat(optarg, m_interval) || m_interval <= 0.0) + { + throw string("Wrong value " + string(optarg) + " for interval"); + } + + if (vblank) + { + if (m_interval < 1.0) + { + throw string("Wrong value " + string(optarg) + " for vblank interval"); + } + m_interval *= -1.0; //negative interval means vblank + optarg--; + } + } + else if (c == 'u') //nr of pixels to use + { + if (!StrToInt(optarg, m_pixels) || m_pixels <= 0) + { + throw string("Wrong value " + string(optarg) + " for pixels"); + } + } + else if (c == 'd') //turn on debug mode + { + m_debug = true; + if (optarg) //optional debug dpy + { + m_strdebugdpy = optarg; + m_debugdpy = m_strdebugdpy.c_str(); + } + } +} + +void CFlagManagerDispmanX::PrintHelpMessage() +{ + cout << "Usage: boblight-dispmanx [OPTION]\n"; + cout << "\n"; + cout << " options:\n"; + cout << "\n"; + cout << " -p priority, from 0 to 255, default is 128\n"; + cout << " -s address:[port], set the address and optional port to connect to\n"; + cout << " -o add libboblight option, syntax: [light:]option=value\n"; + cout << " -l list libboblight options\n"; + cout << " -i set the interval in seconds, default is 0.1\n"; + cout << " -u set the number of pixels/rows to use\n"; + cout << " default is 64 for xrender and 16 for xgetimage\n"; + cout << " -d debug mode\n"; + cout << " -f fork\n"; + cout << " -y set the sync mode, default is on, valid options are \"on\" and \"off\"\n"; + cout << "\n"; +} diff --git a/src/flagmanager-dispmanx.h b/src/flagmanager-dispmanx.h new file mode 100644 index 00000000..f91381f1 --- /dev/null +++ b/src/flagmanager-dispmanx.h @@ -0,0 +1,44 @@ +/* + * boblight + * 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 . + */ + +#ifndef FLAGMANAGERDISPMANX +#define FLAGMANAGERDISPMANX + +#include "flagmanager.h" + +class CFlagManagerDispmanX : public CFlagManager +{ +public: + CFlagManagerDispmanX(); + + int m_color; + + void ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg); //we load our own flags here + void PrintHelpMessage(); + + double m_interval; //grab interval in seconds, or vertical blanks when negative + int m_pixels; //number of pixels on lines to capture + bool m_debug; //if true we make a little window where we put our captured output on, looks pretty + const char* m_debugdpy; //display to place the debug window on, default is NULL + +private: + + std::string m_strdebugdpy; //place to store the debug dpy, cause our copied argv is destroyed +}; + +#endif //FLAGMANAGEROPENMAX diff --git a/src/flagmanager.cpp b/src/flagmanager.cpp new file mode 100644 index 00000000..de5623e8 --- /dev/null +++ b/src/flagmanager.cpp @@ -0,0 +1,257 @@ +/* + * boblight + * 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 . + */ + +#include +#include +#include + +#include "flagmanager.h" +#include "misc.h" + +//#define BOBLIGHT_DLOPEN_EXTERN +#include "boblight.h" + +using namespace std; + +//very simple, store a copy of argc and argv +CArguments::CArguments(int argc, char** argv) +{ + m_argc = argc; + + if (m_argc == 0) + { + 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]); + } + } +} + +//delete the copy of argv +CArguments::~CArguments() +{ + if (m_argv) + { + for (int i = 0; i < m_argc; i++) + { + delete[] m_argv[i]; + } + delete[] m_argv; + } +} + +CFlagManager::CFlagManager() +{ + m_port = -1; //-1 tells libboblight to use default port + m_address = NULL; //NULL tells libboblight to use default address + m_priority = 128; //default priority + m_printhelp = false; //don't print helpmessage unless asked to + m_printboblightoptions = false; //same for libboblight options + m_fork = false; //don't fork by default + m_sync = false; //sync mode disabled by default + + // default getopt flags, can be extended in derived classes + // p = priority, s = address[:port], o = boblight option, l = list boblight options, h = print help message, f = fork + m_flags = "p:s:o:lhfy:"; +} + +void CFlagManager::ParseFlags(int tempargc, char** tempargv) +{ + //that copy class sure comes in handy now! + CArguments arguments(tempargc, tempargv); + int argc = arguments.m_argc; + char** argv = arguments.m_argv; + + string option; + 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 (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 +} + +//go through all options and print the descriptions to stdout +void CFlagManager::PrintBoblightOptions() +{ + void* boblight = boblight_init(); + int nroptions = boblight_getnroptions(boblight); + + for (int i = 0; i < nroptions; i++) + { + cout << boblight_getoptiondescript(boblight, i) << "\n"; + } + + boblight_destroy(boblight); +} + +void CFlagManager::ParseBoblightOptions(void* boblight) +{ + int nrlights = boblight_getnrlights(boblight); + + for (int i = 0; i < m_options.size(); i++) + { + 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 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"); + } + + 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 = + + //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++) + { + 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 + } + } + + m_options.push_back("gamma=" + ToString(VIDEOGAMMA)); + + cout << "Gamma not set, using " << VIDEOGAMMA << " since this is default for video\n"; + + return true; +} + diff --git a/src/flagmanager.h b/src/flagmanager.h new file mode 100644 index 00000000..8a3b327d --- /dev/null +++ b/src/flagmanager.h @@ -0,0 +1,72 @@ +/* + * boblight + * 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 . + */ + +#ifndef FLAGMANAGER +#define FLAGMANAGER + +#define VIDEOGAMMA 2.2 + +#include +#include + +//class for making a copy of argc and argv +class CArguments +{ + public: + CArguments(int argc, char** argv); + ~CArguments(); + + int m_argc; + char** m_argv; +}; + +class CFlagManager +{ + public: + CFlagManager(); + + bool m_printhelp; //if we need to print the help message + bool m_printboblightoptions; //if we need to print the boblight options + + const char* m_address; //address to connect to, set to NULL if none given for default + int m_port; //port to connect to, set to -1 if none given for default + int m_priority; //priority, set to 128 if none given for default + bool m_fork; //if we should fork + bool m_sync; //if sync mode is enabled + + void ParseFlags(int tempargc, char** tempargv); //parsing commandline flags + virtual void PrintHelpMessage() {}; + + void PrintBoblightOptions(); //printing of boblight options (-o [light:]option=value) + void ParseBoblightOptions(void* boblight); //parsing of boblight options + bool SetVideoGamma(); //set gamma to 2.2 if not given, returns true if done + + protected: + + std::string m_flags; //string to pass to getopt, for example "c:r:a:p" + std::string m_straddress; //place to store address to connect to, because CArguments deletes argv + + std::vector m_options; //place to store boblight options + + //gets called from ParseFlags, for derived classes + virtual void ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg){}; + //gets called after getopt + virtual void PostGetopt(int optind, int argc, char** argv) {}; +}; + +#endif //FLAGMANAGER diff --git a/src/grabber-dispmanx.cpp b/src/grabber-dispmanx.cpp new file mode 100644 index 00000000..04cd1bb8 --- /dev/null +++ b/src/grabber-dispmanx.cpp @@ -0,0 +1,165 @@ +/* + * boblight + * 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 . + */ + +#include "stdint.h" + +#include "grabber-dispmanx.h" + +#include +#include + +#include "misc.h" + +//#define BOBLIGHT_DLOPEN_EXTERN +#include "boblight.h" + +using namespace std; + +CGrabberDispmanX::CGrabberDispmanX(void* boblight, volatile bool& stop, bool sync) : m_stop(stop), m_timer(&stop) +{ + int ret; + + bcm_host_init(); + + m_boblight = boblight; + m_debug = false; + m_sync = sync; + + type = VC_IMAGE_RGB888; + + display = vc_dispmanx_display_open(0); + + ret = vc_dispmanx_display_get_info(display, &info); + assert(ret == 0); +} + +CGrabberDispmanX::~CGrabberDispmanX() +{ + int ret; + + free(image); + + ret = vc_dispmanx_resource_delete(resource); + assert( ret == 0 ); + ret = vc_dispmanx_display_close(display); + assert( ret == 0 ); + + bcm_host_deinit(); +} + +bool CGrabberDispmanX::Setup() +{ + if (m_interval > 0.0) //set up timer + { + m_timer.SetInterval(Round64(m_interval * 1000000.0)); + } + + pitch = ALIGN_UP(m_size*3, 32); + + image = new char[m_size * m_size * 3]; + + resource = vc_dispmanx_resource_create(type, + m_size, + m_size, + &vc_image_ptr ); + assert(resource); + + m_error.clear(); + + return ExtendedSetup(); //run stuff from derived classes +} + +bool CGrabberDispmanX::ExtendedSetup() +{ + if (!CheckExtensions()) + return false; + + return true; +} + +bool CGrabberDispmanX::CheckExtensions() +{ + return true; +} + +bool CGrabberDispmanX::Run() +{ + int rgb[3]; + VC_RECT_T rectangle; + char* image_ptr; + + boblight_setscanrange(m_boblight, m_size, m_size); + + while(!m_stop) + { + vc_dispmanx_snapshot(display,resource, VC_IMAGE_ROT0); + + vc_dispmanx_rect_set(&rectangle, 0, 0, m_size, m_size); + + vc_dispmanx_resource_read_data(resource, &rectangle, image, m_size*3); + + image_ptr = (char *)image; + //read out the pixels + for (int y = 0; y < m_size && !m_stop; y++) + { +// image_ptr += y*m_size*3; + for (int x = 0; x < m_size && !m_stop; x++) + { + rgb[0] = image_ptr[y*m_size*3+x*3]; + rgb[1] = image_ptr[y*m_size*3+x*3 + 1]; + rgb[2] = image_ptr[y*m_size*3+x*3 + 2]; + + boblight_addpixelxy(m_boblight, x, y, rgb); + } + } + + + //send pixeldata to boblight + if (!boblight_sendrgb(m_boblight, m_sync, NULL)) + { + m_error = boblight_geterror(m_boblight); + return true; //recoverable error + } + + //when in debug mode, put the captured image on the debug window + if (m_debug) + { + printf("Debug not supproted!\n"); + m_debug = false; + } + + if (!Wait()) + { + return false; //unrecoverable error + } + } + + m_error.clear(); + + return true; +} + +bool CGrabberDispmanX::Wait() +{ + if (m_interval > 0.0) //wait for timer + { + m_timer.Wait(); + } + return true; +} + diff --git a/src/grabber-dispmanx.h b/src/grabber-dispmanx.h new file mode 100644 index 00000000..3783b101 --- /dev/null +++ b/src/grabber-dispmanx.h @@ -0,0 +1,90 @@ +/* + * boblight + * 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 . + */ + +#ifndef GRABBERDISPMANX +#define GRABBERDISPMANX + +#include "bcm_host.h" + +#include + +//#include "config.h" +#include "timer.h" + +#ifndef ALIGN_UP +#define ALIGN_UP(x,y) ((x + (y)-1) & ~((y)-1)) +#endif + +//class for grabbing with DispmanX +class CGrabberDispmanX +{ + public: + CGrabberDispmanX(void* boblight, volatile bool& stop, bool sync); + ~CGrabberDispmanX(); + + bool ExtendedSetup(); + bool Run(); + + std::string& GetError() { return m_error; } //retrieves the latest error + + void SetInterval(double interval) { m_interval = interval; } //sets interval, negative means vblanks + void SetSize(int size) { m_size = size; } //sets how many pixels we want to grab + + bool Setup(); //base setup function + + void SetDebug(const char* display); //turn on debug window + + protected: + + bool Wait(); //wait for the timer or on the vblank + volatile bool& m_stop; + + std::string m_error; //latest error + + void* m_boblight; //our handle from libboblight + + int m_size; //nr of pixels on lines to grab + + bool m_debug; //if we have debug mode on + + long double m_lastupdate; + long double m_lastmeasurement; + long double m_measurements; + int m_nrmeasurements; + + double m_interval; //interval in seconds, or negative for vblanks + CTimer m_timer; //our timer + bool m_sync; //sync mode for libboblight + + + private: + + bool CheckExtensions(); + + DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_MODEINFO_T info; + void *image; + DISPMANX_UPDATE_HANDLE_T update; + DISPMANX_RESOURCE_HANDLE_T resource; + DISPMANX_ELEMENT_HANDLE_T element; + uint32_t vc_image_ptr; + VC_IMAGE_TYPE_T type; + int pitch; +}; + +#endif //GRABBEROPENMAX diff --git a/src/misc.cpp b/src/misc.cpp new file mode 100644 index 00000000..3cf71bd0 --- /dev/null +++ b/src/misc.cpp @@ -0,0 +1,81 @@ +/* + * boblight + * 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 . + */ + +#include +#include +#include "misc.h" + +using namespace std; + +void PrintError(const std::string& error) +{ + std::cerr << "ERROR: " << error << "\n"; +} + +//get the first word (separated by whitespace) from string data and place that in word +//then remove that word from string data +bool GetWord(string& data, string& word) +{ + stringstream datastream(data); + string end; + + datastream >> word; + if (datastream.fail()) + { + data.clear(); + return false; + } + + size_t pos = data.find(word) + word.length(); + + if (pos >= data.length()) + { + data.clear(); + return true; + } + + data = data.substr(pos); + + datastream.clear(); + datastream.str(data); + + datastream >> end; + if (datastream.fail()) + data.clear(); + + return true; +} + +//convert . or , to the current locale for correct conversion of ascii float +void ConvertFloatLocale(std::string& strfloat) +{ + static struct lconv* locale = localeconv(); + + size_t pos = strfloat.find_first_of(",."); + + while (pos != string::npos) + { + strfloat.replace(pos, 1, 1, *locale->decimal_point); + pos++; + + if (pos >= strfloat.size()) + break; + + pos = strfloat.find_first_of(",.", pos); + } +} diff --git a/src/misc.h b/src/misc.h new file mode 100644 index 00000000..f6ef4f3c --- /dev/null +++ b/src/misc.h @@ -0,0 +1,191 @@ +/* + * boblight + * 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 . + */ + +#ifndef MISCUTIL +#define MISCUTIL + +#include "stdint.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +void PrintError(const std::string& error); +bool GetWord(std::string& data, std::string& word); +void ConvertFloatLocale(std::string& strfloat); + +template +inline std::string ToString(Value value) +{ + std::string data; + std::stringstream valuestream; + valuestream << value; + valuestream >> data; + return data; +} + +inline std::string GetErrno() +{ + return strerror(errno); +} + +inline std::string GetErrno(int err) +{ + return strerror(err); +} + +template +inline A Clamp(A value, B min, C max) +{ + return value < max ? (value > min ? value : min) : max; +} + +template +inline A Max(A value1, B value2) +{ + return value1 > value2 ? value1 : value2; +} + +template +inline A Max(A value1, B value2, C value3) +{ + return (value1 > value2) ? (value1 > value3 ? value1 : value3) : (value2 > value3 ? value2 : value3); +} + +template +inline A Min(A value1, B value2) +{ + return value1 < value2 ? value1 : value2; +} + +template +inline A Min(A value1, B value2, C value3) +{ + return (value1 < value2) ? (value1 < value3 ? value1 : value3) : (value2 < value3 ? value2 : value3); +} + +template +inline T Abs(T value) +{ + return value > 0 ? value : -value; +} + +template +inline A Round(B value) +{ + if (value == 0.0) + { + return 0; + } + else if (value > 0.0) + { + return (A)(value + 0.5); + } + else + { + return (A)(value - 0.5); + } +} + +inline int32_t Round32(float value) +{ + return lroundf(value); +} + +inline int32_t Round32(double value) +{ + return lround(value); +} + +inline int64_t Round64(float value) +{ + return llroundf(value); +} + +inline int64_t Round64(double value) +{ + return llround(value); +} + +inline bool StrToInt(const std::string& data, int& value) +{ + return sscanf(data.c_str(), "%i", &value) == 1; +} + +inline bool StrToInt(const std::string& data, int64_t& value) +{ + return sscanf(data.c_str(), "%ld", &value) == 1; +} + +inline bool HexStrToInt(const std::string& data, int& value) +{ + return sscanf(data.c_str(), "%x", &value) == 1; +} + +inline bool HexStrToInt(const std::string& data, int64_t& value) +{ + return sscanf(data.c_str(), "%x", &value) == 1; +} + +inline bool StrToFloat(const std::string& data, float& value) +{ + return sscanf(data.c_str(), "%f", &value) == 1; +} + +inline bool StrToFloat(const std::string& data, double& value) +{ + return sscanf(data.c_str(), "%lf", &value) == 1; +} + +inline bool StrToBool(const std::string& data, bool& value) +{ + std::string data2 = data; + std::string word; + if (!GetWord(data2, word)) + return false; + + if (word == "1" || word == "true" || word == "on" || word == "yes") + { + value = true; + return true; + } + else if (word == "0" || word == "false" || word == "off" || word == "no") + { + value = false; + return true; + } + else + { + int ivalue; + if (StrToInt(word, ivalue)) + { + value = ivalue != 0; + return true; + } + } + + return false; +} + +#endif //MISCUTIL diff --git a/src/timer.cpp b/src/timer.cpp new file mode 100644 index 00000000..343062ca --- /dev/null +++ b/src/timer.cpp @@ -0,0 +1,69 @@ +/* + * boblight + * 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 . + */ + +#include "timer.h" +#include "misc.h" +#include "timeutils.h" + +#include +using namespace std; + +CTimer::CTimer(volatile bool* stop /*=NULL*/) +{ + m_interval = -1; + m_timerstop = stop; +} + +void CTimer::SetInterval(int64_t usecs) +{ + m_interval = usecs; + Reset(); +} + +int64_t CTimer::GetInterval() +{ + return m_interval; +} + +void CTimer::Reset() +{ + m_time = GetTimeUs(); +} + +void CTimer::Wait() +{ + int64_t sleeptime; + + //keep looping until we have a timestamp that's not too old + int64_t now = GetTimeUs(); + do + { + m_time += m_interval; + sleeptime = m_time - now; + } + while(sleeptime <= m_interval * -2LL); + + if (sleeptime > m_interval * 2LL) //failsafe, m_time must be bork if we get here + { + sleeptime = m_interval * 2LL; + Reset(); + } + + USleep(sleeptime, m_timerstop); +} + diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 00000000..28bac58b --- /dev/null +++ b/src/timer.h @@ -0,0 +1,42 @@ +/* + * boblight + * 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 . + */ + +#ifndef CTIMER +#define CTIMER + +#include "stdint.h" + +#include + +class CTimer +{ + public: + CTimer(volatile bool* stop = NULL); + void SetInterval(int64_t usecs); + virtual void Wait(); + void Reset(); + + int64_t GetInterval(); + + protected: + int64_t m_time; + int64_t m_interval; + volatile bool* m_timerstop; +}; + +#endif diff --git a/src/timeutils.cpp b/src/timeutils.cpp new file mode 100644 index 00000000..b5f67f53 --- /dev/null +++ b/src/timeutils.cpp @@ -0,0 +1,56 @@ +/* + * boblight + * 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 . + */ + +#include "timeutils.h" + +void USleep(int64_t usecs, volatile bool* stop /*= NULL*/) +{ + if (usecs <= 0) + { + return; + } + else if (stop && usecs > 1000000) //when a pointer to a bool is passed, check it every second and stop when it's true + { + int64_t now = GetTimeUs(); + int64_t end = now + usecs; + + while (now < end) + { + struct timespec sleeptime = {}; + + if (*stop) + return; + else if (end - now >= 1000000) + sleeptime.tv_sec = 1; + else + sleeptime.tv_nsec = ((end - now) % 1000000) * 1000; + + nanosleep(&sleeptime, NULL); + now = GetTimeUs(); + } + } + else + { + struct timespec sleeptime; + sleeptime.tv_sec = usecs / 1000000; + sleeptime.tv_nsec = (usecs % 1000000) * 1000; + + nanosleep(&sleeptime, NULL); + } +} + diff --git a/src/timeutils.h b/src/timeutils.h new file mode 100644 index 00000000..9c9bd689 --- /dev/null +++ b/src/timeutils.h @@ -0,0 +1,49 @@ +/* + * boblight + * 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 . + */ + +#ifndef TIMEUTILS +#define TIMEUTILS + +#include "stdint.h" +//#include "config.h" + +#include +#include + +inline int64_t GetTimeUs() +{ +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + return ((int64_t)time.tv_sec * 1000000LL) + (int64_t)(time.tv_nsec + 500) / 1000LL; +#else + struct timeval time; + gettimeofday(&time, NULL); + return ((int64_t)time.tv_sec * 1000000LL) + (int64_t)time.tv_usec; +#endif +} + +template +inline T GetTimeSec() +{ + return (T)GetTimeUs() / (T)1000000.0; +} + +void USleep(int64_t usecs, volatile bool* stop = NULL); + +#endif //TIMEUTILS