diff options
| author | horchi <vdr@jwendel.de> | 2017-03-05 16:49:27 +0100 |
|---|---|---|
| committer | horchi <vdr@jwendel.de> | 2017-03-05 16:49:27 +0100 |
| commit | 6965ee5e2570436648ecd9b50197c80fd3c28565 (patch) | |
| tree | bdd78eac61983d68a173f0b473f030be2b0c2ff7 | |
| download | vdr-plugin-seduatmo-0.0.3.tar.gz vdr-plugin-seduatmo-0.0.3.tar.bz2 | |
init git0.0.3
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | COPYING | 340 | ||||
| -rw-r--r-- | HISTORY | 10 | ||||
| l--------- | Makefile | 1 | ||||
| -rw-r--r-- | Makefile.pre-1.7.35 | 111 | ||||
| -rw-r--r-- | Makefile.since-1.7.35 | 123 | ||||
| -rw-r--r-- | README | 59 | ||||
| -rw-r--r-- | common.c | 111 | ||||
| -rw-r--r-- | common.h | 54 | ||||
| -rw-r--r-- | config.c | 116 | ||||
| -rw-r--r-- | config.h | 83 | ||||
| -rw-r--r-- | ledsconf.c | 127 | ||||
| -rw-r--r-- | ledsconf.h | 59 | ||||
| -rw-r--r-- | main.cc | 52 | ||||
| -rw-r--r-- | patches/softhddev-0.5.2-seduatmo.patch | 58 | ||||
| -rw-r--r-- | po/de_DE.po | 77 | ||||
| -rwxr-xr-x | scripts/seduconf.pl | 77 | ||||
| -rw-r--r-- | seduatmo.c | 510 | ||||
| -rw-r--r-- | seduservice.c | 140 | ||||
| -rw-r--r-- | seduservice.h | 85 | ||||
| -rw-r--r-- | seduthread.c | 844 | ||||
| -rw-r--r-- | seduthread.h | 192 | ||||
| -rw-r--r-- | softhdservice.h | 39 |
23 files changed, 3274 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..929ca40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.dependencies +*.o +*.so +*~ +*.mo +*.pot @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. @@ -0,0 +1,10 @@ +VDR Plugin 'seduatmo' Revision History +-------------------------------------- + +2015-10-11: Version 0.0.3 + Fixed menu handling + +2012-11-26: Version 0.0.2 + +2012-11-07: Version 0.0.1 + - Initial revision. diff --git a/Makefile b/Makefile new file mode 120000 index 0000000..b3f546d --- /dev/null +++ b/Makefile @@ -0,0 +1 @@ +Makefile.since-1.7.35
\ No newline at end of file diff --git a/Makefile.pre-1.7.35 b/Makefile.pre-1.7.35 new file mode 100644 index 0000000..36a7232 --- /dev/null +++ b/Makefile.pre-1.7.35 @@ -0,0 +1,111 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id: Makefile,v 1.7 2012/11/28 06:29:42 wendel Exp $ + +PLUGIN = seduatmo + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The C++ compiler and options: + +CXX ?= g++ +CXXFLAGS ?= -g -O3 -Wall -Werror=overloaded-virtual -Wno-parentheses + +### The directory environment: + +VDRDIR ?= = /usr/include/vdr +LIBDIR ?= ../../lib +TMPDIR ?= /tmp + +### Make sure that necessary options are included: + +-include $(VDRDIR)/Make.global + +### Allow user defined options to overwrite defaults: + +-include $(VDRDIR)/Make.config + +### The version number of VDR's plugin API (taken from VDR's "config.h"): + +APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h) + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### Includes and Defines (add further entries here): + +INCLUDES += -I$(VDRDIR)/include + +DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +CXXFLAGS += -Wno-unused-result + +### The object files (add further files here): + +OBJS = $(PLUGIN).o seduthread.o common.o config.o ledsconf.o seduservice.o + +### The main target: + +all: libvdr-$(PLUGIN).so i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +LOCALEDIR = $(VDRDIR)/locale +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ $^ + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q $@ $< + @touch $@ + +$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + @mkdir -p $(dir $@) + cp $< $@ + +.PHONY: i18n +i18n: $(I18Nmsgs) $(I18Npot) + +### Targets: + +libvdr-$(PLUGIN).so: $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@ + @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION) + +dist: $(I18Npo) 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/Makefile.since-1.7.35 b/Makefile.since-1.7.35 new file mode 100644 index 0000000..49fe38d --- /dev/null +++ b/Makefile.since-1.7.35 @@ -0,0 +1,123 @@ +# +# Makefile for a Video Disk Recorder plugin +# + +PLUGIN = seduatmo + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | 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) -fPIC + +CXXFLAGS += -Wno-unused-result + +### The version number of VDR's plugin API: + +APIVERSION = $(call PKGCFG,apiversion) + +### Allow user defined options to overwrite defaults: + +-include $(PLGCFG) + +### 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): + +INCLUDES += + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o +OBJS += seduthread.o common.o config.o ledsconf.o seduservice.o + +### The main target: + +all: $(SOFILE) i18n + +### 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) + +### Internationalization (I18N): + +PODIR = po +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file)))) +I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^` + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $< + @touch $@ + +$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + install -D -m644 $< $@ + +.PHONY: i18n +i18n: $(I18Nmo) $(I18Npot) + +install-i18n: $(I18Nmsgs) + +### Targets: + +$(SOFILE): $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@ + +install-lib: $(SOFILE) + install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) + +install: install-lib install-i18n + +dist: $(I18Npo) clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) --exclude debian --exclude CVS --exclude .svn --exclude .hg --exclude .git $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ @@ -0,0 +1,59 @@ + +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Jörg Wendel <vdr@jwendel.de> + +Project's homepage: URL + + +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. +See the file COPYING for more information. + +Description: + +Make shure that vdr user has sufficiant priveleges to Access the USB serial port. +e.g. to ensure use an udev.rule like this: +KERNEL=="ttyUSB?", OWNER="vdr", ATTRS{product}=="SEDU Board USB", SYMLINK+="ttySEDU" + +Adjust the seduconf.pl cofig script to generate a suiteable seduatmo.conf according to your configuration and place it in plugin cond dir. + +Blacklevel = 5 -> brightness for blacklevel +DetectCineBars = 2 -> 0- horizontal; 1 - vertical; 2 - both +FixedColorBlue = 0 -> B level of fixek color (0-255) +FixedColorGreen = 101 -> G level of fixek color (0-255) +FixedColorRed = 111 -> R level of fixek color (0-255) +Frequence = 25 -> frequency +Gamma = 14 -> Gamma correction (divided by 10) +HorizontalDepht = 2 -> Number of PIX extend into screen on left/right, 0 for the most outer one only +VerticalDepht = 1 -> Number of PIX extend into screen at top/bot, 0 for the most outer one only +LevelBlue = 70 -> white calibration level blue(0-255) +LevelGreen = 100 -> white calibration level green(0-255) +LevelRed = 57 -> white calibration level red(0-255) +LogLevel = 0 -> log Level (0-2) +SeduMode = 0 -> Protocol: 0 – miniDMX (only A2/512Byte), 1 - tpm2 +SeduRgbOrder = BGR -> ;) +ShowMainmenu = 1 -> ;) +Threshold = 17 -> level for black level detection, dark led until all LED below this threshold +ViewMode = 0 -> 0 - atmo; 1 - fixed color; 2 - off + +Blacklevel = 5 -> Helligkeitslevel bei Schwarzem Bild +DetectCineBars = 2 -> 0- horizontal; 1 - vertical; 2 - both +FixedColorBlue = 0 -> B Wert für Fixed Color (0-255) +FixedColorGreen = 101 -> G Wert für Fixed Color (0-255) +FixedColorRed = 111 -> R Wert für Fixed Color (0-255) +Frequence = 25 -> refresh Frequenz +Gamma = 14 -> Gamma Korrektur (wird durch 10 geteilt) +HorizontalDepht = 2 -> Anzahl der Pixel die seitlich in das Bild hinein herangezogen werden, 0 für nur das äußere +VerticalDepth = 1 -> Anzahl der Pixel die oben und unten in das Bild hineinragen , 0 für nur das äußere +LevelBlue = 70 -> Weißabgleich B (0-255) +LevelGreen = 100 -> Weißabgleich G (0-255) +LevelRed = 57 -> Weißabgleich R (0-255) +LogLevel = 0 -> log Level (0-2) +SeduMode = 0 -> Protokoll: 0 – miniDMX (nur A2/512Byte), 1 - tpm2 +SeduRgbOrder = BGR -> ;) +ShowMainmenu = 1 -> ;) +Threshold = 17 -> Schwellwert für Schwarzerkennung, liegen alle drei Farben eines Pixel darunter bleibt die LED aus +ViewMode = 0 -> 0 - atmo; 1 - fixed color; 2 - off diff --git a/common.c b/common.c new file mode 100644 index 0000000..17b594b --- /dev/null +++ b/common.c @@ -0,0 +1,111 @@ +/* + * 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, "SEDUATMO: "); + 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, "SEDUATMO: "); + 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; +} + +//*************************************************************************** +// Misc. Functions +//*************************************************************************** + +int minMax(int x, int min, int max) +{ + if (x < min) + return min; + + if (max < x) + return max; + + return x; +} + +double min(double a, double b) +{ + return a < b ? a : b; +} + +double max(double a, double b) +{ + return a >= b ? a : b; +} + +int getrand(int min, int max) +{ + srand(time(0)); + return rand() % (max-min) + min; +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..a774793 --- /dev/null +++ b/common.h @@ -0,0 +1,54 @@ +/* + * 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 +}; + +//*************************************************************************** +// Misc .. +//*************************************************************************** + +int minMax(int x, int min, int max); +int getrand(int min, int max); +double min(double a, double b); +double max(double a, double b); + +//*************************************************************************** +// 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..fbb7918 --- /dev/null +++ b/config.c @@ -0,0 +1,116 @@ +/* + * seduthred.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: config.c,v 1.27 2012/11/28 06:29:24 wendel Exp $ + */ + +#include <string.h> + +#include "config.h" +#include "common.h" + +//*************************************************************************** +// Global Configuration +//*************************************************************************** + +cSeduConfig cfg; + +//*************************************************************************** +// cConfigData +//*************************************************************************** + +cSeduConfig::cSeduConfig() +{ + // to be configured + + frequence = 25; + threshold = 17; + average = 10; + adjRed = 57; + adjGreen = 100; + adjBlue = 70; + gamma = 14; + xDeep = 2; + yDeep = 1; + black = 0; + detectCineBars = cbBoth; + + seduMode = smMiniDMX; + strcpy(seduRGBOrder, "BGR"); + loglevel = 0; + + showMainmenu = yes; + viewMode = vmAtmo; + effectSpeed = 500; + + fixedR = 111; + fixedG = 101; + fixedB = 0; + + + // calculated + + leds = 0; + ledCount = 0; + grabWidth = na; + grabHeight = na; +} + +cSeduConfig::~cSeduConfig() +{ + if (leds) delete leds; +} + +//*************************************************************************** +// Create Leds from config +//*************************************************************************** + +cSeduConfig::cLed* cSeduConfig::createLeds(cLedConfs* conf) +{ + int seq = 0; + delete leds; + + grabWidth = 0; + grabHeight = 0; + + ledCount = conf->Count(); + leds = new cLed[ledCount]; + memset(leds, 0, ledCount*sizeof(cLed)); + + for (cLedConf* l = conf->First(); l; l = conf->Next(l)) + { + tell(1, "led%d (%d) %d/%d %d/%d", seq, l->Pos(), + l->X(), l->Y(), + l->ToX(), l->ToY()); + + if (l->isValid()) + { + // calc size of led matrix + + if (grabWidth < l->X()) + grabWidth = l->X(); + if (grabWidth < l->ToX()) + grabWidth = l->ToX(); + if (grabHeight < l->Y()) + grabHeight = l->Y(); + if (grabHeight < l->ToY()) + grabHeight = l->ToY(); + + leds[seq].lp = (LedPosition)l->Pos(); + leds[seq].x = l->X(); + leds[seq].y = l->Y(); + leds[seq].toX = l->ToX(); + leds[seq].toY = l->ToY(); + + seq++; + } + } + + ledCount = seq; + grabWidth++; + grabHeight++; + + return leds; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..cb52d6f --- /dev/null +++ b/config.h @@ -0,0 +1,83 @@ +/* + * config.h: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: config.h,v 1.28 2012/11/28 06:29:24 wendel Exp $ + */ + +#ifndef __SEDU_CONFIG_H +#define __SEDU_CONFIG_H + +#include "common.h" +#include "ledsconf.h" +#include "seduservice.h" + +//*************************************************************************** +// Configuration +//*************************************************************************** + +class cSeduConfig : public cSeduService +{ + public: + + cSeduConfig(); + ~cSeduConfig(); + + // geometry + + int grabWidth; + int grabHeight; + + // adjust + + int threshold; + int adjGreen; + int adjRed; + int adjBlue; + int frequence; + unsigned int average; + int gamma; + int xDeep; + int yDeep; + int black; + + // technical + + ViewMode viewMode; + int fixedR; + int fixedG; + int fixedB; + int effectSpeed; + + int showMainmenu; + char seduRGBOrder[4]; + SeduMode seduMode; + Cinebars detectCineBars; + + int loglevel; + + cLed* leds; + int ledCount; + + // functions + + cLed* createLeds(cLedConfs* conf); + void copyLeds(cSeduConfig* c) + { + ledCount = c->ledCount; + leds = new cLed[ledCount]; + memset(leds, 0, ledCount*sizeof(cLed)); + + for (int i = 0; i < ledCount; i++) + leds[i] = c->leds[i]; + } +}; + +//*************************************************************************** +// Global Configuration +//*************************************************************************** + +extern cSeduConfig cfg; + +#endif // __SEDU_CONFIG_H diff --git a/ledsconf.c b/ledsconf.c new file mode 100644 index 0000000..5cbd98a --- /dev/null +++ b/ledsconf.c @@ -0,0 +1,127 @@ +/* + * ledsconf.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: ledsconf.c,v 1.18 2012/11/20 19:04:09 wendel Exp $ + */ + +#include <ctype.h> + +#include "common.h" +#include "config.h" +#include "ledsconf.h" + +//*************************************************************************** +// cLedConf +//*************************************************************************** +//*************************************************************************** +// Object +//*************************************************************************** + +cLedConf::cLedConf() +{ + x = na; + toX = na; + y = na; + toY = na; + lp = na; +} + +//*************************************************************************** +// Parse like like "led 0-1 14-17" +//*************************************************************************** + +bool cLedConf::Parse(const char* s) +{ + const char* p = s; + + p = skipWs(p); + + // check keyword + + if (strncasecmp(p, "led ", 4) != 0) + return false; + + p += 4; + skipWs(p); + + // LED Position + + if (strncasecmp(p, "top ", 4) == 0) + lp = lpTop; + else if (strncasecmp(p, "left ", 5) == 0) + lp = lpLeft; + else if (strncasecmp(p, "bot ", 4) == 0) + lp = lpBottom; + else if (strncasecmp(p, "bottom ", 7) == 0) + lp = lpBottom; + else if (strncasecmp(p, "right ", 6) == 0) + lp = lpRight; + else + return error("Missing location {top,left,bot(tom),right}"); + + // skip to delemiter + + while (*p && *p != ' ' && *p != '\t') + p++; + + // check + + if (!*p) + return false; + + skipWs(p); + + // parse X + + if (!parseRange(p, x, toX)) + return false; + + // parse Y + + if (!parseRange(p, y, toY)) + return false; + + return true; +} + +//*************************************************************************** +// Parse Range like "12-26" +//*************************************************************************** + +bool cLedConf::parseRange(const char*& p, int& from, int& to) +{ + p = skipWs(p); + + if (!isdigit(*p)) + return false; + + from = to = strtol(p, (char**)&p, 0); + + p = skipWs(p); + + if (*p != '-') + return true; + + p++; + + if (!isdigit(*p)) + return false; + + to = strtol(p, (char**)&p, 0); + + return true; +} + +//*************************************************************************** +// Skip Whitespaces +//*************************************************************************** + +const char* cLedConf::skipWs(const char* p) +{ + while (*p && (*p == ' ' || *p == '\t')) + p++; + + return p; +} diff --git a/ledsconf.h b/ledsconf.h new file mode 100644 index 0000000..3e01144 --- /dev/null +++ b/ledsconf.h @@ -0,0 +1,59 @@ +/* + * ledsconf.h: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: ledsconf.h,v 1.9 2012/11/20 14:32:28 wendel Exp $ + */ + +#ifndef _LED_CONF_H_ +#define _LED_CONF_H_ + +#include <vdr/plugin.h> +#include <vdr/tools.h> + +#include "seduservice.h" + +//*************************************************************************** +// cLedConf +//*************************************************************************** + +class cLedConf : public cListObject, public cSeduService +{ + public: + + cLedConf(); + + bool Parse(const char* s); + + int X() { return x; } + int ToX() { return toX; } + int Y() { return y; } + int ToY() { return toY; } + int Pos() { return lp; } + int isValid() { return x > na && y > na && lp > na; } + + private: + + bool parseRange(const char*& s, int& from, int& to); + const char* skipWs(const char* p); + + int x; + int toX; + int y; + int toY; + int lp; +}; + +//*************************************************************************** +// cLedConfs +//*************************************************************************** + +class cLedConfs : public cConfig<cLedConf> +{ + +}; + +extern cLedConfs ledConfs; + +#endif // _LED_CONF_H_ @@ -0,0 +1,52 @@ + +#include <stdio.h> +#include <stdlib.h> + +int damping = 84; + +unsigned char _damping(unsigned char c, unsigned char l) +{ + int delta = ((c - l) / 100.0) * (double)damping; + + if (!delta && c < l) + delta--; + else if (!delta && c > l) + delta++; + + return l + delta; +} + +unsigned char ddamping(unsigned char c, unsigned char l) +{ + int delta; + double percent = 100 - (damping); + + delta = ((c - l) / 100.0) * percent; + + if (!delta && c < l) + delta--; + else if (!delta && c > l) + delta++; + + return l + delta; +} +int main(int argc, char** argv) +{ + damping = atoi(argv[2]); + int c = atoi(argv[1]); + int o = 100; + int cnt = 0; + + while (o != c) + { + int prev = o; + o = ddamping(c, o); + + printf("request of %d - set to %d, old was %d \n", c, o, prev); + cnt++; + } + + printf("%d steps\n", cnt); + + return 0; +} diff --git a/patches/softhddev-0.5.2-seduatmo.patch b/patches/softhddev-0.5.2-seduatmo.patch new file mode 100644 index 0000000..fb4532f --- /dev/null +++ b/patches/softhddev-0.5.2-seduatmo.patch @@ -0,0 +1,58 @@ +--- ../vdr-plugin-softhddevice-0.5.2.git.20121115.2130.plain//softhddevice.cpp 2012-11-15 22:28:40.000000000 +0100 ++++ softhddevice.cpp 2012-11-19 11:47:16.519507231 +0100 +@@ -2354,6 +2354,27 @@ + r->height = height; + return true; + } ++ ++ if (strcmp(id, ATMO1_GRAB_SERVICE) == 0) ++ { ++ SoftHDDevice_AtmoGrabService_v1_1_t* r; ++ ++ if (!data) ++ return true; ++ ++ if (SuspendMode != NOT_SUSPENDED) ++ return false; ++ ++ r = (SoftHDDevice_AtmoGrabService_v1_1_t*)data; ++ ++ r->img = VideoGrabService(&r->size, &r->width, &r->height); ++ ++ if (!r->img) ++ return false; ++ ++ return true; ++ } ++ + return false; + } + +--- ../vdr-plugin-softhddevice-0.5.2.git.20121115.2130.plain//softhddevice_service.h 2012-11-05 11:59:01.000000000 +0100 ++++ softhddevice_service.h 2012-11-19 11:48:18.791509431 +0100 +@@ -23,6 +23,7 @@ + #pragma once + + #define ATMO_GRAB_SERVICE "SoftHDDevice-AtmoGrabService-v1.0" ++#define ATMO1_GRAB_SERVICE "SoftHDDevice-AtmoGrabService-v1.1" + #define OSD_3DMODE_SERVICE "SoftHDDevice-Osd3DModeService-v1.0" + + enum +@@ -48,3 +49,17 @@ + { + int Mode; + } SoftHDDevice_Osd3DModeService_v1_0_t; ++ ++typedef struct ++{ ++ // rewuest/reply data ++ ++ int width; ++ int height; ++ ++ // reply data ++ ++ int size; ++ ++ void *img; ++} SoftHDDevice_AtmoGrabService_v1_1_t; diff --git a/po/de_DE.po b/po/de_DE.po new file mode 100644 index 0000000..494ae04 --- /dev/null +++ b/po/de_DE.po @@ -0,0 +1,77 @@ +# VDR plugin language source file. +# Copyright (C) 2012 ckone santos +# This file is distributed under the same license as the VDR package. +# Joerg Wendel +# +msgid "" +msgstr "" +"Project-Id-Version: vdr-seduatmo 0.0.2\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2012-11-29 12:31+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: ckone santos\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "View Mode" +msgstr "" + +msgid "Fixed Color Red" +msgstr "Feste Farbe Rot" + +msgid "Fixed Color Green" +msgstr "Feste Farbe Grün" + +msgid "Fixed Color Blue" +msgstr "Feste Farbe Blau" + +msgid "Effect Speed [ms]" +msgstr "" + +msgid "Log level" +msgstr "" + +msgid "Show mainmenu" +msgstr "Zeige Hauptmenü" + +msgid "Frequence [Hz]" +msgstr "Frequenz (Hz)" + +msgid "Detect cinema bars" +msgstr "Balkenerkennung" + +msgid "Threshold" +msgstr "Schwellwert" + +msgid "Gamma (10-30)" +msgstr "" + +msgid "Horizontal depth" +msgstr "Horizontale Tiefe" + +msgid "Vertical depth" +msgstr "Vertikale Tiefe" + +msgid "Smoothness" +msgstr "Laufruhe" + +msgid "Blacklevel" +msgstr "Scharzwert" + +msgid "Level red [%]" +msgstr "Weißabgleich rot (%)" + +msgid "Level green [%]" +msgstr "Weißabgleich grün (%)" + +msgid "Level blue [%]" +msgstr "Weißabgleich blau (%)" + +msgid "SEDU mode" +msgstr "" + +msgid "SEDU RGB order" +msgstr "SEDU RGB Reihenfolge" diff --git a/scripts/seduconf.pl b/scripts/seduconf.pl new file mode 100755 index 0000000..aed3367 --- /dev/null +++ b/scripts/seduconf.pl @@ -0,0 +1,77 @@ +#!/usr/bin/perl -w + +$top = 28; # Number of LEDs at the top +$bot = 28; # Number of LEDs at the bottom +$left = 16; # Number of LEDs on the left => might be higher than physically when $cor=1 +$right = 16; # Number of LEDs on the right => might be higher than physically when $cor=1 + +$horz = 3; # horizontal deep on left/right (grabbed Fields) +$vert = 2; # vertical deep at top/bottom (grabbed Fields) + +@fit = ('bot', 'right', 'top', 'left'); # pyhsical/technical LED setup + +$dir = 'r'; # forward or reverse (clock) direction (f/r) +$cor = 0; # have a single LED in each corner (0/1) +$shift = 0; # shift first LED to last position (0/1) + +############## Do not touch below here ############## + +$top = $top-1; +$bot = $bot-1; +$left = $left-1; +$right = $right-1; +$horz = $horz-1; +$vert = $vert-1; + +for ($t=0;$t<=$top;$t++) { + $value = "led top $t 0"; + push(@top, $value); +} + +for ($b=$bot;$b>=0;$b--) { + $vert1 = $right-$vert; + $value = "led bot $b $right"; + push(@bot, $value); +} + +for ($l=$left;$l>=0;$l--) { + if ( $cor==1 and ($l==0 or $l==$left-1)) { next; } + $value = "led left 0 $l"; + push(@left, $value); +} + +for ($r=0;$r<=$right;$r++) { + if ( $cor==1 and ($r==0 or $r==$right-1)) { next; } + $horz1 = $top-$horz; + $value = "led right $top $r"; + push(@right, $value); +} + +if ($dir eq 'r') { + @left = reverse(@left); + @bot = reverse(@bot); + @right = reverse(@right); + @top = reverse(@top); +} + + +open (CONF, ">seduatmo.conf") or die "Can't open CONF file\n"; + +$cnt = 1; +foreach $side(@fit) { + print CONF "# $side\n"; + if ($cnt==1 and $shift==1) { + $first = $$side[0]; + shift(@$side); + } + print CONF join("\n",@$side); + print CONF "\n\n"; + $cnt++ +} + +if ($shift==1) { + print CONF "# shift first LED to last position\n"; + print CONF $first, "\n"; +} + +close CONF; diff --git a/seduatmo.c b/seduatmo.c new file mode 100644 index 0000000..2764603 --- /dev/null +++ b/seduatmo.c @@ -0,0 +1,510 @@ +/* + * seduatmo.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: seduatmo.c,v 1.64 2012/11/28 06:29:24 wendel Exp $ + */ + +#include <vdr/plugin.h> + +#include "seduthread.h" +#include "config.h" +#include "ledsconf.h" + +//*************************************************************************** +// +//*************************************************************************** + +static const char *VERSION = "0.0.3"; +static const char *DESCRIPTION = "sedu ambi light control with data from softhddevice"; +static const char *MAINMENUENTRY = "Seduatmo"; + +//*************************************************************************** +// Setup +//*************************************************************************** + +class cSeduSetup : public cMenuSetupPage, public cSeduService +{ + public: + + cSeduSetup(); + + protected: + + virtual void Setup(); + virtual eOSState ProcessKey(eKeys Key); + virtual void Store(); + + const char* seduModes[smCount]; + const char* cineBars[cbCount]; + const char* seduRGBOrders[6]; + int rgbOrderIndex; + + cSeduConfig data; +}; + +//*************************************************************************** +// Plugin +//*************************************************************************** + +class cPluginSeduatmo : public cPlugin +{ + public: + + cPluginSeduatmo(void); + virtual ~cPluginSeduatmo(); + 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 cSeduSetup; } + 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(); + cSeduThread* update; + + int isRunning() + { + if (!update) + return no; + + return update->isRunning(); + } + + private: + + cLedConfs ledConfs; +}; + +//*************************************************************************** +// Plugins Main Menu +//*************************************************************************** + +class cSeduPluginMenu : public cMenuSetupPage +{ + public: + + cSeduPluginMenu(const char* title, cPluginSeduatmo* aPlugin); + virtual ~cSeduPluginMenu() { }; + + virtual eOSState ProcessKey(eKeys key); + + protected: + + void Store(); + cPluginSeduatmo* plugin; + int effectSpeed; +}; + +cSeduPluginMenu::cSeduPluginMenu(const char* title, cPluginSeduatmo* aPlugin) +{ + SetTitle(title ? title : ""); + plugin = aPlugin; + effectSpeed = cfg.effectSpeed; + + Clear(); + + cOsdMenu::Add(new cMenuEditStraItem(tr("View Mode"), + (int*)&cfg.viewMode, + (int)cSeduService::vmCount, + cSeduService::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)); + + Add(new cMenuEditIntItem(tr("Effect Speed [ms]"), &effectSpeed, 100, 5000)); + + 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 == cSeduService::vmDetached && plugin->isRunning()) + plugin->stopAtmo(); + else if (cfg.viewMode != cSeduService::vmDetached && !plugin->isRunning()) + plugin->startAtmo(); + + Display(); + } + + if (key == kOk) + { + cfg.effectSpeed = effectSpeed; + Store(); + + return osEnd; + } + + return state; +} + +void cSeduPluginMenu::Store() +{ + plugin->SetupStore("FixedColorRed", cfg.fixedR); + plugin->SetupStore("FixedColorGreen", cfg.fixedG); + plugin->SetupStore("FixedColorBlue", cfg.fixedB); + plugin->SetupStore("ViewMode", (int)cfg.viewMode); + plugin->SetupStore("EffectSpeed", cfg.effectSpeed); + + Setup.Save(); +} + +//*************************************************************************** +// Plugin +//*************************************************************************** + +cPluginSeduatmo::cPluginSeduatmo(void) +{ + update = 0; +} + +cPluginSeduatmo::~cPluginSeduatmo() +{ + stopAtmo(); +} + +bool cPluginSeduatmo::ProcessArgs(int argc, char* argv[]) +{ + return true; +} + +bool cPluginSeduatmo::Initialize(void) +{ + char* tmp; + + asprintf(&tmp, "%s/%s", cPlugin::ConfigDirectory("seduatmo"), "seduatmo.conf"); + + if (!ledConfs.Load(tmp, true)) + { + free(tmp); + return fail; + } + + free(tmp); + + cfg.createLeds(&ledConfs); + + return true; +} + +bool cPluginSeduatmo::Start(void) +{ + startAtmo(); + + return true; +} + +int cPluginSeduatmo::startAtmo() +{ + if (update) + { + update->Stop(); + delete update; + } + + update = new cSeduThread(); + + if (cfg.grabWidth <= 0 || cfg.grabHeight <= 0 || !cfg.ledCount) + tell(0, "Error: Invalid configuration in seduatmo.conf, aborting"); + else + update->Start(); + + return done; +} + +int cPluginSeduatmo::stopAtmo() +{ + if (update) + update->Stop(); + + delete update; + update = 0; + + return done; +} + +void cPluginSeduatmo::Stop(void) +{ + stopAtmo(); +} + +cString cPluginSeduatmo::Active(void) +{ + return 0; +} + +time_t cPluginSeduatmo::WakeupTime(void) +{ + return 0; +} + +cOsdObject* cPluginSeduatmo::MainMenuAction(void) +{ + return new cSeduPluginMenu(MAINMENUENTRY, this); +} + +bool cPluginSeduatmo::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 = (cSeduService::ViewMode)atoi(Value); + + else if (!strcasecmp(Name, "DetectCineBars")) cfg.detectCineBars = (cSeduService::Cinebars)atoi(Value); + + else if (!strcasecmp(Name, "Threshold")) cfg.threshold = atoi(Value); + else if (!strcasecmp(Name, "Gamma")) cfg.gamma = atoi(Value); + else if (!strcasecmp(Name, "Frequence")) cfg.frequence = atoi(Value); + else if (!strcasecmp(Name, "Blacklevel")) cfg.black = atoi(Value); + else if (!strcasecmp(Name, "Smoothness")) cfg.average = atoi(Value); + + else if (!strcasecmp(Name, "HorizontalDepth")) cfg.xDeep = atoi(Value); + else if (!strcasecmp(Name, "VerticalDepth")) cfg.yDeep = atoi(Value); + + else if (!strcasecmp(Name, "LevelRed")) cfg.adjRed = atoi(Value); + else if (!strcasecmp(Name, "LevelGreen")) cfg.adjGreen = atoi(Value); + else if (!strcasecmp(Name, "LevelBlue")) cfg.adjBlue = 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 if (!strcasecmp(Name, "EffectSpeed")) cfg.effectSpeed = atoi(Value); + + else if (!strcasecmp(Name, "SeduMode")) cfg.seduMode = (cSeduService::SeduMode)atoi(Value); + else if (!strcasecmp(Name, "SeduRGBOrder")) strcpy(cfg.seduRGBOrder, Value); + + else + return false; + + return true; +} + +bool cPluginSeduatmo::Service(const char* Id, void* Data) +{ + return false; +} + +cString cPluginSeduatmo::SVDRPCommand(const char* Command, const char* Option, int &ReplyCode) +{ + if (!strcasecmp(Command, "MODE")) + { + if (Option && strcasecmp(Option, "atmo") == 0) + { + cfg.viewMode = cSeduService::vmAtmo; + startAtmo(); + ReplyCode = 550; + return "atmo mode activated"; + } + else if (Option && strcasecmp(Option, "fixed") == 0) + { + cfg.viewMode = cSeduService::vmFixedCol; + startAtmo(); + ReplyCode = 550; + return "fixed color activated"; + } + else if (Option && strcasecmp(Option, "rainbow") == 0) + { + cfg.viewMode = cSeduService::vmRainbow; + startAtmo(); + ReplyCode = 550; + return "rainbow effect activated"; + } + else if (Option && strcasecmp(Option, "wheel") == 0) + { + cfg.viewMode = cSeduService::vmColorWheel; + startAtmo(); + ReplyCode = 550; + return "color wheel effect activated"; + } + else if (Option && strcasecmp(Option, "wheelstatic") == 0) + { + cfg.viewMode = cSeduService::vmColorWheelStatic; + startAtmo(); + ReplyCode = 550; + return "static color wheel activated"; + } + else if (Option && strcasecmp(Option, "black") == 0) + { + cfg.viewMode = cSeduService::vmBlack; + startAtmo(); + + ReplyCode = 550; + return "stripes black"; + } + else if (Option && strcasecmp(Option, "detach") == 0) + { + cfg.viewMode = cSeduService::vmDetached; + stopAtmo(); + + ReplyCode = 550; + return "stripes detached"; + } + else + { + ReplyCode = 901; + return "Error: Unexpected option"; + } + } + + return 0; +} + +const char** cPluginSeduatmo::SVDRPHelpPages(void) +{ + static const char* HelpPages[] = + { + "MODE <mode>\n" + " Set mode {atmo|fixed|rainbow|wheel|wheelstatic|black|detach}\n", + 0 + }; + + return HelpPages; +} + +//*************************************************************************** +// Class Setup Menu +//*************************************************************************** +//*************************************************************************** +// Object +//*************************************************************************** + +cSeduSetup::cSeduSetup() +{ + data = cfg; + data.copyLeds(&cfg); + + // sedu mode + + seduModes[0] = "miniDMX"; + seduModes[1] = "tpm2"; + + // rgb order + + seduRGBOrders[0] = "RGB"; + seduRGBOrders[1] = "RBG"; + seduRGBOrders[2] = "BGR"; + seduRGBOrders[3] = "BRG"; + seduRGBOrders[4] = "GBR"; + seduRGBOrders[5] = "GRB"; + + for (rgbOrderIndex = 0; rgbOrderIndex < 6; rgbOrderIndex++) + { + if (strcasecmp(seduRGBOrders[rgbOrderIndex], data.seduRGBOrder) == 0) + break; + } + + if (rgbOrderIndex >= 6) + rgbOrderIndex = 0; + + // Cinema Bars + + cineBars[0] = "Horizontal"; + cineBars[1] = "Vertical"; + cineBars[2] = "Both"; + + Setup(); +} + +//*************************************************************************** +// Setup +//*************************************************************************** + +void cSeduSetup::Setup() +{ + Clear(); + + Add(new cMenuEditIntItem(tr("Log level"), &data.loglevel, 0, 3)); + Add(new cMenuEditBoolItem(tr("Show mainmenu"), &data.showMainmenu)); + + Add(new cMenuEditIntItem(tr("Frequence [Hz]"), &data.frequence, 1, 100)); + + Add(new cMenuEditStraItem(tr("Detect cinema bars"), (int*)&data.detectCineBars, 3, cineBars)); + + Add(new cMenuEditIntItem(tr("Threshold"), &data.threshold, 0, 255)); + Add(new cMenuEditIntItem(tr("Gamma (10-30)"), &data.gamma, 10, 30)); + Add(new cMenuEditIntItem(tr("Horizontal depth"), &data.xDeep, 0, 5)); + Add(new cMenuEditIntItem(tr("Vertical depth"), &data.yDeep, 0, 5)); + Add(new cMenuEditIntItem(tr("Smoothness"), (int*)&data.average, 1, 100)); + Add(new cMenuEditIntItem(tr("Blacklevel"), &data.black, 0, 255)); + + Add(new cMenuEditIntItem(tr("Level red [%]"), &data.adjRed, 0, 100)); + Add(new cMenuEditIntItem(tr("Level green [%]"), &data.adjGreen, 0, 100)); + Add(new cMenuEditIntItem(tr("Level blue [%]"), &data.adjBlue, 0, 100)); + + Add(new cMenuEditStraItem(tr("SEDU mode"), (int*)&data.seduMode, 2, seduModes)); + Add(new cMenuEditStraItem(tr("SEDU RGB order"), &rgbOrderIndex, 6, seduRGBOrders)); +} + +eOSState cSeduSetup::ProcessKey(eKeys Key) +{ + eOSState state = cMenuSetupPage::ProcessKey(Key); + + // nothing yet .. + + return state; +} + +void cSeduSetup::Store() +{ + strcpy(data.seduRGBOrder, seduRGBOrders[rgbOrderIndex]); + + cfg = data; + cfg.copyLeds(&data); + + SetupStore("LogLevel", data.loglevel); + SetupStore("ShowMainmenu", data.showMainmenu); + SetupStore("ViewMode", (int)data.viewMode); + + SetupStore("DetectCineBars", data.detectCineBars); + + SetupStore("Frequence", data.frequence); + SetupStore("Threshold", data.threshold); + SetupStore("Gamma", data.gamma); + SetupStore("Blacklevel", data.black); + SetupStore("Smoothness", data.average); + + SetupStore("HorizontalDepth", data.xDeep); + SetupStore("VerticalDepth", data.yDeep); + + SetupStore("LevelRed", data.adjRed); + SetupStore("LevelGreen", data.adjGreen); + SetupStore("LevelBlue", data.adjBlue); + + SetupStore("FixedColorRed", data.fixedR); + SetupStore("FixedColorGreen", data.fixedG); + SetupStore("FixedColorBlue", data.fixedB); + SetupStore("EffectSpeed", data.effectSpeed); + + SetupStore("SeduMode", data.seduMode); + SetupStore("SeduRgbOrder", data.seduRGBOrder); +} + +//*************************************************************************** +// VDR Internal +//*************************************************************************** + +VDRPLUGINCREATOR(cPluginSeduatmo); diff --git a/seduservice.c b/seduservice.c new file mode 100644 index 0000000..1f241da --- /dev/null +++ b/seduservice.c @@ -0,0 +1,140 @@ +/* + * seduservice.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: seduservice.c,v 1.3 2012/11/22 18:02:59 wendel Exp $ + */ + +#include <math.h> + +#include "seduservice.h" +#include "common.h" + +//*************************************************************************** +// View Modes +//*************************************************************************** + +const char* cSeduService::viewModes[] = +{ + "atmo", + "fixed color", + "rainbow", + "moving color wheel", + "static color wheel", + "black", + "detached", + + 0 +}; + +const char* cSeduService::toName(ViewMode vm) +{ + return viewModes[vm]; +} + +//*************************************************************************** +// Color conversion functions +//*************************************************************************** + +void cSeduService::rgb2hsv(int r, int g, int b, double* h, double* s, double* v) +{ + double minC, maxC, delta, rc, gc, bc; + rc = (double)r / 255.0; + gc = (double)g / 255.0; + bc = (double)b / 255.0; + maxC = max(rc, max(gc, bc)); + minC = min(rc, min(gc, bc)); + delta = maxC - minC; + *v = maxC; + + if (maxC != 0) + *s = delta / maxC; + else + *s = 0; + + if (*s == 0) + { + *h = 0; + } + else + { + if (rc == maxC) + *h = (gc - bc) / delta; + else if (gc == maxC) + *h = 2 + (bc - rc) / delta; + else if (bc == maxC) + *h = 4 + (rc - gc) / delta; + + *h *= 60.0; + + if (*h < 0) + *h += 360.0; + } +} + +//*************************************************************************** +// +//*************************************************************************** + +Pixel cSeduService::hsv2rgb(int h, double s, double v) +{ + Pixel p; + + double rr = 0; + double gg = 0; + double bb = 0; + + int i = floor(h/60.0); + double f = h/60.0 - i; + double pv = v * (1 - s); + double qv = v * (1 - s * f); + double tv = v * (1 - s * (1-f)); + + switch (i) + { + case 0: // rojo dominante + rr = v; + gg = tv; + bb = pv; + break; + + case 1: // verde + rr = qv; + gg = v; + bb = pv; + break; + + case 2: + rr = pv; + gg = v; + bb = tv; + break; + + case 3: // azul + rr = pv; + gg = qv; + bb = v; + break; + + case 4: + rr = tv; + gg = pv; + bb = v; + break; + + case 5: // rojo + rr = v; + gg = pv; + bb = qv; + break; + } + + // set each component to a integer value between 0 and 255 + + p.r = minMax(255*rr, 0, 255); + p.g = minMax(255*gg, 0, 255); + p.b = minMax(255*bb, 0, 255); + + return p; +} diff --git a/seduservice.h b/seduservice.h new file mode 100644 index 0000000..7079041 --- /dev/null +++ b/seduservice.h @@ -0,0 +1,85 @@ +/* + * seduservice.h: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: seduservice.h,v 1.3 2012/11/22 18:02:59 wendel Exp $ + */ + +#ifndef __SEDU_SERVICE_H +#define __SEDU_SERVICE_H + +//*************************************************************************** +// Pixel - format as provided by softhddevice +//*************************************************************************** + +struct Pixel +{ + unsigned char b; + unsigned char g; + unsigned char r; + unsigned char a; +}; + +//*************************************************************************** +// Sedu Service +//*************************************************************************** + +class cSeduService +{ + public: + + enum Cinebars + { + cbHorizontal, + cbVertical, + cbBoth, + cbCount + }; + + enum SeduMode + { + smMiniDMX, + smTpm2, + smCount + }; + + enum ViewMode + { + vmAtmo, + vmFixedCol, + vmRainbow, + vmColorWheel, + vmColorWheelStatic, + vmBlack, + vmDetached, + vmCount + }; + + enum LedPosition + { + lpTop, + lpLeft, + lpBottom, + lpRight + }; + + struct cLed + { + int x; + int toX; + int y; + int toY; + LedPosition lp; + }; + + // static + + void rgb2hsv(int r, int g, int b, double* h, double* s, double* v); + Pixel hsv2rgb(int h, double s, double v); + + static const char* toName(ViewMode vm); + static const char* viewModes[]; +}; + +#endif // __SEDU_SERVICE_H diff --git a/seduthread.c b/seduthread.c new file mode 100644 index 0000000..ae9b1ec --- /dev/null +++ b/seduthread.c @@ -0,0 +1,844 @@ +/* + * seduthred.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: seduthread.c,v 1.148 2012/11/28 06:29:24 wendel Exp $ + */ + + +#include <regex.h> + +#include <vdr/plugin.h> + +#include "softhdservice.h" +#include "seduthread.h" +#include "config.h" + +//*************************************************************************** +// Class cSeduThread +//*************************************************************************** +//*************************************************************************** +// Object +//*************************************************************************** + +cSeduThread::cSeduThread() +{ + loopActive = false; + pixAverage = 0; + image = 0; + imageSize = 0; + imageWidth = 0; + imageHeight = 0; + cineBarsHor = 0; + cineBarsVer = 0; +} + +cSeduThread::~cSeduThread() +{ + sedu.close(); + delete[] pixAverage; +} + +//*************************************************************************** +// Stop Thread +//*************************************************************************** + +void cSeduThread::Stop() +{ + loopActive = false; + waitCondition.Broadcast(); // wakeup the thread + + Cancel(3); // wait up to 3 seconds for thread was stopping +} + +//*************************************************************************** +// Action +//*************************************************************************** + +void cSeduThread::Action() +{ + MsTime wait = 0; + cMutexLock lock(&mutex); + + tell(0, "atmo Thread started (pid=%d)", getpid()); + + loopActive = true; + pixAverage = new PixQueue[cfg.ledCount]; + + sedu.setMode(cfg.seduMode, cfg.ledCount); + + while (loopActive && Running()) + { + MsTime start = msNow(); + + // work ... + + if (cfg.viewMode == vmAtmo) + { + if (grabImage() == success) + { + detectCineBars(); + putData(); + + MsTime elapsed = msNow() - start; + wait = 1000 / cfg.frequence - elapsed; + tell(2, "sleeping %ldms (%d Hz)", wait, cfg.frequence); + } + else + { + if (sedu.isOpen()) + { + error("softhddevice grab failed"); + tell(0, "Closing sedu interface to enable others (XBMC/boblight/...) to connect"); + sedu.close(); + } + + wait = 10000; // retry softhd grab every 10 seconds + } + } + else + { + putData(); + + if (cfg.viewMode != vmRainbow && cfg.viewMode != vmColorWheel) + wait = 500; // less load on fixed color or black + else + wait = 100; // for Rainbow sleep always 100ms + } + + waitCondition.TimedWait(mutex, wait); // wait time in ms + } + + sedu.close(); + loopActive = false; + + delete[] pixAverage; + pixAverage = 0; + + tell(0, "atmo thread ended (pid=%d)", getpid()); +} + +//*************************************************************************** +// Grab Image +//*************************************************************************** + +int cSeduThread::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 = cfg.grabWidth; + req.height = cfg.grabHeight; + req.img = 0; + + if (!softHdPlugin->Service(ATMO1_GRAB_SERVICE, &req) || !req.img) + return fail; + + tell(2, "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 cSeduThread::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 cSeduThread::putData() +{ + Pixel pFixedCol = {0,0,0,0}; + + if (!sedu.isOpen()) + { + if (sedu.open() != success) + return fail; + } + + switch (cfg.viewMode) + { + case vmBlack: + case vmFixedCol: + { + pFixedCol.r = cfg.viewMode == vmFixedCol ? cfg.fixedR : 0; + pFixedCol.g = cfg.viewMode == vmFixedCol ? cfg.fixedG : 0; + pFixedCol.b = cfg.viewMode == vmFixedCol ? cfg.fixedB : 0; + + if (cfg.viewMode != vmBlack) + { + gammaAdj(&pFixedCol); + whiteAdj(&pFixedCol); + } + + break; + } + case vmRainbow: + { + pFixedCol = getRainbowColor(); + break; + } + + default: break; + } + + sedu.writeStartSeq(); + + // loop over all LEDs + + for (int led = 0; led < cfg.ledCount; led++) + { + Pixel pixel = {0,0,0,0}; + Pixel* p = &pixel; + + if (cfg.viewMode == vmAtmo) + { + getPixel(led, p); + pixAverage[led].push(p); + + pixAverage[led].getPixel(p); + + threshold(p); + gammaAdj(p); + whiteAdj(p); + } + else + if (cfg.viewMode == vmColorWheel) + { + pixel = getColorWheel(1, led); + p = &pixel; + } + else if (cfg.viewMode == vmColorWheelStatic) + { + pixel = getColorWheel(0, led); + p = &pixel; + } + else + { + p = &pFixedCol; + } + + sedu.writePix(p); + } + + sedu.writeEndSeq(); + sedu.read(); + + return success; +} + +//*************************************************************************** +// Get Pixel +//*************************************************************************** + +int cSeduThread::getPixel(int ledIdx, Pixel* pixel) +{ + cLed* led; + PixSum sum; + + // some checks ... + + if (ledIdx >= cfg.ledCount) + { + tell(0, "Invalid led index %d, ignoring", ledIdx); + return 0; + } + + // get led ... + + led = &cfg.leds[ledIdx]; + + // valid ? + + if (led->x < 0 || led->y < 0) + { + tell(0, "Invalid position for (%d/%d) led %d, ignoring", + led->x, led->y, ledIdx); + return 0; + } + + // calc average over pixels in 'deep' + + sum.clear(); + + switch (led->lp) + { + case lpLeft: + { + for (int x = led->x; x <= led->x + cfg.xDeep; x++) + sum.add(&image[led->y*imageWidth + x + cineBarsVer]); + + break; + } + case lpRight: + { + for (int x = led->x; x >= led->x - cfg.xDeep; x--) + sum.add(&image[led->y*imageWidth + x - cineBarsVer]); + + break; + } + case lpTop: + { + for (int y = led->y; y <= led->y + cfg.yDeep; y++) + sum.add(&image[(y+cineBarsHor)*imageWidth + led->x]); + + break; + } + + case lpBottom: + { + for (int y = led->y; y >= led->y - cfg.yDeep; y--) + sum.add(&image[(y-cineBarsHor)*imageWidth + led->x]); + + break; + } + } + + if (!sum.getCount()) + return error("Fatal missing range for led %d", ledIdx); + + sum.getAvg(pixel); + + return success; +} + +//*************************************************************************** +// Merge Pixel +// - merge pixel p2 onto p1 - result stored in p1 +//*************************************************************************** + +void cSeduThread::merge(Pixel* p1, Pixel* p2, int level) +{ + double factor = level / 100.0 / 2.0; + + if (p1 && p2) + { + p1->r = p2->r * factor + p1->r * (1.0-factor); + p1->g = p2->g * factor + p1->g * (1.0-factor); + p1->b = p2->b * factor + p1->b * (1.0-factor); + } +} + +//*************************************************************************** +// Threshold +//*************************************************************************** + +void cSeduThread::threshold(Pixel* p) +{ + if (p) + { + if (p->r < cfg.threshold && p->g < cfg.threshold && p->b < cfg.threshold) + memset(p, cfg.black, sizeof(Pixel)); + } +} + +//*************************************************************************** +// White Adjust +//*************************************************************************** + +void cSeduThread::whiteAdj(Pixel* p) +{ + if (p && !isBlack(p)) + { + p->r = (double)p->r * (0.01 * cfg.adjRed); + p->b = (double)p->b * (0.01 * cfg.adjBlue); + p->g = (double)p->g * (0.01 * cfg.adjGreen); + } +} + +//*************************************************************************** +// White Adjust +//*************************************************************************** + +void cSeduThread::gammaAdj(Pixel* p) +{ + if (p && !isBlack(p) && cfg.gamma > 10) + { + double g = cfg.gamma / 10.0; + + p->r = (unsigned char)(pow(p->r / 255.0, g) * 255.0); + p->g = (unsigned char)(pow(p->g / 255.0, g) * 255.0); + p->b = (unsigned char)(pow(p->b / 255.0, g) * 255.0); + } +} + +//*************************************************************************** +// Get Rainbow Color +//*************************************************************************** + +Pixel cSeduThread::getRainbowColor() +{ + static int rainbowColorTone = 0; + static int callCount = 0; + + Pixel p = hsv2rgb(rainbowColorTone, 1, 1); + + if (!(callCount++ % (cfg.effectSpeed / 100))) + { + if (++rainbowColorTone >= 360) + rainbowColorTone = 0; + } + + gammaAdj(&p); + whiteAdj(&p); + + return p; +} + +Pixel cSeduThread::getColorWheel(int moving, int led) +{ + static int degrees = 0; + static int callCount = 0; + int steps = 360 / cfg.ledCount; + int color = 0; + + if (moving && !(callCount++ % (cfg.effectSpeed / 100))) + { + // calculate spinng wheel with given effect speed + + if (led == 0) + degrees += steps; + + if (degrees >= 360) + degrees = 0; + } + + // calculate color degrees + + color = led * steps + degrees; + + if (color >= 360) + color -= 360; + + // convert color from HSV to RGB + + Pixel p = hsv2rgb(color, 1, 1); + + // create a single Pixel + + gammaAdj(&p); + whiteAdj(&p); + + return p; +} + +//*************************************************************************** +// Class cSeduLine +//*************************************************************************** +//*************************************************************************** +// Object +//*************************************************************************** + +cSeduLine::cSeduLine() +{ + dataBytesSend = 0; + fd = na; + bzero(&oldtio, sizeof(oldtio)); + deviceName = 0; + + setMode(smMiniDMX); +} + +//*************************************************************************** +// SEDU Mode +//*************************************************************************** + +void cSeduLine::setMode(SeduMode aMode, int channels) +{ + mode = aMode; + + switch (mode) + { + case smMiniDMX: + { + byteStart = 0x5A; + byteMode = 0xA2; + byteEnd = 0xA5; + + dataBytes = 512; + + break; + } + case smTpm2: + { + byteStart = 0xC9; + byteMode = 0xDA; + byteEnd = 0x36; + + dataBytes = channels*3; + + break; + } + } +} + +//*************************************************************************** +// Detect +//*************************************************************************** + +int cSeduLine::detect() +{ + const char* pattern = "module:ftdi_sio"; // move to config? + + FILE* fd; + regex_t reg; + char line[200]; + + free(deviceName); + deviceName = 0; + + if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB)) + { + tell(0, "Invalid regular expression '%s'for usb device", pattern); + regfree(®); + return fail; + } + + if (!(fd = fopen("/proc/tty/driver/usbserial", "r"))) + { + tell(0, "Could not open '/proc/tty/driver/usbserial' '%m'"); + + regfree(®); + return fail; + } + + while (fgets(line, sizeof(line), fd)) + { + char* p; + + if (!regexec(®, line, 0, 0, 0) && (p = index(line, ':'))) + { + *p = 0; + asprintf(&deviceName, "/dev/ttyUSB%s", line); + break; + } + } + + fclose(fd); + regfree(®); + + if (!deviceName) + { + tell(0, "Could not auto detect a usb device like '%s' in '/proc/tty/driver/usbserial'"); + return fail; + } + + return success; +} + +//*************************************************************************** +// Open/Close +//*************************************************************************** + +int cSeduLine::open() +{ + struct termios newtio; + + if (detect() != success) + { + free(deviceName); + deviceName = strdup("/dev/ttySEDU"); + tell(0, "Falling back to '%s'", deviceName); + } + + if (isOpen()) + close(); + + // open serial line with 8 data bits, no parity, 1 stop bit + + if ((fd = ::open(deviceName, O_RDWR | O_NOCTTY | O_NDELAY)) < 0) + { + fd = na; + tell(0, "Error: Opening '%s' failed", deviceName); + + return fail; + } + + tell(0, "Opening '%s' succeeded!", deviceName); + + // configure serial line + + tcgetattr(fd, &oldtio); + bzero(&newtio, sizeof(newtio)); + + /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. + CRTSCTS : output hardware flow control (only used if the cable has + all necessary lines. See sect. 7 of Serial-HOWTO) + CS8 : 8n1 (8bit,no parity,1 stopbit) + CLOCAL : local connection, no modem control + CREAD : enable receiving characters */ + + newtio.c_cflag = B500000 | CS8 | CLOCAL | CREAD; + newtio.c_iflag = IGNPAR; + newtio.c_oflag = 0; + newtio.c_lflag = 0; + + if (tcsetattr(fd, TCSANOW, &newtio) != 0) + tell(0, "tcsetattr failed!"); + + tcflush(fd, TCIFLUSH); + + return success; +} + +int cSeduLine::close() +{ + if (isOpen()) + { + tcsetattr(fd, TCSANOW, &oldtio); + ::close(fd); + fd = na; + } + + free(deviceName); + deviceName = 0; + + return success; +} + +//*************************************************************************** +// Read/Write +//*************************************************************************** + +int cSeduLine::read() +{ + fd_set readfs; + timeval tv; + unsigned char c; + MsTime start = msNow(); + + if (!isOpen()) + return fail; + + // check if something to read ... + + tv.tv_sec = 0; + tv.tv_usec = 100000; + + FD_ZERO(&readfs); + FD_SET(fd, &readfs); + select(fd+1, &readfs, 0, 0, &tv); + + if (FD_ISSET(fd, &readfs)) + { + tell(2, "Received (after %ldms): ", (msNow()-start)); + + while (::read(fd, &c, 1) > 0) + tell(2, "%02X ", c); + } + else + { + tell(3, ".. no data available"); + } + + return 0; +} + +int cSeduLine::write(unsigned char b) +{ + if (!isOpen()) + return 0; + + if (checkLine() != success) + return 0; + + tell(3, "send: 0x%02X", b); + + return ::write(fd, &b, 1); +} + +int cSeduLine::writeStartSeq() +{ + write(byteStart); + write(byteMode); + + if (mode == smTpm2) + { + write((dataBytes & 0xFF00) >> 8); + write(dataBytes & 0x00FF); + } + + dataBytesSend = 0; + + return success; +} + +int cSeduLine::writeEndSeq() +{ + while (dataBytesSend < dataBytes) + dataBytesSend += write(0); + + write(byteEnd); + + tell(2, "Wrote %d RGB Values", dataBytesSend); + + return success; +} + +//*************************************************************************** +// Write Pixel +//*************************************************************************** + +int cSeduLine::writePix(Pixel* p) +{ + writeColor(p, 0); + writeColor(p, 1); + writeColor(p, 2); + + return success; +} + +int cSeduLine::writeColor(Pixel* p, int index) +{ + switch (cfg.seduRGBOrder[index]) + { + case 'R': dataBytesSend += write(p ? p->r : 0); break; + case 'B': dataBytesSend += write(p ? p->b : 0); break; + case 'G': dataBytesSend += write(p ? p->g : 0); break; + } + + return success; +} + +//*************************************************************************** +// Check Line +//*************************************************************************** + +int cSeduLine::checkLine() +{ + fd_set port; + + if (!isOpen()) + return fail; + + // check if space to write ... + + FD_ZERO(&port); + FD_SET(fd, &port); + + if (select(fd+1, 0, &port, 0, 0) == -1) + { + tell(0, "Error: select() %m"); + return fail; + } + + return success; +} diff --git a/seduthread.h b/seduthread.h new file mode 100644 index 0000000..23688c4 --- /dev/null +++ b/seduthread.h @@ -0,0 +1,192 @@ +/* + * seduthread.h: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + * $Id: seduthread.h,v 1.64 2012/11/28 06:29:24 wendel Exp $ + */ + +#include <termios.h> +#include <queue> + +#include <vdr/thread.h> + +#include "common.h" +#include "config.h" + +class PixQueue +{ + public: + + PixQueue() { clear(); } + virtual ~PixQueue() { clear(); } + void clear() { while (!pQueue.empty()) pQueue.pop(); r=g=b=0; } + int getCount() { return pQueue.size(); } + + void push(Pixel* p) + { + pQueue.push(*p); + + r += p->r; + g += p->g; + b += p->b; + + // remove old entrys from queue and sum + + while (pQueue.size() > cfg.average) + { + r -= pQueue.front().r; + g -= pQueue.front().g; + b -= pQueue.front().b; + + pQueue.pop(); + } + } + + void getPixel(Pixel* p) + { + p->r = r / pQueue.size(); + p->g = g / pQueue.size(); + p->b = b / pQueue.size(); + } + + protected: + + std::queue <Pixel> pQueue; + unsigned int r; + unsigned int g; + unsigned int b; +}; + +class PixSum +{ + public: + + PixSum() { clear(); } + + void clear() { r=g=b=count=0; } + int getCount() { return count; } + + void add(Pixel* p) + { + r += p->r; + g += p->g; + b += p->b; + count++; + } + + void getAvg(Pixel* p) + { + p->r = r / count; + p->g = g / count; + p->b = b / count; + } + + protected: + + unsigned int r; + unsigned int g; + unsigned int b; + int count; +}; + +//*************************************************************************** +// cSeduLine - Serial Communication +//*************************************************************************** + +class cSeduLine : public cSeduService +{ + public: + + cSeduLine(); + ~cSeduLine() { close(); } + + int open(); + int close(); + int isOpen() { return fd != na; } + + int checkLine(); + int read(); + + int write(unsigned char b); + + int writeStartSeq(); + int writeEndSeq(); + int writePix(Pixel* p); + int writeColor(Pixel* p, int index); + + // set .. + + void setMode(SeduMode aMode, int channels = 0); + + private: + + int detect(); + + // data + + int dataBytesSend; + + int mode; + int dataBytes; + int byteMode; + int byteStart; + int byteEnd; + + char* deviceName; + int fd; + struct termios oldtio; +}; + +//*************************************************************************** +// SEDU Thread +//*************************************************************************** + +class cSeduThread : public cThread, public cSeduService +{ + public: + + cSeduThread(); + ~cSeduThread(); + + int isRunning() { return Running(); } + + // interface + + void Stop(); + + private: + + void Action(void); + + int grabImage(); + int detectCineBars(); + int putData(); + + void threshold(Pixel* p); + void whiteAdj(Pixel* p); + void gammaAdj(Pixel* p); + void merge(Pixel* p1, Pixel* p2, int level = 100); + + int getPixel(int ledIdx, Pixel* pixel); + int isBlack(Pixel* p) { return p->r < cfg.threshold && p->g < cfg.threshold && p->b < cfg.threshold; } + + // data + + cSeduLine sedu; + + cMutex mutex; + cCondVar waitCondition; + int loopActive; + + Pixel* image; + PixQueue* pixAverage; + int cineBarsHor; + int cineBarsVer; + int imageSize; + int imageWidth; + int imageHeight; + + Pixel getRainbowColor(); + Pixel getColorWheel(int moving = 0, int led = 0); +}; diff --git a/softhdservice.h b/softhdservice.h new file mode 100644 index 0000000..3438a23 --- /dev/null +++ b/softhdservice.h @@ -0,0 +1,39 @@ +/// +/// @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 +{ + // rewuest/reply data + + int width; + int height; + + // reply data + + int size; + + void* img; +}; |
