diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 129 | ||||
-rw-r--r-- | Pixel.h | 34 | ||||
-rw-r--r-- | README.md | 20 | ||||
-rw-r--r-- | ambiservice.c | 39 | ||||
-rw-r--r-- | ambiservice.h | 50 | ||||
-rw-r--r-- | ambithread.c | 311 | ||||
-rw-r--r-- | ambithread.h | 68 | ||||
-rw-r--r-- | boblightservice.c | 136 | ||||
-rw-r--r-- | boblightservice.h | 49 | ||||
-rw-r--r-- | common.c | 80 | ||||
-rw-r--r-- | common.h | 45 | ||||
-rw-r--r-- | config.c | 60 | ||||
-rw-r--r-- | config.h | 71 | ||||
-rw-r--r-- | lib/boblight-functions.h | 41 | ||||
-rw-r--r-- | lib/boblight.cpp | 120 | ||||
-rw-r--r-- | lib/boblight.h | 103 | ||||
-rw-r--r-- | lib/boblight_client.cpp | 704 | ||||
-rw-r--r-- | lib/boblight_client.h | 115 | ||||
-rw-r--r-- | lib/options.h | 41 | ||||
-rw-r--r-- | softhdservice.h | 38 | ||||
-rw-r--r-- | vdrboblight.c | 412 |
22 files changed, 2669 insertions, 0 deletions
@@ -16,3 +16,6 @@ *.exe *.out *.app + +# Other Files +.dependencies diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5311afc --- /dev/null +++ b/Makefile @@ -0,0 +1,129 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile 2.13 2012/12/21 11:36:15 kls Exp $ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. + +PLUGIN = vdrboblight + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' DVBAPI.h | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The directory environment: + +# Use package data if installed...otherwise assume we're under the VDR source directory: +PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc)) +LIBDIR = $(call PKGCFG,libdir) +LOCDIR = $(call PKGCFG,locdir) +PLGCFG = $(call PKGCFG,plgcfg) +# +TMPDIR ?= /tmp + +### The compiler options: + +export CFLAGS = $(call PKGCFG,cflags) +export CXXFLAGS = $(call PKGCFG,cxxflags) + +### Allow user defined options to overwrite defaults: + +-include $(PLGCFG) + +### The version number of VDR's plugin API: + +APIVERSION = $(call PKGCFG,apiversion) +ifeq ($(strip $(APIVERSION)),) +APIVERSION = $(shell grep 'define APIVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g') +NOCONFIG := 1 +endif + +# backward compatibility with VDR version < 1.7.34 +API1733 := $(shell if [ "$(APIVERSION)" \< "1.7.34" ]; then echo true; fi; ) + +ifdef API1733 + +VDRSRC = $(VDRDIR) +ifeq ($(strip $(VDRSRC)),) +VDRSRC := ../../.. +endif +LIBDIR = $(VDRSRC)/PLUGINS/lib + +ifndef NOCONFIG +CXXFLAGS = $(call PKGCFG,cflags) +CXXFLAGS += -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses -fPIC +else +-include $(VDRSRC)/Make.global +-include $(VDRSRC)/Make.config +endif + +export CXXFLAGS +endif + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### The name of the shared object file: + +SOFILE = libvdr-$(PLUGIN).so + +### Includes and Defines (add further entries here): + +ifdef API1733 +INCLUDES += -I$(VDRSRC)/include +endif + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o ambithread.o ambiservice.o boblightservice.o common.o config.o + +### The main target: + +ifdef API1733 +all: install +else +all: $(SOFILE) $(DEVPLUGTARGETS) +endif + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Targets: + +$(SOFILE): $(OBJS) $(FFDECSA) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(DECSALIB) -o $@ + + +install-lib: $(SOFILE) + install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) + +install: install-lib $(DEVPLUGINSTALL) + +dist: clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot + @-rm -f libvdr-$(PLUGIN).so libvdr-$(PLUGIN).so.$(APIVERSION) @@ -0,0 +1,34 @@ +/* + * Pixel.h + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __PIXEL_H +#define __PIXEL_H + +//*************************************************************************** +// Pixel - format as provided by softhddevice +//*************************************************************************** + +struct Pixel +{ + unsigned char b; + unsigned char g; + unsigned char r; + unsigned char a; +}; +#endif
\ No newline at end of file @@ -1,4 +1,24 @@ vdr-plugin-boblight =================== +This is a "plugin" for the Video Disk Recorder (VDR). + Boblight with data from softhddevice + +Needs libboblight.so and boblightd configured and running (https://code.google.com/p/boblight) + + +Priority [128] Every boblight client has a priority, the higher the lower +Updaterate [25] Updaterate in Hz, 25 => 25 Updates per second from softhddevice. Boblightd has it's own updaterate, so this could be lowered +Detect cinema bars +Show mainmenu +Log level + +Threshold [20] 0-255 Blacklevel detection, Black => LED's off +Gamma [10] 0-100 Gamma corretion (divided by 10, 10 = 1.0) +Value [80] 0-200 Saturation and value are multipliers for HSV color space (divided by 10, 10 = 1.0) +Saturation [30] 0-200 Saturation and value are multipliers for HSV color space (divided by 10, 10 = 1.0) +Speed [60] 0-100 Speed is a factor for a first order lowpass filter, the higher you set it the faster the lights react. +Autospeed [0] 0-100 Autospeed adjusts the speed on top of that based on how fast the colors are changing. +Interpolation [true] Interpolation is a setting for a boblightd output device, + when it's on it will interpolate between the last two writes of a client. (Off might reduce load)
\ No newline at end of file diff --git a/ambiservice.c b/ambiservice.c new file mode 100644 index 0000000..b3b6ba8 --- /dev/null +++ b/ambiservice.c @@ -0,0 +1,39 @@ +/* + * ambiservice.h + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include "ambiservice.h" + +//*************************************************************************** +// View Modes +//*************************************************************************** + +const char* cAmbiService::viewModes[] = +{ + "atmo", + "fixed color", + "black", + "detached", + + 0 +}; + +const char* cAmbiService::toName(ViewMode vm) +{ + return viewModes[vm]; +} diff --git a/ambiservice.h b/ambiservice.h new file mode 100644 index 0000000..7ca41c6 --- /dev/null +++ b/ambiservice.h @@ -0,0 +1,50 @@ +/* + * ambiservice.c + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __AMBI_SERVICE_H +#define __AMBI_SERVICE_H + +class cAmbiService +{ + public: + + enum Cinebars + { + cbHorizontal, + cbVertical, + cbBoth, + cbCount + }; + + enum ViewMode + { + vmAtmo, + vmFixedCol, + vmBlack, + vmDetached, + vmCount + }; + + // static + + static const char* toName(ViewMode vm); + static const char* viewModes[]; +}; + +#endif // __SEDU_SERVICE_H diff --git a/ambithread.c b/ambithread.c new file mode 100644 index 0000000..3ee66e7 --- /dev/null +++ b/ambithread.c @@ -0,0 +1,311 @@ +/* + * ambithread.c + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include <vdr/plugin.h> + +#include "softhdservice.h" +#include "ambithread.h" +#include "config.h" + +//*************************************************************************** +// Class cAmbiThread +//*************************************************************************** +//*************************************************************************** +// Object +//*************************************************************************** + +cAmbiThread::cAmbiThread() +{ + loopActive = false; + image = 0; + imageSize = 0; + imageWidth = 0; + imageHeight = 0; + cineBarsHor = 0; + cineBarsVer = 0; +} + +cAmbiThread::~cAmbiThread() +{ + bob.close(); +} + +//*************************************************************************** +// Stop Thread +//*************************************************************************** + +void cAmbiThread::Stop() +{ + loopActive = false; + waitCondition.Broadcast(); // wakeup the thread + + Cancel(3); // wait up to 3 seconds for thread was stopping +} + +//*************************************************************************** +// Action +//*************************************************************************** + +void cAmbiThread::Action() +{ + MsTime wait = 0; + cMutexLock lock(&mutex); + + tell(0, "boblight Thread started (pid=%d)", getpid()); + + loopActive = true; + bob.open(); + + while (loopActive && Running()) + { + MsTime start = msNow(); + + // work ... + if(bob.ping() == success) { + + if(cfg.dirty > 0) { + cfg.dirty = 0; + bob.sendOptions(); + } + + if (cfg.viewMode == vmAtmo) + { + if (grabImage() == success) + { + detectCineBars(); + putData(); + + MsTime elapsed = msNow() - start; + wait = 1000 / cfg.frequence - elapsed; + tell(3, "sleeping %ldms (%d Hz)", wait, cfg.frequence); + } + else + { + wait = 10000; // retry softhd grab every 10 seconds + } + } + else + { + putData(); + wait = 500; // less load on fixed color or black + } + } + else { // Connection lost, reconnect + bob.close(); + bob.open(); + wait = 10000; + } + + waitCondition.TimedWait(mutex, wait); // wait time in ms + } + + bob.close(); + loopActive = false; + + tell(0, "boblight thread ended (pid=%d)", getpid()); +} + +//*************************************************************************** +// Grab Image +//*************************************************************************** + +int cAmbiThread::grabImage() +{ + SoftHDDevice_AtmoGrabService_v1_1_t req; + + free(image); + image = 0; + + cPlugin* softHdPlugin = cPluginManager::GetPlugin("softhddevice"); + int softHdGrabService = (softHdPlugin && softHdPlugin->Service(ATMO1_GRAB_SERVICE, 0)); + + if (!softHdGrabService) + return error("Can't find softhddevice %s, aborting grab, retrying in 10 seconds!", + softHdPlugin ? "service" : "plugin"); + + // grab image at sofhddevice + req.width = -64; //warum? steht hier => http://projects.vdr-developer.org/projects/plg-softhddevice/repository/revisions/master/entry/video.c#L7372 + req.height = 64; + req.img = 0; + + if (!softHdPlugin->Service(ATMO1_GRAB_SERVICE, &req) || !req.img) + return fail; + + tell(3, "Got image with %dx%d pixel; %d bytes", req.width, req.height, req.size); + + image = (Pixel*)req.img; + imageSize = req.size; + imageWidth = req.width; + imageHeight = req.height; + + return success; +} + +//*************************************************************************** +// Detect Cine Bars +//*************************************************************************** + +int cAmbiThread::detectCineBars() +{ + const int threshold = 3; // threshold for black level of cine bars + Pixel* p; + int off; + + // check horizontal bars + + if (cfg.detectCineBars == cbHorizontal || cfg.detectCineBars == cbBoth) + { + for (off = 0; off < imageHeight/5; off++) // cinebar height max 1/5 of the screen height + { + int above = 0; + + for (int x = 0; x < imageWidth; x++) + { + p = &image[off*imageWidth + x]; + + if (p->r > threshold || p->g > threshold || p->b > threshold) + above++; + + p = &image[((imageHeight-1)-off)*imageWidth + x]; + + if (p->r > threshold || p->g > threshold || p->b > threshold) + above++; + } + + if (above > imageWidth/8) // max 1/8 failed pixel + break; + } + + if (cineBarsHor != off) + { + static int last = 0; + static int count = 0; + + if (off != last) + { + last = off; + count = 0; + } + + if (count++ >= cfg.frequence) + { + count = 0; + cineBarsHor = off; + tell(0, "Switch horizontal cine bars to %d", cineBarsHor); + } + } + } + + // check vertical bars + + if (cfg.detectCineBars == cbVertical || cfg.detectCineBars == cbBoth) + { + for (off = 0; off < imageWidth/5; off++) // cinebar height max 1/5 of the screen width + { + int above = 0; + + for (int y = 0; y < imageHeight; y++) + { + p = &image[y*imageWidth + off]; + + if (p->r > threshold || p->g > threshold || p->b > threshold) + above++; + + p = &image[y*imageWidth + ((imageWidth-1)-off)]; + + if (p->r > threshold || p->g > threshold || p->b > threshold) + above++; + } + + if (above > imageHeight/6) // max 1/6 failed pixel + break; + } + + if (cineBarsVer != off) + { + static int last = 0; + static int count = 0; + + if (off != last) + { + last = off; + count = 0; + } + + if (count++ >= cfg.frequence) + { + count = 0; + + cineBarsVer = off; + tell(0, "Switch vertical cine bars to %d", cineBarsVer); + } + } + } + + return done; +} + +//*************************************************************************** +// Put Data +//*************************************************************************** + +int cAmbiThread::putData() +{ + + if (cfg.viewMode == vmFixedCol) + { + int pFixedCol[3] = {cfg.fixedR, cfg.fixedG, cfg.fixedB}; + bob.writePix(pFixedCol); + } + else if (cfg.viewMode == vmBlack) { + int pFixedCol[3] = {0,0,0}; + bob.writePix(pFixedCol); + } + else if(cfg.viewMode == vmAtmo) { + + int row = 0; + Pixel pixel = {0,0,0,0}; + Pixel* p = &pixel; + + for (int y = 0; y < imageHeight; y++) { + // skip horizontal cinebars + if(y < cineBarsHor) continue; + if(y > imageHeight - cineBarsHor) continue; + + int rgb[3]; + row = imageWidth * y; + for (int x = 0; x < imageWidth; x++) { + // skip vertical cinebars + if(x < cineBarsVer) continue; + if(x > imageWidth - cineBarsVer) continue; + + p = &image[row + x]; + rgb[0] = p->r; + rgb[1] = p->g; + rgb[2] = p->b; + bob.writeColor(rgb, x - cineBarsVer, y - cineBarsHor); + } + } + bob.setScanRange(imageWidth - (2*cineBarsVer), imageHeight - (2*cineBarsHor)); + } + + bob.send(); + + return success; +} diff --git a/ambithread.h b/ambithread.h new file mode 100644 index 0000000..d4fe822 --- /dev/null +++ b/ambithread.h @@ -0,0 +1,68 @@ +/* + * ambithread.h + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include <queue> + +#include <vdr/thread.h> + +#include "common.h" +#include "config.h" +#include "Pixel.h" +#include "boblightservice.h" + + +//*************************************************************************** +// SEDU Thread +//*************************************************************************** + +class cAmbiThread : public cThread, public cAmbiService +{ + public: + + cAmbiThread(); + ~cAmbiThread(); + + int isRunning() { return Running(); } + + // interface + + void Stop(); + + private: + + void Action(void); + + int grabImage(); + int detectCineBars(); + int putData(); + + // data + cBoblight bob; + + cMutex mutex; + cCondVar waitCondition; + int loopActive; + + Pixel* image; + int cineBarsHor; + int cineBarsVer; + int imageSize; + int imageWidth; + int imageHeight; +};
\ No newline at end of file diff --git a/boblightservice.c b/boblightservice.c new file mode 100644 index 0000000..a6f5692 --- /dev/null +++ b/boblightservice.c @@ -0,0 +1,136 @@ +/* + * boblightservice.c + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> + +#define BOBLIGHT_DLOPEN +#include "lib/boblight.h" +#include "boblightservice.h" + +cBoblight::cBoblight() +{ + + char* boblight_error = boblight_loadlibrary(NULL); + if (boblight_error) + { + error("Couldn't load libboblight"); + } +} + +//*************************************************************************** +// Open/Close +//*************************************************************************** + +int cBoblight::open() +{ + //init boblight + m_boblight = boblight_init(); + tell(1, "Successfully loaded and initalized libboblight"); + + if (!boblight_connect(m_boblight, NULL, -1, 1000000) || !boblight_setpriority(m_boblight, cfg.priority)) + { + tell(0, "Error connecting to boblight %s", boblight_geterror(m_boblight)); + close(); + return fail; + } + tell(0, "Connected to boblight"); + sendOptions(); + return success; +} + +int cBoblight::close() +{ + tell(1, "Destroying boblight"); + boblight_destroy(m_boblight); // calls delete *void + m_boblight = 0; // set pointer to 0 + return success; +} + +int cBoblight::ping() { + if(m_boblight == 0) { + tell(1, "boblight not initalized"); + return fail; + } + + if (!boblight_ping(m_boblight, NULL)) { + tell(0, "Connecting to boblight lost: %s", boblight_geterror(m_boblight)); + return fail; + } + return success; +} + +//*************************************************************************** +// Write Pixel +//*************************************************************************** + +int cBoblight::writePix(int *rgb) +{ + boblight_addpixel(m_boblight, -1, rgb); + + return success; +} + +int cBoblight::writeColor(int *rgb, int x, int y) +{ + boblight_addpixelxy(m_boblight, x, y, rgb); + + return success; +} + +int cBoblight::send() { + if (!boblight_sendrgb(m_boblight, 0, NULL)) + { + //m_error = boblight_geterror(m_boblight); + return fail; + } + return success; +} + +int cBoblight::setScanRange(int width, int height) { + boblight_setscanrange(m_boblight, width, height); + return success; +} + +int cBoblight::sendOptions() { + if (m_boblight == 0) return fail; + char buf[32]; + + sprintf(buf, "%s %1f", "value", cfg.value * 0.01); + boblight_setoption(m_boblight, -1, buf); + + sprintf(buf, "%s %d", "threshold", cfg.threshold); + boblight_setoption(m_boblight, -1, buf); + + sprintf(buf, "%s %.1f", "gamma", cfg.gamma * 0.01); + boblight_setoption(m_boblight, -1, buf); + + sprintf(buf, "%s %1f", "saturation", cfg.saturation * 0.01); + boblight_setoption(m_boblight, -1, buf); + + sprintf(buf, "%s %d", "speed", cfg.speed); + boblight_setoption(m_boblight, -1, buf); + + sprintf(buf, "%s %d", "autospeed", cfg.autospeed); + boblight_setoption(m_boblight, -1, buf); + + sprintf(buf, "%s %s", "interpolation", cfg.interpolation ? "true" : "false"); + boblight_setoption(m_boblight, -1, buf); + + return success; +}
\ No newline at end of file diff --git a/boblightservice.h b/boblightservice.h new file mode 100644 index 0000000..c34d9f3 --- /dev/null +++ b/boblightservice.h @@ -0,0 +1,49 @@ +/* + * boblightservice.h + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __BOBLIGHT_H +#define __BOBLIGHT_H + +#include "common.h" +#include "config.h" +#include "ambiservice.h" + +class cBoblight : public cAmbiService +{ + public: + + cBoblight(); + ~cBoblight() { close(); } + + int open(); + int close(); + + int writePix(int *rgb); + int writeColor(int *rgb, int x, int y); + int setScanRange(int width, int height); + int ping(); + int send(); + int sendOptions(); + + private: + void* m_boblight; + +}; + +#endif
\ No newline at end of file diff --git a/common.c b/common.c new file mode 100644 index 0000000..2351300 --- /dev/null +++ b/common.c @@ -0,0 +1,80 @@ +/* + * common.c: EPG2VDR plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <sys/time.h> +#include <stdarg.h> +#include <string.h> +#include <syslog.h> + +#include <vdr/thread.h> + +#include "common.h" +#include "config.h" + +cMutex logMutex; + +//*************************************************************************** +// Tell +//*************************************************************************** + +void tell(int eloquence, const char* format, ...) +{ + if (cfg.loglevel < eloquence) + return ; + + const int sizeBuffer = 100000; + char t[sizeBuffer+100]; *t = 0; + va_list ap; + + cMutexLock lock(&logMutex); + + va_start(ap, format); + + snprintf(t, sizeBuffer, "BOBLIGHT: "); + vsnprintf(t+strlen(t), sizeBuffer-strlen(t), format, ap); + + syslog(LOG_ERR, "%s", t); + + va_end(ap); +} + +//*************************************************************************** +// Error +//*************************************************************************** + +int error(const char* format, ...) +{ + const int sizeBuffer = 100000; + char t[sizeBuffer+100]; *t = 0; + va_list ap; + + cMutexLock lock(&logMutex); + + va_start(ap, format); + + snprintf(t, sizeBuffer, "BOBLIGHT: "); + vsnprintf(t+strlen(t), sizeBuffer-strlen(t), format, ap); + + syslog(LOG_ERR, "%s", t); + + va_end(ap); + + return fail; +} + +//*************************************************************************** +// msNow +//*************************************************************************** + +MsTime msNow() +{ + timeval tv; + + gettimeofday(&tv, 0); + + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..747a085 --- /dev/null +++ b/common.h @@ -0,0 +1,45 @@ +/* + * common.h: EPG2VDR plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __COMMON_H +#define __COMMON_H + +//*************************************************************************** +// +//*************************************************************************** + +enum Misc +{ + success = 0, + done = success, + fail = -1, + ignore = -2, + na = -1, + yes = 1, + on = 1, + off = 0, + no = 0, + TB = 1 +}; + +//*************************************************************************** +// Time +//*************************************************************************** + +typedef unsigned long long MsTime; + +MsTime msNow(); + +//*************************************************************************** +// Tell +//*************************************************************************** + +void tell(int eloquence, const char* format, ...); +int error(const char* format, ...); + +//*************************************************************************** +#endif //___COMMON_H diff --git a/config.c b/config.c new file mode 100644 index 0000000..02e33ad --- /dev/null +++ b/config.c @@ -0,0 +1,60 @@ +/* + * config.c + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include <string.h> + +#include "config.h" +#include "common.h" + + +//*************************************************************************** +// Global Configuration +//*************************************************************************** + +cBobConfig cfg; + +//*************************************************************************** +// cConfigData +//*************************************************************************** + +cBobConfig::cBobConfig() +{ + // to be configured + frequence = 25; + threshold = 20; + gamma = 10; + value = 80; + saturation = 30; + speed = 60; + autospeed = 0; + interpolation = 1; //bool + priority = 128; + + detectCineBars = cbBoth; + + loglevel = 0; + + showMainmenu = yes; + viewMode = vmAtmo; + fixedR = 111; + fixedG = 101; + fixedB = 0; + + dirty = 0; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..9978928 --- /dev/null +++ b/config.h @@ -0,0 +1,71 @@ +/* + * config.h + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __BOB_CONFIG_H +#define __BOB_CONFIG_H + +#include "common.h" +#include "ambiservice.h" + +//*************************************************************************** +// Configuration +//*************************************************************************** + +class cBobConfig : public cAmbiService +{ + public: + + cBobConfig(); + + // adjust + + int frequence; + int threshold; + int gamma; + int value; + int saturation; + int speed; + int autospeed; + + int interpolation; //bool + int priority; + + // technical + + ViewMode viewMode; + int fixedR; + int fixedG; + int fixedB; + + int showMainmenu; //bool + Cinebars detectCineBars; + + int loglevel; + + int dirty; + +}; + +//*************************************************************************** +// Global Configuration +//*************************************************************************** + +extern cBobConfig cfg; + +#endif diff --git a/lib/boblight-functions.h b/lib/boblight-functions.h new file mode 100644 index 0000000..0e0731e --- /dev/null +++ b/lib/boblight-functions.h @@ -0,0 +1,41 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +//these definitions can be expanded to make normal prototypes, or functionpointers and dlsym lines + +BOBLIGHT_FUNCTION(void*, boblight_init, ()); +BOBLIGHT_FUNCTION(void, boblight_destroy, (void* vpboblight)); + +BOBLIGHT_FUNCTION(int, boblight_connect, (void* vpboblight, const char* address, int port, int usectimeout)); +BOBLIGHT_FUNCTION(int, boblight_setpriority, (void* vpboblight, int priority)); +BOBLIGHT_FUNCTION(const char*, boblight_geterror, (void* vpboblight)); +BOBLIGHT_FUNCTION(int, boblight_getnrlights, (void* vpboblight)); +BOBLIGHT_FUNCTION(const char*, boblight_getlightname, (void* vpboblight, int lightnr)); + +BOBLIGHT_FUNCTION(int, boblight_getnroptions, (void* vpboblight)); +BOBLIGHT_FUNCTION(const char*, boblight_getoptiondescript,(void* vpboblight, int option)); +BOBLIGHT_FUNCTION(int, boblight_setoption, (void* vpboblight, int lightnr, const char* option)); +BOBLIGHT_FUNCTION(int, boblight_getoption, (void* vpboblight, int lightnr, const char* option, const char** output)); + +BOBLIGHT_FUNCTION(void, boblight_setscanrange, (void* vpboblight, int width, int height)); + +BOBLIGHT_FUNCTION(int, boblight_addpixel, (void* vpboblight, int lightnr, int* rgb)); +BOBLIGHT_FUNCTION(void, boblight_addpixelxy, (void* vpboblight, int x, int y, int* rgb)); + +BOBLIGHT_FUNCTION(int, boblight_sendrgb, (void* vpboblight, int sync, int* outputused)); +BOBLIGHT_FUNCTION(int, boblight_ping, (void* vpboblight, int* outputused)); diff --git a/lib/boblight.cpp b/lib/boblight.cpp new file mode 100644 index 0000000..6c52136 --- /dev/null +++ b/lib/boblight.cpp @@ -0,0 +1,120 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "boblight.h" +#include "boblight_client.h" + +using namespace boblight; + +//C wrapper for C++ class + +void* boblight_init() +{ + CBoblight* boblight = new CBoblight; + return reinterpret_cast<void*>(boblight); +} + +void boblight_destroy(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + delete boblight; +} + +int boblight_connect(void* vpboblight, const char* address, int port, int usectimeout) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->Connect(address, port, usectimeout); +} + +int boblight_setpriority(void* vpboblight, int priority) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->SetPriority(priority); +} + +const char* boblight_geterror(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->GetError(); +} + +int boblight_getnrlights(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->GetNrLights(); +} + +const char* boblight_getlightname(void* vpboblight, int lightnr) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->GetLightName(lightnr); +} + +int boblight_getnroptions(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->GetNrOptions(); +} + +const char* boblight_getoptiondescript(void* vpboblight, int option) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->GetOptionDescription(option); +} + +int boblight_setoption(void* vpboblight, int lightnr, const char* option) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->SetOption(lightnr, option); +} + +int boblight_getoption(void* vpboblight, int lightnr, const char* option, const char** output) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->GetOption(lightnr, option, output); +} + +void boblight_setscanrange(void* vpboblight, int width, int height) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + boblight->SetScanRange(width, height); +} + +int boblight_addpixel(void* vpboblight, int lightnr, int* rgb) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->AddPixel(lightnr, rgb); +} + +void boblight_addpixelxy(void* vpboblight, int x, int y, int* rgb) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + boblight->AddPixel(rgb, x, y); +} + +int boblight_sendrgb(void* vpboblight, int sync, int* outputused) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->SendRGB(sync, outputused); +} + +int boblight_ping(void* vpboblight, int* outputused) +{ + CBoblight* boblight = reinterpret_cast<CBoblight*>(vpboblight); + return boblight->Ping(outputused, true); +} diff --git a/lib/boblight.h b/lib/boblight.h new file mode 100644 index 0000000..c596357 --- /dev/null +++ b/lib/boblight.h @@ -0,0 +1,103 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +//if you define BOBLIGHT_DLOPEN, all boblight functions are defined as pointers +//you can then call boblight_loadlibrary to load libboblight with dlopen and the function pointers with dlsym +//if you pass NULL to boblight_loadlibrary's first argument, the default filename for libboblight is used +//if boblight_loadlibrary returns NULL, dlopen and dlsym went ok, if not it returns a char* from dlerror + +//if you want to use the boblight functions from multiple files, you can define BOBLIGHT_DLOPEN in one file, +//and define BOBLIGHT_DLOPEN_EXTERN in the other file, the functionpointers are then defined as extern + +#ifndef LIBBOBLIGHT +#define LIBBOBLIGHT + + #if !defined(BOBLIGHT_DLOPEN) && !defined(BOBLIGHT_DLOPEN_EXTERN) + + #ifdef __cplusplus + extern "C" { + #endif + + //generate normal prototypes + #define BOBLIGHT_FUNCTION(returnvalue, name, arguments) returnvalue name arguments + #include "boblight-functions.h" + #undef BOBLIGHT_FUNCTION + + #ifdef __cplusplus + } + #endif + + #elif defined(BOBLIGHT_DLOPEN) + + #include <dlfcn.h> + #include <stddef.h> + + //generate function pointers + #define BOBLIGHT_FUNCTION(returnvalue, name, arguments) returnvalue (* name ) arguments = NULL + #include "boblight-functions.h" + #undef BOBLIGHT_FUNCTION + + #ifdef __cplusplus + #define BOBLIGHT_CAST(value) reinterpret_cast<value> + #else + #define BOBLIGHT_CAST(value) (value) + #endif + + //gets a functionpointer from dlsym, and returns char* from dlerror if it didn't work + #define BOBLIGHT_FUNCTION(returnvalue, name, arguments) \ + name = BOBLIGHT_CAST(returnvalue (*) arguments)(dlsym(p_boblight, #name)); \ + { char* error = dlerror(); if (error) return error; } + + void* p_boblight = NULL; //where we put the lib + + //load function pointers + char* boblight_loadlibrary(const char* filename) + { + if (filename == NULL) + filename = "libboblight.so"; + + if (p_boblight != NULL) + { + dlclose(p_boblight); + p_boblight = NULL; + } + + p_boblight = dlopen(filename, RTLD_NOW); + if (p_boblight == NULL) + return dlerror(); + + //generate dlsym lines + #include "boblight-functions.h" + + return NULL; + } + #undef BOBLIGHT_FUNCTION + #undef BOBLIGHT_CAST + + //you can define BOBLIGHT_DLOPEN_EXTERN when you load the library in another file + #elif defined(BOBLIGHT_DLOPEN_EXTERN) + + extern char* boblight_loadlibrary(const char* filename); + extern void* p_boblight; + #define BOBLIGHT_FUNCTION(returnvalue, name, arguments) extern returnvalue (* name ) arguments + #include "boblight-functions.h" + #undef BOBLIGHT_FUNCTION + + #endif //BOBLIGHT_DLOPEN_EXTERN +#endif //LIBBOBLIGHT + diff --git a/lib/boblight_client.cpp b/lib/boblight_client.cpp new file mode 100644 index 0000000..dfab262 --- /dev/null +++ b/lib/boblight_client.cpp @@ -0,0 +1,704 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + + +#include "util/inclstdint.h" + +#include <string> +#include <iostream> //debug +#include <sstream> + +#include "boblight_client.h" +#include "util/misc.h" +#include "util/timeutils.h" +#include "protocolversion.h" + +using namespace std; +using namespace boblight; + +#define GAMMASIZE (sizeof(m_gammacurve) / sizeof(m_gammacurve[0])) + +CLight::CLight() +{ + #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) variable = default; + #include "options.h" + #undef BOBLIGHT_OPTION + + m_singlechange = 0.0; + + m_width = -1; + m_height = -1; + + memset(m_rgb, 0, sizeof(m_rgb)); + m_rgbcount = 0; + memset(m_prevrgb, 0, sizeof(m_prevrgb)); + memset(m_hscanscaled, 0, sizeof(m_hscanscaled)); + memset(m_vscanscaled, 0, sizeof(m_vscanscaled)); + + for (int i = 0; i < GAMMASIZE; i++) + m_gammacurve[i] = i; +} + +string CLight::SetOption(const char* option, bool& send) +{ + string stroption = option; + string strname; + + send = false; + + if (!GetWord(stroption, strname)) + return "emtpy option"; //string with only whitespace + + #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ + if (strname == #name) \ + { \ + type value; \ + if (#type == "bool")\ + {\ + if (!StrToBool(stroption, *(bool*)(&value)))\ + return "invalid value " + stroption + " for option " + strname + " with type " + #type; \ + }\ + else\ + {\ + stringstream stream; \ + stream << stroption; \ + stream >> value; \ + if (stream.fail()) return "invalid value " + stroption + " for option " + strname + " with type " + #type; \ + \ + }\ + variable = value; \ + postprocess\ + \ + return ""; \ + } + #include "options.h" + #undef BOBLIGHT_OPTION + + return "unknown option " + strname; +} + +std::string CLight::GetOption(const char* option, std::string& output) +{ + string stroption = option; + string strname; + + if (!GetWord(stroption, strname)) + return "emtpy option"; //string with only whitespace + + #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ + if (#name == strname)\ + {\ + output = ToString(variable);\ + return "";\ + } + #include "options.h" + #undef BOBLIGHT_OPTION + + return "unknown option"; +} + +void CLight::AddPixel(int* rgb) +{ + if (rgb[0] >= m_threshold || rgb[1] >= m_threshold || rgb[2] >= m_threshold) + { + if (m_gamma == 1.0) + { + m_rgb[0] += Clamp(rgb[0], 0, 255); + m_rgb[1] += Clamp(rgb[1], 0, 255); + m_rgb[2] += Clamp(rgb[2], 0, 255); + } + else + { + m_rgb[0] += m_gammacurve[Clamp(rgb[0], 0, GAMMASIZE - 1)]; + m_rgb[1] += m_gammacurve[Clamp(rgb[1], 0, GAMMASIZE - 1)]; + m_rgb[2] += m_gammacurve[Clamp(rgb[2], 0, GAMMASIZE - 1)]; + } + } + m_rgbcount++; +} + +void CLight::GetRGB(float* rgb) +{ + //if no pixels are set, the denominator is 0, so just return black + if (m_rgbcount == 0) + { + for (int i = 0; i < 3; i++) + { + rgb[i] = 0.0f; + m_rgb[i] = 0.0f; + } + + return; + } + + //convert from numerator/denominator to float + for (int i = 0; i < 3; i++) + { + rgb[i] = Clamp(m_rgb[i] / (float)m_rgbcount / 255.0f, 0.0f, 1.0f); + m_rgb[i] = 0.0f; + } + m_rgbcount = 0; + + //this tries to set the speed based on how fast the input is changing + //it needs sync mode to work properly + if (m_autospeed > 0.0) + { + float change = Abs(rgb[0] - m_prevrgb[0]) + Abs(rgb[1] - m_prevrgb[1]) + Abs(rgb[2] - m_prevrgb[2]); + change /= 3.0; + + //only apply singlechange if it's large enough, otherwise we risk sending it continously + if (change > 0.001) + m_singlechange = Clamp(change * m_autospeed / 10.0, 0.0, 1.0); + else + m_singlechange = 0.0; + } + + memcpy(m_prevrgb, rgb, sizeof(m_prevrgb)); + + //we need some hsv adjustments + if (m_value != 1.0 || m_valuerange[0] != 0.0 || m_valuerange[1] != 1.0 || + m_saturation != 1.0 || m_satrange[0] != 0.0 || m_satrange[1] != 1.0) + { + //rgb - hsv conversion, thanks wikipedia! + float hsv[3]; + float max = Max(rgb[0], rgb[1], rgb[2]); + float min = Min(rgb[0], rgb[1], rgb[2]); + + if (min == max) //grayscale + { + hsv[0] = -1.0f; //undefined + hsv[1] = 0.0; //no saturation + hsv[2] = min; //value + } + else + { + if (max == rgb[0]) //red zone + { + hsv[0] = (60.0f * ((rgb[1] - rgb[2]) / (max - min)) + 360.0f); + while (hsv[0] >= 360.0f) + hsv[0] -= 360.0f; + } + else if (max == rgb[1]) //green zone + { + hsv[0] = 60.0f * ((rgb[2] - rgb[0]) / (max - min)) + 120.0f; + } + else if (max == rgb[2]) //blue zone + { + hsv[0] = 60.0f * ((rgb[0] - rgb[1]) / (max - min)) + 240.0f; + } + + hsv[1] = (max - min) / max; //saturation + hsv[2] = max; //value + } + + //saturation and value adjustment + hsv[1] = Clamp(hsv[1] * m_saturation, m_satrange[0], m_satrange[1]); + hsv[2] = Clamp(hsv[2] * m_value, m_valuerange[0], m_valuerange[1]); + + if (hsv[0] == -1.0f) //grayscale + { + for (int i = 0; i < 3; i++) + rgb[i] = hsv[2]; + } + else + { + int hi = (int)(hsv[0] / 60.0f) % 6; + float f = (hsv[0] / 60.0f) - (float)(int)(hsv[0] / 60.0f); + + float s = hsv[1]; + float v = hsv[2]; + float p = v * (1.0f - s); + float q = v * (1.0f - f * s); + float t = v * (1.0f - (1.0f - f) * s); + + if (hi == 0) + { rgb[0] = v; rgb[1] = t; rgb[2] = p; } + else if (hi == 1) + { rgb[0] = q; rgb[1] = v; rgb[2] = p; } + else if (hi == 2) + { rgb[0] = p; rgb[1] = v; rgb[2] = t; } + else if (hi == 3) + { rgb[0] = p; rgb[1] = q; rgb[2] = v; } + else if (hi == 4) + { rgb[0] = t; rgb[1] = p; rgb[2] = v; } + else if (hi == 5) + { rgb[0] = v; rgb[1] = p; rgb[2] = q; } + } + + for (int i = 0; i < 3; i++) + rgb[i] = Clamp(rgb[i], 0.0f, 1.0f); + } +} + +//scale the light's scanrange to the dimensions set with boblight_setscanrange() +void CLight::SetScanRange(int width, int height) +{ + m_width = width; + m_height = height; + + m_hscanscaled[0] = Round32(m_hscan[0] / 100.0 * ((float)width - 1)); + m_hscanscaled[1] = Round32(m_hscan[1] / 100.0 * ((float)width - 1)); + m_vscanscaled[0] = Round32(m_vscan[0] / 100.0 * ((float)height - 1)); + m_vscanscaled[1] = Round32(m_vscan[1] / 100.0 * ((float)height - 1)); +} + +int CBoblight::Connect(const char* address, int port, int usectimeout) +{ + CMessage message; + CTcpData data; + int64_t now; + int64_t target; + string word; + + //set address + m_usectimeout = usectimeout; + if (address) + m_address = address; + else + m_address = "127.0.0.1"; + + //set port + if (port >= 0) + m_port = port; + else + m_port = 19333; + + //try to open a tcp connection + if (m_socket.Open(m_address, m_port, m_usectimeout) != SUCCESS) + { + m_error = m_socket.GetError(); + return 0; + } + + //write hello to the server, we should get hello back + if (!WriteDataToSocket("hello\n")) + return 0; + + if (!ReadDataToQueue()) + return 0; + + message = m_messagequeue.GetMessage(); + if (!ParseWord(message, "hello")) + { + m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; + return 0; + } + + //get the protocol version from the server + if (!WriteDataToSocket("get version\n")) + return 0; + + if (!ReadDataToQueue()) + return 0; + + message = m_messagequeue.GetMessage(); + + if (!ParseWord(message, "version") || !GetWord(message.message, word)) + { + m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; + return 0; + } + + //if we don't get the same protocol version back as we have, we can't work together + if (word != PROTOCOLVERSION) + { + m_error = "version mismatch, " + m_address + ":" + ToString(m_port) + " has version \"" + word + + "\", libboblight has version \"" + PROTOCOLVERSION + "\""; + return 0; + } + + //get lights info, like number, names and area + if (!WriteDataToSocket("get lights\n")) + return 0; + + if (!ReadDataToQueue()) + return 0; + + message = m_messagequeue.GetMessage(); + if (!ParseLights(message)) + { + m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; + return 0; + } + + return 1; +} + +CBoblight::CBoblight() +{ + int padsize = 1; + //get option name pad size so it looks pretty + #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ + if (strlen(#name) + 1 > padsize)\ + padsize = strlen(#name) + 1; + #include "options.h" + #undef BOBLIGHT_OPTION + + //stick in a line that describes the options + string option = "name"; + option.append(Max(padsize - option.length(), 1), ' '); + option += "type min max default"; + m_options.push_back(option); + + //fill vector with option strings + #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ + {\ + string option = #name;\ + option.append(padsize - strlen(#name), ' ');\ + \ + option += #type;\ + option.append(Max(8 - strlen(#type), 1), ' ');\ + \ + option += #min;\ + option.append(Max(8 - strlen(#min), 1), ' ');\ + \ + option += #max;\ + option.append(Max(8 - strlen(#max), 1), ' ');\ + \ + if (strcmp(#default, "-1.0") == 0)\ + option += "set by boblightd";\ + else\ + option += #default;\ + \ + m_options.push_back(option);\ + } + #include "options.h" + #undef BOBLIGHT_OPTION +} + +//reads from socket until timeout or one message has arrived +bool CBoblight::ReadDataToQueue() +{ + CTcpData data; + int64_t now = GetTimeUs(); + int64_t target = now + m_usectimeout; + int nrmessages = m_messagequeue.GetNrMessages(); + + while (now < target && m_messagequeue.GetNrMessages() == nrmessages) + { + if (m_socket.Read(data) != SUCCESS) + { + m_error = m_socket.GetError(); + return false; + } + + m_messagequeue.AddData(data.GetData()); + + if (m_messagequeue.GetRemainingDataSize() > MAXDATA) + { + m_error = m_address + ":" + ToString(m_port) + " sent too much data"; + return false; + } + + now = GetTimeUs(); + } + + if (nrmessages == m_messagequeue.GetNrMessages()) + { + m_error = m_address + ":" + ToString(m_port) + " read timed out"; + return false; + } + return true; +} + +bool CBoblight::WriteDataToSocket(std::string strdata) +{ + CTcpData data; + data.SetData(strdata); + + if (m_socket.Write(data) != SUCCESS) + { + m_error = m_socket.GetError(); + return false; + } + + return true; +} + +//removes one word from the string in the messages, and compares it to wordtocmp +bool CBoblight::ParseWord(CMessage& message, std::string wordtocmp) +{ + string readword; + if (!GetWord(message.message, readword) || readword != wordtocmp) + return false; + + return true; +} + +bool CBoblight::ParseLights(CMessage& message) +{ + string word; + int nrlights; + + //first word in the message is "lights", second word is the number of lights + if (!ParseWord(message, "lights") || !GetWord(message.message, word) || !StrToInt(word, nrlights) || nrlights < 1) + return false; + + for (int i = 0; i < nrlights; i++) + { + CLight light; + + //read some data to the message queue if we have no messages + if (m_messagequeue.GetNrMessages() == 0) + { + if (!ReadDataToQueue()) + return false; + } + + message = m_messagequeue.GetMessage(); + + //first word sent is "light, second one is the name + if (!ParseWord(message, "light") || !GetWord(message.message, light.m_name)) + { + return false; + } + + //third one is "scan" + if (!ParseWord(message, "scan")) + return false; + + //now we read the scanrange + string scanarea; + for (int i = 0; i < 4; i++) + { + if (!GetWord(message.message, word)) + return false; + + scanarea += word + " "; + } + + ConvertFloatLocale(scanarea); //workaround for locale mismatch (, and .) + + if (sscanf(scanarea.c_str(), "%f %f %f %f", light.m_vscan, light.m_vscan + 1, light.m_hscan, light.m_hscan + 1) != 4) + return false; + + m_lights.push_back(light); + } + return true; +} + +const char* CBoblight::GetLightName(int lightnr) +{ + if (lightnr < 0) //negative lights don't exist, so we set it to an invalid number to get the error message + lightnr = m_lights.size(); + + if (CheckLightExists(lightnr)) + return m_lights[lightnr].m_name.c_str(); + + return NULL; +} + +int CBoblight::SetPriority(int priority) +{ + string data = "set priority " + ToString(priority) + "\n"; + + return WriteDataToSocket(data); +} + +bool CBoblight::CheckLightExists(int lightnr, bool printerror /*= true*/) +{ + if (lightnr >= (int)m_lights.size()) + { + if (printerror) + { + m_error = "light " + ToString(lightnr) + " doesn't exist (have " + ToString(m_lights.size()) + " lights)"; + } + return false; + } + return true; +} + +void CBoblight::SetScanRange(int width, int height) +{ + for (int i = 0; i < m_lights.size(); i++) + { + m_lights[i].SetScanRange(width, height); + } +} + +int CBoblight::AddPixel(int lightnr, int* rgb) +{ + if (!CheckLightExists(lightnr)) + return 0; + + if (lightnr < 0) + { + for (int i = 0; i < m_lights.size(); i++) + m_lights[i].AddPixel(rgb); + } + else + { + m_lights[lightnr].AddPixel(rgb); + } + + return 1; +} + +void CBoblight::AddPixel(int* rgb, int x, int y) +{ + for (int i = 0; i < m_lights.size(); i++) + { + if (x >= m_lights[i].m_hscanscaled[0] && x <= m_lights[i].m_hscanscaled[1] && + y >= m_lights[i].m_vscanscaled[0] && y <= m_lights[i].m_vscanscaled[1]) + { + m_lights[i].AddPixel(rgb); + } + } +} + +int CBoblight::SendRGB(int sync, int* outputused) +{ + string data; + + for (int i = 0; i < m_lights.size(); i++) + { + float rgb[3]; + m_lights[i].GetRGB(rgb); + data += "set light " + m_lights[i].m_name + " rgb " + ToString(rgb[0]) + " " + ToString(rgb[1]) + " " + ToString(rgb[2]) + "\n"; + if (m_lights[i].m_autospeed > 0.0 && m_lights[i].m_singlechange > 0.0) + data += "set light " + m_lights[i].m_name + " singlechange " + ToString(m_lights[i].m_singlechange) + "\n"; + } + + //send a message that we want devices to sync to our input + if (sync) + data += "sync\n"; + + //if we want to check if our output is used, send a ping message + if (outputused) + data += "ping\n"; + + if (!WriteDataToSocket(data)) + return 0; + + if (outputused) + return Ping(outputused, false); + else + return 1; +} + +int CBoblight::Ping(int* outputused, bool send) +{ + string word; + + if (send) + { + if (!WriteDataToSocket("ping\n")) + return 0; + } + + if (!ReadDataToQueue()) + return 0; + + CMessage message = m_messagequeue.GetMessage(); + + if (!GetWord(message.message, word) || word != "ping") + { + m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; + return 0; + } + + //client can set outputused to NULL + if (outputused) + { + if (!GetWord(message.message, word) || !StrToInt(word, *outputused)) + { + m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; + return 0; + } + } + + return 1; +} + +int CBoblight::GetNrOptions() +{ + return m_options.size(); +} + +const char* CBoblight::GetOptionDescription(int option) +{ + if (option < 0 || option >= m_options.size()) + return NULL; + + return m_options[option].c_str(); +} + +int CBoblight::SetOption(int lightnr, const char* option) +{ + string error; + string data; + bool send; + + if (!CheckLightExists(lightnr)) + return 0; + + if (lightnr < 0) + { + for (int i = 0; i < m_lights.size(); i++) + { + error = m_lights[i].SetOption(option, send); + if (!error.empty()) + { + m_error = error; + return 0; + } + if (send) + { + data += "set light " + m_lights[i].m_name + " " + option + "\n"; + } + } + } + else + { + error = m_lights[lightnr].SetOption(option, send); + if (!error.empty()) + { + m_error = error; + return 0; + } + if (send) + { + data += "set light " + m_lights[lightnr].m_name + " " + option + "\n"; + } + } + + if (!WriteDataToSocket(data)) + return 0; + + return 1; +} + +int CBoblight::GetOption(int lightnr, const char* option, const char** output) +{ + if (lightnr < 0) //negative lights don't exist, so we set it to an invalid number to get the error message + lightnr = m_lights.size(); + + if (!CheckLightExists(lightnr)) + return 0; + + string error = m_lights[lightnr].GetOption(option, m_lastoption); + if (!error.empty()) + { + m_error = error; + return 0; + } + + *output = m_lastoption.c_str(); + + return 1; +} diff --git a/lib/boblight_client.h b/lib/boblight_client.h new file mode 100644 index 0000000..aac141d --- /dev/null +++ b/lib/boblight_client.h @@ -0,0 +1,115 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef CBOBLIGHT +#define CBOBLIGHT + +#include <string> +#include <vector> + +#include "util/tcpsocket.h" +#include "util/messagequeue.h" + +namespace boblight +{ + class CLight + { + public: + CLight(); + + std::string SetOption(const char* option, bool& send); + std::string GetOption(const char* option, std::string& output); + + void SetScanRange(int width, int height); + void AddPixel(int* rgb); + + std::string m_name; + float m_speed; + float m_autospeed; + float m_singlechange; + + bool m_interpolation; + bool m_use; + + float m_value; + float m_valuerange[2]; + float m_saturation; + float m_satrange[2]; + int m_threshold; + float m_gamma; + float m_gammacurve[256]; + + float m_rgb[3]; + int m_rgbcount; + float m_prevrgb[3]; + void GetRGB(float* rgb); + + float m_hscan[2]; + float m_vscan[2]; + int m_width; + int m_height; + int m_hscanscaled[2]; + int m_vscanscaled[2]; + }; + + class CBoblight + { + public: + CBoblight(); + + int Connect(const char* address, int port, int usectimeout); + const char* GetError() { return m_error.c_str(); } + + int GetNrLights() { return m_lights.size(); } + const char* GetLightName (int lightnr); + + int SetPriority (int priority); + void SetScanRange (int width, int height); + + int AddPixel(int lightnr, int* rgb); + void AddPixel(int* rgb, int x, int y); + + int SendRGB(int sync, int* outputused); + int Ping(int* outputused, bool send); + + int GetNrOptions(); + const char* GetOptionDescription(int option); + int SetOption(int lightnr, const char* option); + int GetOption(int lightnr, const char* option, const char** output); + + private: + CTcpClientSocket m_socket; + std::string m_address; + int m_port; + std::string m_error; + CMessageQueue m_messagequeue; + int m_usectimeout; + + bool ReadDataToQueue(); + bool WriteDataToSocket(std::string strdata); + bool ParseWord(CMessage& message, std::string wordtocmp); + bool ParseLights(CMessage& message); + bool CheckLightExists(int lightnr, bool printerror = true); + + std::vector<CLight> m_lights; + + std::vector<std::string> m_options; + std::string m_lastoption; //place to store the last option retrieved by GetOption + }; +} +#endif //CBOBLIGHT diff --git a/lib/options.h b/lib/options.h new file mode 100644 index 0000000..05c3e82 --- /dev/null +++ b/lib/options.h @@ -0,0 +1,41 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +// name type min max default variable post-process +BOBLIGHT_OPTION(speed, float, 0.0, 100.0, 100.0, m_speed, m_speed = Clamp(m_speed, 0.0, 100.0); send = true;) +BOBLIGHT_OPTION(autospeed, float, 0, 100.0, 0.0, m_autospeed, m_autospeed = Max(m_autospeed, 0.0);) +BOBLIGHT_OPTION(interpolation, bool, false, true, false, m_interpolation, send = true;) +BOBLIGHT_OPTION(use, bool, false, true, true, m_use, send = true;) +BOBLIGHT_OPTION(saturation, float, 0.0, 20.0, 1.0, m_saturation, m_saturation = Max(m_saturation, 0.0);) +BOBLIGHT_OPTION(saturationmin, float, 0.0, 1.0, 0.0, m_satrange[0], m_satrange[0] = Clamp(m_satrange[0], 0.0, m_satrange[1]);) +BOBLIGHT_OPTION(saturationmax, float, 0.0, 1.0, 1.0, m_satrange[1], m_satrange[1] = Clamp(m_satrange[1], m_satrange[0], 1.0);) +BOBLIGHT_OPTION(value, float, 0.0, 20.0, 1.0, m_value, m_value = Max(m_value, 0.0);) +BOBLIGHT_OPTION(valuemin, float, 0.0, 1.0, 0.0, m_valuerange[0], m_valuerange[0] = Clamp(m_valuerange[0], 0.0, m_valuerange[1]);) +BOBLIGHT_OPTION(valuemax, float, 0.0, 1.0, 1.0, m_valuerange[1], m_valuerange[1] = Clamp(m_valuerange[1], m_valuerange[0], 1.0);) +BOBLIGHT_OPTION(threshold, int, 0, 255, 0, m_threshold, m_threshold = Clamp(m_threshold, 0, 255);) + +BOBLIGHT_OPTION(gamma, float, 0.0, 10.0, 1.0, m_gamma, m_gamma = Max(m_gamma, 0.0); \ + for (int i = 0; i < GAMMASIZE; i++) \ + m_gammacurve[i] = pow((float)i / ((float)GAMMASIZE - 1.0f), m_gamma) * (GAMMASIZE - 1.0f);) + +BOBLIGHT_OPTION(hscanstart, float, 0.0, 100.0, -1.0, m_hscan[0], m_hscan[0] = Clamp(m_hscan[0], 0.0, m_hscan[1]); SetScanRange(m_width, m_height);) +BOBLIGHT_OPTION(hscanend, float, 0.0, 100.0, -1.0, m_hscan[1], m_hscan[1] = Clamp(m_hscan[1], m_hscan[0], 100.0); SetScanRange(m_width, m_height);) +BOBLIGHT_OPTION(vscanstart, float, 0.0, 100.0, -1.0, m_vscan[0], m_vscan[0] = Clamp(m_vscan[0], 0.0, m_vscan[1]); SetScanRange(m_width, m_height);) +BOBLIGHT_OPTION(vscanend, float, 0.0, 100.0, -1.0, m_vscan[1], m_vscan[1] = Clamp(m_vscan[1], m_vscan[0], 100.0); SetScanRange(m_width, m_height);) + + diff --git a/softhdservice.h b/softhdservice.h new file mode 100644 index 0000000..3e98c7e --- /dev/null +++ b/softhdservice.h @@ -0,0 +1,38 @@ +/// +/// @file softhddev_service.h @brief software HD device service header file. +/// +/// Copyright (c) 2012 by durchflieger. All Rights Reserved. +/// +/// Contributor(s): +/// +/// License: AGPLv3 +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License. +/// +/// This program 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 Affero General Public License for more details. +/// +/// $Id: softhdservice.h,v 1.2 2012/11/13 08:58:11 wendel Exp $ +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define ATMO1_GRAB_SERVICE "SoftHDDevice-AtmoGrabService-v1.1" + +struct SoftHDDevice_AtmoGrabService_v1_1_t +{ + // [in/out] + + int width; + int height; + + // [out] + + int size; + void* img; +};
\ No newline at end of file diff --git a/vdrboblight.c b/vdrboblight.c new file mode 100644 index 0000000..20ae8a5 --- /dev/null +++ b/vdrboblight.c @@ -0,0 +1,412 @@ +/* + * vdrboblight.c + * + * Copyright (C) 2013 - Christian Völlinger + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include <vdr/plugin.h> + +#include "config.h" +#include "ambiservice.h" +#include "ambithread.h" + +//*************************************************************************** +// +//*************************************************************************** + +static const char *VERSION = "0.0.1"; +static const char *DESCRIPTION = "Boblight with data from softhddevice"; +static const char *MAINMENUENTRY = "Boblight"; + +//*************************************************************************** +// Setup +//*************************************************************************** + +class cAmbiSetup : public cMenuSetupPage, public cAmbiService +{ + public: + + cAmbiSetup(); + + protected: + + virtual void Setup(); + virtual eOSState ProcessKey(eKeys Key); + virtual void Store(); + + const char* cineBars[cbCount]; + const char* seduRGBOrders[6]; + int rgbOrderIndex; +}; + +//*************************************************************************** +// Plugin +//*************************************************************************** + +class cPluginBoblight : public cPlugin +{ + public: + + cPluginBoblight(void); + virtual ~cPluginBoblight(); + virtual const char* Version(void) { return VERSION; } + virtual const char* Description(void) { return DESCRIPTION; } + virtual const char* CommandLineHelp(void) { return 0; } + virtual bool ProcessArgs(int argc, char* argv[]); + virtual bool Initialize(void); + virtual bool Start(void); + virtual void Stop(void); + virtual void Housekeeping(void) { }; + virtual void MainThreadHook(void) { }; + virtual cString Active(void); + virtual time_t WakeupTime(void); + virtual const char* MainMenuEntry(void) { return cfg.showMainmenu ? MAINMENUENTRY : 0; } + virtual cOsdObject* MainMenuAction(void); + virtual cMenuSetupPage* SetupMenu(void) { return new cAmbiSetup; } + virtual bool SetupParse(const char* Name, const char* Value); + virtual bool Service(const char* Id, void* Data = NULL); + virtual const char** SVDRPHelpPages(void); + virtual cString SVDRPCommand(const char* Command, const char* Option, int &ReplyCode); + + int startAtmo(); + int stopAtmo(); + cAmbiThread* update; + + int isRunning() + { + if (!update) + return no; + + return update->isRunning(); + } +}; + +//*************************************************************************** +// Plugins Main Menu +//*************************************************************************** + +class cSeduPluginMenu : public cMenuSetupPage +{ + public: + + cSeduPluginMenu(const char* title, cPluginBoblight* aPlugin); + virtual ~cSeduPluginMenu() { }; + + virtual eOSState ProcessKey(eKeys key); + + protected: + + void Store() { } + cPluginBoblight* plugin; +}; + +cSeduPluginMenu::cSeduPluginMenu(const char* title, cPluginBoblight* aPlugin) +{ + SetTitle(title ? title : ""); + plugin = aPlugin; + + Clear(); + + cOsdMenu::Add(new cMenuEditStraItem(tr("View Mode"), + (int*)&cfg.viewMode, + (int)cAmbiService::vmCount, + cAmbiService::viewModes)); + + Add(new cMenuEditIntItem(tr("Fixed Color Red"), &cfg.fixedR, 0, 255)); + Add(new cMenuEditIntItem(tr("Fixed Color Green"), &cfg.fixedG, 0, 255)); + Add(new cMenuEditIntItem(tr("Fixed Color Blue"), &cfg.fixedB, 0, 255)); + + SetHelp(0, 0, 0, 0); + + Display(); +} + +//*************************************************************************** +// Process Key +//*************************************************************************** + +eOSState cSeduPluginMenu::ProcessKey(eKeys key) +{ + eOSState state = cOsdMenu::ProcessKey(key); + + if (key == kLeft || key == kRight) + { + if (cfg.viewMode == cAmbiService::vmDetached && plugin->isRunning()) + plugin->stopAtmo(); + else if (cfg.viewMode != cAmbiService::vmDetached && !plugin->isRunning()) + plugin->startAtmo(); + } + + if (state != osUnknown) + return state; + + if (key == kOk) + { + SetupStore("FixedColorRed", cfg.fixedR); + SetupStore("FixedColorGreen", cfg.fixedG); + SetupStore("FixedColorBlue", cfg.fixedB); + SetupStore("ViewMode", (int)cfg.viewMode); + + return osEnd; + } + return state; +} + +//*************************************************************************** +// Plugin +//*************************************************************************** + +cPluginBoblight::cPluginBoblight(void) +{ + update = 0; +} + +cPluginBoblight::~cPluginBoblight() +{ + stopAtmo(); +} + +bool cPluginBoblight::ProcessArgs(int argc, char* argv[]) +{ + return true; +} + +bool cPluginBoblight::Initialize(void) +{ + return true; +} + +bool cPluginBoblight::Start(void) +{ + startAtmo(); + + return true; +} + +int cPluginBoblight::startAtmo() +{ + if (update) + { + update->Stop(); + delete update; + } + + update = new cAmbiThread(); + update->Start(); + + return done; +} + +int cPluginBoblight::stopAtmo() +{ + if (update) + update->Stop(); + + delete update; + update = 0; + + return done; +} + +void cPluginBoblight::Stop(void) +{ + stopAtmo(); +} + +cString cPluginBoblight::Active(void) +{ + return 0; +} + +time_t cPluginBoblight::WakeupTime(void) +{ + return 0; +} + +cOsdObject* cPluginBoblight::MainMenuAction(void) +{ + return new cSeduPluginMenu(MAINMENUENTRY, this); +} + +bool cPluginBoblight::SetupParse(const char* Name, const char* Value) +{ + if (!strcasecmp(Name, "LogLevel")) cfg.loglevel = atoi(Value); + else if (!strcasecmp(Name, "ShowMainmenu")) cfg.showMainmenu = atoi(Value); + else if (!strcasecmp(Name, "ViewMode")) cfg.viewMode = (cAmbiService::ViewMode)atoi(Value); + + else if (!strcasecmp(Name, "DetectCineBars")) cfg.detectCineBars = (cAmbiService::Cinebars)atoi(Value); + + else if (!strcasecmp(Name, "Frequence")) cfg.frequence = atoi(Value); + else if (!strcasecmp(Name, "Threshold")) cfg.threshold = atoi(Value); + else if (!strcasecmp(Name, "Value")) cfg.value = atoi(Value); + else if (!strcasecmp(Name, "Saturation")) cfg.saturation = atoi(Value); + else if (!strcasecmp(Name, "Speed")) cfg.speed = atoi(Value); + else if (!strcasecmp(Name, "Autospeed")) cfg.autospeed = atoi(Value); + else if (!strcasecmp(Name, "Interpolation")) cfg.interpolation = atoi(Value); + else if (!strcasecmp(Name, "Priority")) cfg.priority = atoi(Value); + + + else if (!strcasecmp(Name, "FixedColorRed")) cfg.fixedR = atoi(Value); + else if (!strcasecmp(Name, "FixedColorGreen")) cfg.fixedG = atoi(Value); + else if (!strcasecmp(Name, "FixedColorBlue")) cfg.fixedB = atoi(Value); + + else + return false; + + return true; +} + +bool cPluginBoblight::Service(const char* Id, void* Data) +{ + return false; +} + +cString cPluginBoblight::SVDRPCommand(const char* Command, const char* Option, int &ReplyCode) +{ + if (!update) + return "Error: Plugin not initialized!"; + + if (!strcasecmp(Command, "MODE")) + { + if (Option && strcasecmp(Option, "atmo") == 0) + { + cfg.viewMode = cAmbiService::vmAtmo; + startAtmo(); + ReplyCode = 550; + return "atmo mode activated"; + } + else if (Option && strcasecmp(Option, "fixed") == 0) + { + cfg.viewMode = cAmbiService::vmFixedCol; + startAtmo(); + ReplyCode = 550; + return "fixed color activated"; + } + else if (Option && strcasecmp(Option, "black") == 0) + { + cfg.viewMode = cAmbiService::vmBlack; + startAtmo(); + + ReplyCode = 550; + return "stripes black"; + } + else if (Option && strcasecmp(Option, "detach") == 0) + { + cfg.viewMode = cAmbiService::vmDetached; + stopAtmo(); + + ReplyCode = 550; + return "stripes detached"; + } + else + { + ReplyCode = 901; + return "Error: Unexpected option"; + } + } + + return 0; +} + +const char** cPluginBoblight::SVDRPHelpPages(void) +{ + static const char* HelpPages[] = + { + "MODE <mode>\n" + " Set mode {atmo|fixed|black|detach}\n", + 0 + }; + + return HelpPages; +} + +//*************************************************************************** +// Class Setup Menu +//*************************************************************************** +//*************************************************************************** +// Object +//*************************************************************************** + +cAmbiSetup::cAmbiSetup() +{ + cineBars[0] = "Horizontal"; + cineBars[1] = "Vertical"; + cineBars[2] = "Both"; + + Setup(); +} + +//*************************************************************************** +// Setup +//*************************************************************************** + +void cAmbiSetup::Setup() +{ + Clear(); + + Add(new cMenuEditIntItem(tr("Log level"), &cfg.loglevel, 0, 3)); + Add(new cMenuEditBoolItem(tr("Show mainmenu"), &cfg.showMainmenu)); + + Add(new cMenuEditIntItem(tr("Updaterate [Hz]"), &cfg.frequence, 1, 100)); + + Add(new cMenuEditStraItem(tr("Detect cinema bars"), (int*)&cfg.detectCineBars, 3, cineBars)); + + Add(new cMenuEditIntItem(tr("Threshold (0-255)"), &cfg.threshold, 0, 255)); + Add(new cMenuEditIntItem(tr("Gamma (0-10.0)"), &cfg.gamma, 0, 100)); + Add(new cMenuEditIntItem(tr("Value (0-20.0)"), &cfg.value, 0, 200)); + Add(new cMenuEditIntItem(tr("Saturation (0-20.0)"), &cfg.saturation, 0, 200)); + Add(new cMenuEditIntItem(tr("Speed (0-100)"), &cfg.speed, 0, 100)); + Add(new cMenuEditIntItem(tr("Autospeed (0-100)"), &cfg.autospeed, 0, 100)); + Add(new cMenuEditBoolItem(tr("Interpolation"), &cfg.interpolation)); + Add(new cMenuEditIntItem(tr("Priority 0=Highest, 255=Lowest"), &cfg.priority, 0, 255)); +} + +eOSState cAmbiSetup::ProcessKey(eKeys key) +{ + eOSState state = cMenuSetupPage::ProcessKey(key); + + return state; +} + +void cAmbiSetup::Store() +{ + cfg.dirty = 1; + SetupStore("LogLevel", cfg.loglevel); + SetupStore("ShowMainmenu", cfg.showMainmenu); + SetupStore("ViewMode", (int)cfg.viewMode); + + SetupStore("DetectCineBars", cfg.detectCineBars); + + SetupStore("Updaterate", cfg.frequence); + SetupStore("Threshold", cfg.threshold); + SetupStore("Gamma", cfg.gamma); + SetupStore("Value", cfg.value); + SetupStore("Saturation", cfg.saturation); + SetupStore("Speed", cfg.speed); + SetupStore("Autospeed", cfg.autospeed); + SetupStore("Interpolation", cfg.interpolation); + SetupStore("Priority", cfg.priority); + + SetupStore("FixedColorRed", cfg.fixedR); + SetupStore("FixedColorGreen", cfg.fixedG); + SetupStore("FixedColorBlue", cfg.fixedB); +} + +//*************************************************************************** +// VDR Internal +//*************************************************************************** + +VDRPLUGINCREATOR(cPluginBoblight); |