From 47e367a8524a09dbdce8016296a611674e536225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20V=C3=B6llinger?= Date: Mon, 2 Dec 2013 19:57:54 +0100 Subject: Initial commit --- .gitignore | 3 + Makefile | 129 +++++++++ Pixel.h | 34 +++ README.md | 20 ++ ambiservice.c | 39 +++ ambiservice.h | 50 ++++ ambithread.c | 311 +++++++++++++++++++++ ambithread.h | 68 +++++ boblightservice.c | 136 +++++++++ boblightservice.h | 49 ++++ common.c | 80 ++++++ common.h | 45 +++ config.c | 60 ++++ config.h | 71 +++++ lib/boblight-functions.h | 41 +++ lib/boblight.cpp | 120 ++++++++ lib/boblight.h | 103 +++++++ lib/boblight_client.cpp | 704 +++++++++++++++++++++++++++++++++++++++++++++++ lib/boblight_client.h | 115 ++++++++ lib/options.h | 41 +++ softhdservice.h | 38 +++ vdrboblight.c | 412 +++++++++++++++++++++++++++ 22 files changed, 2669 insertions(+) create mode 100644 Makefile create mode 100644 Pixel.h create mode 100644 ambiservice.c create mode 100644 ambiservice.h create mode 100644 ambithread.c create mode 100644 ambithread.h create mode 100644 boblightservice.c create mode 100644 boblightservice.h create mode 100644 common.c create mode 100644 common.h create mode 100644 config.c create mode 100644 config.h create mode 100644 lib/boblight-functions.h create mode 100644 lib/boblight.cpp create mode 100644 lib/boblight.h create mode 100644 lib/boblight_client.cpp create mode 100644 lib/boblight_client.h create mode 100644 lib/options.h create mode 100644 softhdservice.h create mode 100644 vdrboblight.c diff --git a/.gitignore b/.gitignore index 9fa3b1b..da1e3d2 100644 --- a/.gitignore +++ b/.gitignore @@ -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) diff --git a/Pixel.h b/Pixel.h new file mode 100644 index 0000000..9d9adf6 --- /dev/null +++ b/Pixel.h @@ -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 . + */ + +#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 diff --git a/README.md b/README.md index 6fed0ef..c70d00a 100644 --- a/README.md +++ b/README.md @@ -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 . + */ + +#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 . + */ + +#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 . + */ + +#include + +#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 . + */ + +#include + +#include + +#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 . + */ + +#include + +#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 . + */ + +#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 +#include +#include +#include + +#include + +#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 . + */ + +#include + +#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 . + */ + +#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 . + */ + +//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 . + */ + +#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(boblight); +} + +void boblight_destroy(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + delete boblight; +} + +int boblight_connect(void* vpboblight, const char* address, int port, int usectimeout) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->Connect(address, port, usectimeout); +} + +int boblight_setpriority(void* vpboblight, int priority) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->SetPriority(priority); +} + +const char* boblight_geterror(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->GetError(); +} + +int boblight_getnrlights(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->GetNrLights(); +} + +const char* boblight_getlightname(void* vpboblight, int lightnr) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->GetLightName(lightnr); +} + +int boblight_getnroptions(void* vpboblight) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->GetNrOptions(); +} + +const char* boblight_getoptiondescript(void* vpboblight, int option) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->GetOptionDescription(option); +} + +int boblight_setoption(void* vpboblight, int lightnr, const char* option) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->SetOption(lightnr, option); +} + +int boblight_getoption(void* vpboblight, int lightnr, const char* option, const char** output) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->GetOption(lightnr, option, output); +} + +void boblight_setscanrange(void* vpboblight, int width, int height) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + boblight->SetScanRange(width, height); +} + +int boblight_addpixel(void* vpboblight, int lightnr, int* rgb) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->AddPixel(lightnr, rgb); +} + +void boblight_addpixelxy(void* vpboblight, int x, int y, int* rgb) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + boblight->AddPixel(rgb, x, y); +} + +int boblight_sendrgb(void* vpboblight, int sync, int* outputused) +{ + CBoblight* boblight = reinterpret_cast(vpboblight); + return boblight->SendRGB(sync, outputused); +} + +int boblight_ping(void* vpboblight, int* outputused) +{ + CBoblight* boblight = reinterpret_cast(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 . + */ + +//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 + #include + + //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 + #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 . + */ + + +#include "util/inclstdint.h" + +#include +#include //debug +#include + +#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 . + */ + +#ifndef CBOBLIGHT +#define CBOBLIGHT + +#include +#include + +#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 m_lights; + + std::vector 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 . + */ + +// 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 . + */ + +#include + +#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 \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); -- cgit v1.2.3