summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--HISTORY6
-rw-r--r--Makefile116
-rw-r--r--README103
-rw-r--r--bitmap.c98
-rw-r--r--bitmap.h37
-rw-r--r--ffont.c222
-rw-r--r--ffont.h79
-rw-r--r--imon.c640
-rw-r--r--imon.h136
-rw-r--r--imonlcd.c224
-rw-r--r--po/de_DE.po52
-rw-r--r--setup.c208
-rw-r--r--setup.h56
-rw-r--r--status.c128
-rw-r--r--status.h38
-rw-r--r--watch.c684
-rw-r--r--watch.h128
18 files changed, 3295 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..f90922e
--- /dev/null
+++ b/COPYING
@@ -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.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..33d526e
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,6 @@
+VDR Plugin 'imonlcd' Revision History
+-------------------------------------
+
+2009-05-19: Version 0.0.1
+
+- Initial revision.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..45a7c35
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,116 @@
+#
+# Makefile for iMON LCD plugin to VDR (C++)
+#
+# (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+#
+# $Id$
+
+# 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.
+# IMPORTANT: the presence of this macro is important for the Make.config
+# file. So it must be defined, even if it is not used here!
+#
+PLUGIN = imonlcd
+
+### 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 ?= -fPIC -g -O2 -Wall -Woverloaded-virtual -Wno-parentheses
+
+### The directory environment:
+
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### 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)"'
+
+
+INCLUDES += $(shell freetype-config --cflags)
+LIBS += $(shell freetype-config --libs)
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o bitmap.o imon.o ffont.o setup.o status.o watch.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 --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) -shared $(OBJS) $(LIBS) -o $@
+ @cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
+
+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
diff --git a/README b/README
new file mode 100644
index 0000000..f092092
--- /dev/null
+++ b/README
@@ -0,0 +1,103 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by : Andreas Brachold <vdr07 AT deltab de>
+
+Project's homepage: http://projects.vdr-developer.org/wiki/plg-imonlcd
+
+
+See the file COPYING for license information.
+
+
+Description:
+------------
+imonlcd is a plugin for the Video Disc Recorder and shows information
+about the current state of VDR on iMON LCD.
+
+
+Install LIRC kernel module lirc_imon:
+-------------------------------------
+You need installed kernel module lirc_imon installed to use the iMon LCD.
+This module are provided by LIRC (which will also allow you to use the IR
+receiver that is built into the screen).
+
+Other software like LCDproc should not be used, it could locking the
+device access.
+
+Install LIRC
+A newer or current CVS version of LIRC is required for support of the iMON LCD.
+You need to have the CVS client installed and then you can issue the following
+commands:
+
+#> cvs -d:pserver:anonymous@lirc.cvs.sourceforge.net:/cvsroot/lirc login
+#> cvs -z8 -d:pserver:anonymous@lirc.cvs.sourceforge.net:/cvsroot/lirc co lirc
+#> cd lirc
+#> ./autogen.sh
+#> ./setup.sh
+
+If you have any errors at this point, make sure you've installed all the
+prerequisite build tools. At this you'll be at the "setup" menu for LIRC.
+You'll need to choose "Driver Configuration" then
+
+ "USB Devices" then "Soundgraph iMON IR/LCD".
+
+Choose OK, then "Save configuration & run configure" to run the configure script.
+Once that finishes, run the following commands to install the modules:
+
+#> make
+#> make install
+#> modprobe lirc_imon
+
+At this point, you've got LIRC installed, and you might like to take some time
+to set up your remote (if you've got one).
+That step is outside the scope of these instructions, so I'll just skip that
+and move on to install vdr-plugin-imonlcd now.
+
+
+Install vdr-plugin-imonlcd:
+---------------------------
+Unpack the vdr-plugin-imonlcd tarball to $VDRSOURCE/PLUGINS/src directory
+
+#> cd /usr/local/src/vdr/PLUGINS/src
+#> tar -xzvf vdr-imonlcd-0.0.1.tgz
+#> ln -s imonlcd-0.0.1 imon
+
+Compile the plugin (from VDR's source directory)
+
+#> cd /usr/local/src/vdr/PLUGINS/src
+#> make plugins
+#> make install
+
+Check follow requirements
+-------------------------
+* module lirc_imon is loaded
+* /dev/lcd0 still exits
+* /dev/lcd0 are writable
+
+* To determine need protocol to communicate with LCD, known values
+ 0038 - For LCD with ID 15c2:0038 SoundGraph Inc (default)
+ ffdc - For LCD with ID 15c2:ffdc SoundGraph Inc
+
+ #> lsusb | grep 15c2
+ Bus 002 Device 002: ID 15c2:0038 SoundGraph Inc.
+
+ or by udev
+ #> udevinfo -a -n /dev/lcd0 \
+ | grep -2 'ATTRS{idVendor}=="15c2"' \
+ | grep ATTRS{idProduct} | cut -d '=' -f 3
+ "0038"
+
+
+Start VDR with the plugin.
+---------------------------
+You have to specify the device and protocol of your display in the config file
+on the command line.
+Possible options are:
+ -d DEV, --device=DEV sets the lcd-device to other device than /dev/lcd0
+ -p MODE, --protocol=MODE sets the protocol of lcd-device
+ 0038 - For LCD with ID 15c2:0038 SoundGraph Inc (default)
+ ffdc - For LCD with ID 15c2:ffdc SoundGraph Inc
+
+ Examples:
+ vdr -P'imonlcd'
+ vdr -P'imonlcd -d /dev/lcd0 -p ffdc'
+
diff --git a/bitmap.c b/bitmap.c
new file mode 100644
index 0000000..b16ab9a
--- /dev/null
+++ b/bitmap.c
@@ -0,0 +1,98 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#include <vdr/tools.h>
+#include "bitmap.h"
+
+ciMonBitmap::ciMonBitmap(int w, int h) {
+ width = w;
+ height = h;
+
+ // lines are byte aligned
+ bytesPerLine = (width + 7) / 8;
+
+ bitmap = MALLOC(uchar, bytesPerLine * height);
+ clear();
+}
+
+ciMonBitmap::ciMonBitmap() {
+ height = 0;
+ width = 0;
+ bitmap = NULL;
+}
+
+ciMonBitmap::~ciMonBitmap() {
+
+ if(bitmap)
+ free(bitmap);
+ bitmap = NULL;
+}
+
+ciMonBitmap& ciMonBitmap::operator = (const ciMonBitmap& x) {
+
+ if(height != x.height
+ || width != x.width
+ || bitmap == NULL) {
+
+ if(bitmap)
+ free(bitmap);
+ bitmap = NULL;
+
+ height = x.height;
+ width = x.width;
+
+ bytesPerLine = (width + 7) / 8;
+
+ if(height && width)
+ bitmap = MALLOC(uchar, bytesPerLine * height);
+ }
+ if(x.bitmap)
+ memcpy(bitmap, x.bitmap, bytesPerLine * height);
+ return *this;
+}
+
+bool ciMonBitmap::operator == (const ciMonBitmap& x) const {
+
+ if(height != x.height
+ || width != x.width
+ || bitmap == NULL
+ || x.bitmap == NULL)
+ return false;
+ return ((memcmp(x.bitmap, bitmap, bytesPerLine * height)) == 0);
+}
+
+
+void ciMonBitmap::clear() {
+ if (bitmap)
+ memset(bitmap, 0x00, bytesPerLine * height);
+}
+
+bool ciMonBitmap::SetPixel(int x, int y)
+{
+ unsigned char c;
+ unsigned int n;
+
+ if (!bitmap)
+ return false;
+
+ if (x >= width || x < 0)
+ return false;
+ if (y >= height || y < 0)
+ return false;
+
+ n = x + ((y / 8) * width);
+ c = 0x80 >> (y % 8);
+
+ if(n >= (bytesPerLine * height))
+ return false;
+
+ bitmap[n] |= c;
+ return true;
+}
diff --git a/bitmap.h b/bitmap.h
new file mode 100644
index 0000000..a5e986c
--- /dev/null
+++ b/bitmap.h
@@ -0,0 +1,37 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#ifndef __IMON_BITMAP_H___
+#define __IMON_BITMAP_H___
+
+class ciMonBitmap {
+ int height;
+ int width;
+ unsigned int bytesPerLine;
+ uchar *bitmap;
+protected:
+ ciMonBitmap();
+public:
+ ciMonBitmap( int w, int h );
+
+ virtual ~ciMonBitmap();
+ ciMonBitmap& operator = (const ciMonBitmap& x);
+ bool operator == (const ciMonBitmap& x) const;
+
+ void clear();
+ int Height() const { return height; }
+ int Width() const { return width; }
+ bool SetPixel(int x, int y);
+
+ uchar * getBitmap() const { return bitmap; };
+};
+
+
+#endif
diff --git a/ffont.c b/ffont.c
new file mode 100644
index 0000000..01fc4fe
--- /dev/null
+++ b/ffont.c
@@ -0,0 +1,222 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ *- Glyph handling based on <vdr/font.c>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ */
+
+#include <vdr/tools.h>
+#include "ffont.h"
+
+// --- ciMonFont ---------------------------------------------------------
+
+#define KERNING_UNKNOWN (-10000)
+
+ciMonGlyph::ciMonGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData)
+{
+ charCode = CharCode;
+ advanceX = GlyphData->advance.x >> 6;
+ advanceY = GlyphData->advance.y >> 6;
+ left = GlyphData->bitmap_left;
+ top = GlyphData->bitmap_top;
+ width = GlyphData->bitmap.width;
+ rows = GlyphData->bitmap.rows;
+ pitch = GlyphData->bitmap.pitch;
+ bitmap = MALLOC(uchar, rows * pitch);
+ memcpy(bitmap, GlyphData->bitmap.buffer, rows * pitch);
+}
+
+ciMonGlyph::~ciMonGlyph()
+{
+ free(bitmap);
+}
+
+int ciMonGlyph::GeciMonKerningCache(uint PrevSym) const
+{
+ for (int i = kerningCache.Size(); --i > 0; ) {
+ if (kerningCache[i].prevSym == PrevSym)
+ return kerningCache[i].kerning;
+ }
+ return KERNING_UNKNOWN;
+}
+
+void ciMonGlyph::SeciMonKerningCache(uint PrevSym, int Kerning)
+{
+ kerningCache.Append(ciMonKerning(PrevSym, Kerning));
+}
+
+
+
+ciMonFont::ciMonFont(const char *Name, int CharHeight, int CharWidth)
+{
+ height = 0;
+ bottom = 0;
+ int error = FT_Init_FreeType(&library);
+ if (!error) {
+ error = FT_New_Face(library, Name, 0, &face);
+ if (!error) {
+ if (face->num_fixed_sizes && face->available_sizes) { // fixed font
+ // TODO what exactly does all this mean?
+ height = face->available_sizes->height;
+ for (uint sym ='A'; sym < 'z'; sym++) { // search for descender for fixed font FIXME
+ FT_UInt glyph_index = FT_Get_Char_Index(face, sym);
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (!error) {
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+ if (!error) {
+ if (face->glyph->bitmap.rows-face->glyph->bitmap_top > bottom)
+ bottom = face->glyph->bitmap.rows-face->glyph->bitmap_top;
+ }
+ else
+ esyslog("iMonLCD: FreeType: error %d in FT_Render_Glyph", error);
+ }
+ else
+ esyslog("iMonLCD: FreeType: error %d in FT_Load_Glyph", error);
+ }
+ }
+ else {
+ error = FT_Set_Char_Size(face, // handle to face object
+ CharWidth * 64, // CharWidth in 1/64th of points
+ CharHeight * 64, // CharHeight in 1/64th of points
+ 0, // horizontal device resolution
+ 0); // vertical device resolution
+ if (!error) {
+ height = ((face->size->metrics.ascender-face->size->metrics.descender) + 63) / 64;
+ bottom = abs((face->size->metrics.descender - 63) / 64);
+ }
+ else
+ esyslog("iMonLCD: FreeType: error %d during FT_Set_Char_Size (font = %s)\n", error, Name);
+ }
+ }
+ else
+ esyslog("iMonLCD: FreeType: load error %d (font = %s)", error, Name);
+ }
+ else
+ esyslog("iMonLCD: FreeType: initialization error %d (font = %s)", error, Name);
+}
+
+ciMonFont::~ciMonFont()
+{
+ FT_Done_Face(face);
+ FT_Done_FreeType(library);
+}
+
+int ciMonFont::Kerning(ciMonGlyph *Glyph, uint PrevSym) const
+{
+ int kerning = 0;
+ if (Glyph && PrevSym) {
+ kerning = Glyph->GeciMonKerningCache(PrevSym);
+ if (kerning == KERNING_UNKNOWN) {
+ FT_Vector delta;
+ FT_UInt glyph_index = FT_Get_Char_Index(face, Glyph->CharCode());
+ FT_UInt glyph_index_prev = FT_Get_Char_Index(face, PrevSym);
+ FT_Get_Kerning(face, glyph_index_prev, glyph_index, FT_KERNING_DEFAULT, &delta);
+ kerning = delta.x / 64;
+ Glyph->SeciMonKerningCache(PrevSym, kerning);
+ }
+ }
+ return kerning;
+}
+
+ciMonGlyph* ciMonFont::Glyph(uint CharCode) const
+{
+ // Non-breaking space:
+ if (CharCode == 0xA0)
+ CharCode = 0x20;
+
+ // Lookup in cache:
+ cList<ciMonGlyph> *glyphCache = &glyphCacheMonochrome;
+ for (ciMonGlyph *g = glyphCache->First(); g; g = glyphCache->Next(g)) {
+ if (g->CharCode() == CharCode)
+ return g;
+ }
+
+ FT_UInt glyph_index = FT_Get_Char_Index(face, CharCode);
+
+ // Load glyph image into the slot (erase previous one):
+ int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
+ esyslog("iMonLCD: FreeType: error during FT_Load_Glyph");
+ else {
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
+ if (error)
+ esyslog("iMonLCD: FreeType: error during FT_Render_Glyph %d, %d\n", CharCode, glyph_index);
+ else { //new bitmap
+ ciMonGlyph *Glyph = new ciMonGlyph(CharCode, face->glyph);
+ glyphCache->Add(Glyph);
+ return Glyph;
+ }
+ }
+#define UNKNOWN_GLYPH_INDICATOR '?'
+ if (CharCode != UNKNOWN_GLYPH_INDICATOR)
+ return Glyph(UNKNOWN_GLYPH_INDICATOR);
+ return NULL;
+}
+
+int ciMonFont::Width(uint c) const
+{
+ ciMonGlyph *g = Glyph(c);
+ return g ? g->AdvanceX() : 0;
+}
+
+int ciMonFont::Width(const char *s) const
+{
+ int w = 0;
+ if (s) {
+ uint prevSym = 0;
+ while (*s) {
+ int sl = Utf8CharLen(s);
+ uint sym = Utf8CharGet(s, sl);
+ s += sl;
+ ciMonGlyph *g = Glyph(sym);
+ if (g)
+ w += g->AdvanceX() + Kerning(g, prevSym);
+ prevSym = sym;
+ }
+ }
+ return w;
+}
+
+int ciMonFont::DrawText(ciMonBitmap *Bitmap, int x, int y, const char *s, int Width) const
+{
+ if (s && height) { // checking height to make sure we actually have a valid font
+ uint prevSym = 0;
+ while (*s) {
+ int sl = Utf8CharLen(s);
+ uint sym = Utf8CharGet(s, sl);
+ s += sl;
+ ciMonGlyph *g = Glyph(sym);
+ if (!g)
+ continue;
+ int kerning = Kerning(g, prevSym);
+ prevSym = sym;
+ uchar *buffer = g->Bitmap();
+ int symWidth = g->Width();
+ if (Width && x + symWidth + g->Left() + kerning - 1 > Width)
+ return 1; // we don't draw partial characters
+ if (x + symWidth + g->Left() + kerning > 0) {
+ for (int row = 0; row < g->Rows(); row++) {
+ for (int pitch = 0; pitch < g->Pitch(); pitch++) {
+ uchar bt = *(buffer + (row * g->Pitch() + pitch));
+ for (int col = 0; col < 8 && col + pitch * 8 <= symWidth; col++) {
+ if (bt & 0x80)
+ Bitmap->SetPixel(x + col + pitch * 8 + g->Left() + kerning,
+ y + row + (height - Bottom() - g->Top()));
+ bt <<= 1;
+ }
+ }
+ }
+ }
+ x += g->AdvanceX() + kerning;
+ if (x > Bitmap->Width() - 1)
+ return 1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
diff --git a/ffont.h b/ffont.h
new file mode 100644
index 0000000..003007d
--- /dev/null
+++ b/ffont.h
@@ -0,0 +1,79 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ *- Glyph handling based on <vdr/font.c>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#ifndef __IMON_FONT_H___
+#define __IMON_FONT_H___
+
+#include <vdr/font.h>
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "bitmap.h"
+
+struct ciMonKerning {
+ uint prevSym;
+ int kerning;
+ ciMonKerning(uint PrevSym, int Kerning = 0) { prevSym = PrevSym; kerning = Kerning; }
+ };
+
+class ciMonGlyph : public cListObject {
+private:
+ uint charCode;
+ uchar *bitmap;
+ int advanceX;
+ int advanceY;
+ int left; ///< The bitmap's left bearing expressed in integer pixels.
+ int top; ///< The bitmap's top bearing expressed in integer pixels.
+ int width; ///< The number of pixels per bitmap row.
+ int rows; ///< The number of bitmap rows.
+ int pitch; ///< The pitch's absolute value is the number of bytes taken by one bitmap row, including padding.
+ cVector<ciMonKerning> kerningCache;
+public:
+ ciMonGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData);
+ virtual ~ciMonGlyph();
+ uint CharCode(void) const { return charCode; }
+ uchar *Bitmap(void) const { return bitmap; }
+ int AdvanceX(void) const { return advanceX; }
+ int AdvanceY(void) const { return advanceY; }
+ int Left(void) const { return left; }
+ int Top(void) const { return top; }
+ int Width(void) const { return width; }
+ int Rows(void) const { return rows; }
+ int Pitch(void) const { return pitch; }
+ int GeciMonKerningCache(uint PrevSym) const;
+ void SeciMonKerningCache(uint PrevSym, int Kerning);
+ };
+
+
+class ciMonFont : public cFont {
+private:
+ int height;
+ int bottom;
+ FT_Library library; ///< Handle to library
+ FT_Face face; ///< Handle to face object
+ mutable cList<ciMonGlyph> glyphCacheMonochrome;
+ int Bottom(void) const { return bottom; }
+ int Kerning(ciMonGlyph *Glyph, uint PrevSym) const;
+ ciMonGlyph* Glyph(uint CharCode) const;
+ virtual void DrawText(cBitmap*, int, int, const char*, tColor, tColor, int) const {};
+public:
+ ciMonFont(const char *Name, int CharHeight, int CharWidth = 0);
+ virtual ~ciMonFont();
+ virtual int Width(uint c) const;
+ virtual int Width(const char *s) const;
+ virtual int Height(void) const { return height; }
+
+ int DrawText(ciMonBitmap *Bitmap, int x, int y, const char *s, int Width) const;
+};
+
+
+#endif
diff --git a/imon.c b/imon.c
new file mode 100644
index 0000000..147eef1
--- /dev/null
+++ b/imon.c
@@ -0,0 +1,640 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ *- Based on lcdproc Driver for SoundGraph iMON OEM LCD Modules
+ *
+ * Copyright (c) 2004, Venky Raju <dev (at) venky (dot) ws>
+ * 2007, Dean Harding <dean (at) codeka dotcom>
+ * 2007, Christian Leuschen <christian (dot) leuschen (at) gmx (dot) de>
+ * 2009, Jonathan Kyler <jkyler (at) users (dot) sourceforge (dot) net>
+ * 2009, Eric Pooch < epooch (at) cox (dot) net>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <stdint.h>
+
+#include <vdr/tools.h>
+
+#include "setup.h"
+#include "ffont.h"
+#include "imon.h"
+
+/*
+ * Just for convenience and to have the commands at one place.
+ */
+static const uint64_t CMD_SET_ICONS = (uint64_t) 0x0100000000000000LL;
+static const uint64_t CMD_SET_CONTRAST = (uint64_t) 0x0300000000000000LL;
+static const uint64_t CMD_DISPLAY = (uint64_t) 0x0000000000000000LL; // must be or'd with the applicable CMD_DISPLAY_BYTE
+static const uint64_t CMD_SHUTDOWN = (uint64_t) 0x0000000000000008LL; // must be or'd with the applicable CMD_DISPLAY_BYTE
+static const uint64_t CMD_DISPLAY_ON = (uint64_t) 0x0000000000000040LL; // must be or'd with the applicable CMD_DISPLAY_BYTE
+static const uint64_t CMD_CLEAR_ALARM = (uint64_t) 0x0000000000000000LL; // must be or'd with the applicable CMD_ALARM_BYTE
+static const uint64_t CMD_SET_LINES0 = (uint64_t) 0x1000000000000000LL;
+static const uint64_t CMD_SET_LINES1 = (uint64_t) 0x1100000000000000LL;
+static const uint64_t CMD_SET_LINES2 = (uint64_t) 0x1200000000000000LL;
+static const uint64_t CMD_INIT = (uint64_t) 0x0200000000000000LL; //not exactly sure what this does, but it's needed
+static const uint64_t CMD_LOW_CONTRAST = (uint64_t) (CMD_SET_CONTRAST + (uint64_t) 0x00FFFFFF00580A00LL);
+
+
+/* Allow for variations in Soundgraphs numerous protocols */
+/* 15c2:0038 SoundGraph iMON */
+static const uint64_t CMD_DISPLAY_BYTE_0038 = (uint64_t) 0x8800000000000000LL;
+static const uint64_t CMD_ALARM_BYTE_0038 = (uint64_t) 0x8a00000000000000LL;
+
+/* 15c2:ffdc SoundGraph iMON */
+static const uint64_t CMD_DISPLAY_BYTE_FFDC = (uint64_t) 0x5000000000000000LL;
+static const uint64_t CMD_ALARM_BYTE_FFDC = (uint64_t) 0x5100000000000000LL;
+
+/* Byte 6 */
+static const uint64_t ICON_DISK_OFF = (uint64_t) 0x7F7000FFFFFFFFFFLL;
+static const uint64_t ICON_DISK_ON = (uint64_t) 0x0080FF0000000000LL;
+
+static const uint64_t ICON_DISK_IN = (uint64_t) 0x0080000000000000LL;
+static const uint64_t ICON_CD_IN = (uint64_t) 0x00806B0000000000LL;
+static const uint64_t ICON_DVD_IN = (uint64_t) 0x0080550000000000LL;
+
+/* Byte 5 */
+static const uint64_t ICON_AUDIO_WMA2 = ((uint64_t) 1 << 39);
+static const uint64_t ICON_AUDIO_WAV = ((uint64_t) 1 << 38);
+static const uint64_t ICON_REP = ((uint64_t) 1 << 37);
+static const uint64_t ICON_SFL = ((uint64_t) 1 << 36);
+static const uint64_t ICON_ALARM = ((uint64_t) 1 << 35);
+static const uint64_t ICON_REC = ((uint64_t) 1 << 34);
+static const uint64_t ICON_VOL = ((uint64_t) 1 << 33);
+static const uint64_t ICON_TIME = ((uint64_t) 1 << 32);
+
+/* Byte 4 */
+static const uint64_t ICON_XVID = ((uint64_t) 1 << 31);
+static const uint64_t ICON_WMV = ((uint64_t) 1 << 30);
+static const uint64_t ICON_AUDIO_MPG = ((uint64_t) 1 << 29);
+static const uint64_t ICON_AUDIO_AC3 = ((uint64_t) 1 << 28);
+static const uint64_t ICON_AUDIO_DTS = ((uint64_t) 1 << 27);
+static const uint64_t ICON_AUDIO_WMA = ((uint64_t) 1 << 26);
+static const uint64_t ICON_AUDIO_MP3 = ((uint64_t) 1 << 25);
+static const uint64_t ICON_AUDIO_OGG = ((uint64_t) 1 << 24);
+
+/* Byte 3 */
+static const uint64_t ICON_SRC = ((uint64_t) 1 << 23);
+static const uint64_t ICON_FIT = ((uint64_t) 1 << 22);
+static const uint64_t ICON_TV_2 = ((uint64_t) 1 << 21);
+static const uint64_t ICON_HDTV = ((uint64_t) 1 << 20);
+static const uint64_t ICON_SCR1 = ((uint64_t) 1 << 19);
+static const uint64_t ICON_SCR2 = ((uint64_t) 1 << 18);
+static const uint64_t ICON_MPG = ((uint64_t) 1 << 17);
+static const uint64_t ICON_DIVX = ((uint64_t) 1 << 16);
+
+/* Byte 2 */
+static const uint64_t ICON_SPKR_FC = ((uint64_t) 1 << 15);
+static const uint64_t ICON_SPKR_FR = ((uint64_t) 1 << 14);
+static const uint64_t ICON_SPKR_SL = ((uint64_t) 1 << 13);
+static const uint64_t ICON_SPKR_LFE = ((uint64_t) 1 << 12);
+static const uint64_t ICON_SPKR_SR = ((uint64_t) 1 << 11);
+static const uint64_t ICON_SPKR_RL = ((uint64_t) 1 << 10);
+static const uint64_t ICON_SPKR_SPDIF = ((uint64_t) 1 << 9);
+static const uint64_t ICON_SPKR_RR = ((uint64_t) 1 << 8);
+
+/* Byte 1 */
+static const uint64_t ICON_MUSIC = ((uint64_t) 1 << 7);
+static const uint64_t ICON_MOVIE = ((uint64_t) 1 << 6);
+static const uint64_t ICON_PHOTO = ((uint64_t) 1 << 5);
+static const uint64_t ICON_CD_DVD = ((uint64_t) 1 << 4);
+static const uint64_t ICON_TV = ((uint64_t) 1 << 3);
+static const uint64_t ICON_WEBCAST = ((uint64_t) 1 << 2);
+static const uint64_t ICON_NEWS = ((uint64_t) 1 << 1);
+static const uint64_t ICON_SPKR_FL = ((uint64_t) 1 << 0);
+
+
+ciMonLCD::ciMonLCD()
+{
+ this->imon_fd = -1;
+ this->pFont = NULL;
+ this->last_cd_state = 0;
+}
+
+ciMonLCD::~ciMonLCD() {
+ this->close();
+
+ if(pFont) {
+ delete pFont;
+ pFont = NULL;
+ }
+ if(framebuf) {
+ delete framebuf;
+ framebuf = NULL;
+ }
+ if(backingstore) {
+ delete backingstore;
+ backingstore = NULL;
+ }
+
+}
+
+
+/**
+ * Initialize the driver.
+ * \retval 0 Success.
+ * \retval <0 Error.
+ */
+int ciMonLCD::open(const char* szDevice, eProtocol pro)
+{
+ if(!SetFont(theSetup.m_szFont)) {
+ return -1;
+ }
+
+ isyslog("iMonLCD: using Device %s, with 15c2:%s", szDevice,
+ (pro == ePROTOCOL_FFDC ? "ffdc":"0038"));
+
+ /* Open device for writing */
+ if ((this->imon_fd = ::open(szDevice, O_WRONLY)) < 0) {
+ esyslog("iMonLCD: ERROR opening %s (%s).", szDevice, strerror(errno));
+ esyslog("iMonLCD: Did you load the iMON kernel module?");
+ return -1;
+ }
+
+ /* Set commands based on protocol version */
+ if (pro == ePROTOCOL_FFDC) {
+ this->cmd_display = (CMD_DISPLAY | CMD_DISPLAY_BYTE_FFDC);
+ this->cmd_shutdown = (CMD_SHUTDOWN | CMD_DISPLAY_BYTE_FFDC);
+ this->cmd_display_on = (CMD_DISPLAY_ON | CMD_DISPLAY_BYTE_FFDC);
+ this->cmd_clear_alarm = (CMD_CLEAR_ALARM | CMD_ALARM_BYTE_FFDC);
+ } else //if (pro == PROTOCOL_0038)
+ {
+ this->cmd_display = (CMD_DISPLAY | CMD_DISPLAY_BYTE_0038);
+ this->cmd_shutdown = (CMD_SHUTDOWN | CMD_DISPLAY_BYTE_0038);
+ this->cmd_display_on = (CMD_DISPLAY_ON | CMD_DISPLAY_BYTE_0038);
+ this->cmd_clear_alarm = (CMD_CLEAR_ALARM | CMD_ALARM_BYTE_0038);
+ }
+
+ /* Make sure the frame buffer is there... */
+ this->framebuf = new ciMonBitmap(theSetup.m_nWidth,theSetup.m_nHeight);
+ if (this->framebuf == NULL) {
+ esyslog("iMonLCD: unable to allocate framebuffer");
+ return -1;
+ }
+
+ /* Make sure the framebuffer backing store is there... */
+ this->backingstore = new ciMonBitmap(theSetup.m_nWidth,theSetup.m_nHeight);
+ if (this->backingstore == NULL) {
+ esyslog("iMonLCD: unable to create framebuffer backing store");
+ return -1;
+ }
+ backingstore->SetPixel(0,0);//make dirty
+
+ SendCmd(this->cmd_clear_alarm);
+ SendCmd(this->cmd_display_on);
+ SendCmd(CMD_INIT); /* unknown, required init command */
+ SendCmd(CMD_SET_ICONS);
+ /* clear the progress-bars on top and bottom of the display */
+ SendCmd(CMD_SET_LINES0);
+ SendCmd(CMD_SET_LINES1);
+ SendCmd(CMD_SET_LINES2);
+
+ Contrast(theSetup.m_nContrast);
+
+ dsyslog("iMonLCD: init() done");
+
+ return 0;
+}
+
+/**
+ * Close the driver (do necessary clean-up).
+ */
+void ciMonLCD::close()
+{
+ time_t tt;
+ struct tm *t;
+ uint64_t data;
+
+ if (this->imon_fd >= 0) {
+ if (theSetup.m_nOnExit == eOnExitMode_SHOWMSG) {
+ /*
+ * "show message" means "do nothing" - the
+ * message is there already
+ */
+ isyslog("iMonLCD: closing, leaving \"last\" message.");
+ } else if (theSetup.m_nOnExit == eOnExitMode_BLANKSCREEN) {
+ /*
+ * turning backlight off (confirmed for my
+ * Silverstone LCD) (as "cybrmage" at
+ * mediaportal pointed out, his LCD is an
+ * Antec built-in one and turns completely
+ * off with this command)
+ */
+ isyslog("iMonLCD: closing, turning backlight off.");
+ SendCmd(this->cmd_shutdown);
+ SendCmd(this->cmd_clear_alarm);
+ } else {
+ /*
+ * by default, show the big clock. We need to
+ * set it to the current time, then it just
+ * keeps counting automatically.
+ */
+ isyslog("iMonLCD: closing, showing clock.");
+
+ tt = time(NULL);
+ t = localtime(&tt);
+
+ data = this->cmd_display;
+ data += ((uint64_t) t->tm_sec << 48);
+ data += ((uint64_t) t->tm_min << 40);
+ data += ((uint64_t) t->tm_hour << 32);
+ data += ((uint64_t) t->tm_mday << 24);
+ data += ((uint64_t) t->tm_mon << 16);
+ data += (((uint64_t) t->tm_year) << 8);
+ data += 0x80;
+ SendCmd(data);
+ SendCmd(this->cmd_clear_alarm);
+ }
+
+ ::close(this->imon_fd);
+ this->imon_fd = -1;
+ }
+}
+
+
+/**
+ * Clear the screen.
+ */
+void ciMonLCD::clear()
+{
+ if(framebuf)
+ framebuf->clear();
+}
+
+
+/**
+ * Flush data on screen to the LCD.
+ */
+bool ciMonLCD::flush()
+{
+ const int packetSize = 7;
+
+ unsigned char msb;
+ int offset = 0;
+
+ /*
+ * The display only provides for a complete screen refresh. If
+ * nothing has changed, don't refresh.
+ */
+ if ((*backingstore) == (*framebuf))
+ return true;
+
+ /* send buffer for one command or display data */
+ unsigned char tx_buf[8];
+
+ int err;
+ const uchar* fb = framebuf->getBitmap();
+ int bytes = framebuf->Width() / 8 * framebuf->Height();
+
+
+ for (msb = 0x20; msb < 0x3c; msb++) {
+ /* Copy the packet data from the frame buffer. */
+ int nCopy = packetSize;
+ if(bytes < nCopy) {
+ if(bytes > 0)
+ nCopy = bytes;
+ else
+ nCopy = 0;
+ }
+ if(nCopy!=packetSize)
+ memset(tx_buf, 0xFF , packetSize);
+ if(nCopy)
+ memcpy(tx_buf, fb + offset, nCopy);
+
+ /* Add the memory register byte to the packet data. */
+ tx_buf[packetSize] = msb;
+
+ //uint64_t *v = (uint64_t*)tx_buf;
+ //dsyslog("iMonLCD: writing : %08llx", *v);
+
+ err = write(this->imon_fd, tx_buf, sizeof(tx_buf));
+ cCondWait::SleepMs(2);
+
+ if (err <= 0)
+ esyslog("iMonLCD: error writing to file descriptor: %d (%s)", err, strerror(errno));
+
+ offset += packetSize;
+ bytes -= packetSize;
+ }
+
+ /* Update the backing store. */
+ (*backingstore) = (*framebuf);
+ return (err > 0);
+}
+
+
+/**
+ * Print a string on the screen at position (x,y).
+ * The upper-left corner is (1,1), the lower-right corner is (this->width, this->height).
+ * \param x Horizontal character position (column).
+ * \param y Vertical character position (row).
+ * \param string String that gets written.
+ */
+int ciMonLCD::DrawText(int x, int y, const char* string)
+{
+ if(pFont && framebuf)
+ return pFont->DrawText(framebuf, x, y, string, 1024);
+ return -1;
+}
+
+
+/**
+ * Sets the "icons state" for the device. We use this to control the icons
+ * around the outside the display.
+ *
+ * \param state This symbols to display.
+ */
+bool ciMonLCD::icons(int state)
+{
+ uint64_t icon = 0x0;
+
+ /* bit 0 : disc icon (0=off, 1='spin') */
+ if ((state & eIconDiscSpin) != 0) {
+ bool bSpinIcon = ((state & eIconDiscRunSpin) != 0);
+ bool bSpinBackward ((state & eIconDiscSpinBackward) != 0);
+
+ switch (bSpinIcon ? this->last_cd_state : 3) {
+ case 0:
+ this->last_cd_state = bSpinBackward ? 3 : 1;
+ if (theSetup.m_bDiscMode == 1)
+ /* all on except top & bottom */
+ icon |= ((uint64_t) (255 - 128 - 8) << 40);
+ else
+ /* top & bottom on */
+ icon |= ((uint64_t) (128 | 8) << 40);
+ break;
+ case 1:
+ this->last_cd_state = bSpinBackward ? 0 : 2;
+ if (theSetup.m_bDiscMode == 1)
+ /* all on except top-right & bottom-left */
+ icon |= ((uint64_t) (255 - 16 - 1) << 40);
+ else
+ /* top-right & bottom-left on */
+ icon |= ((uint64_t) (1 | 16) << 40);
+ break;
+ case 2:
+ this->last_cd_state = bSpinBackward ? 1 : 3;
+ if (theSetup.m_bDiscMode == 1)
+ /* all on except right & left */
+ icon |= ((uint64_t) (255 - 32 - 2) << 40);
+ else
+ /* right & left on */
+ icon |= ((uint64_t) (32 | 2) << 40);
+ break;
+ default:
+ this->last_cd_state = bSpinBackward ? 2 : 0;
+ if (theSetup.m_bDiscMode == 1)
+ /* all on except top-left & bottom-right */
+ icon |= ((uint64_t) (255 - 64 - 4) << 40);
+ else
+ /* top-left & bottom-right on */
+ icon |= ((uint64_t) (4 | 64) << 40);
+ break;
+ }
+ }
+
+ /*
+ * bit 1,2,3 : top row (0=none, 1=music, 2=movie, 3=photo, 4=CD/DVD,
+ * 5=TV, 6=Web, 7=News/Weather)
+ */
+ switch (state & eIconTopMask) {
+ case eIconTopMusic: icon |= ICON_MUSIC; break;
+ case eIconTopMovie: icon |= ICON_MOVIE; break;
+ case eIconTopPhoto: icon |= ICON_PHOTO; break;
+ case eIconTopDVD: icon |= ICON_CD_DVD; break;
+ case eIconTopTV: icon |= ICON_TV; break;
+ case eIconTopWeb: icon |= ICON_WEBCAST;break;
+ case eIconTopNews: icon |= ICON_NEWS; break;
+ default: break;
+ }
+
+ /* bit 4,5 : 'speaker' icons (0=off, 1=L+R, 2=5.1ch, 3=7.1ch) */
+ switch (state & eIconSpeakerMask) {
+ case eIconSpeakerL: icon |= ICON_SPKR_FL; break;
+ case eIconSpeakerR: icon |= ICON_SPKR_FR; break;
+ case eIconSpeakerLR: icon |= ICON_SPKR_FL | ICON_SPKR_FR; break;
+ case eIconSpeaker51:
+ icon |= ICON_SPKR_FL | ICON_SPKR_FC | ICON_SPKR_FR | ICON_SPKR_RL | ICON_SPKR_RR;
+ break;
+ case eIconSpeaker71:
+ icon |= ICON_SPKR_FL | ICON_SPKR_FC | ICON_SPKR_FR | ICON_SPKR_RL | ICON_SPKR_RR | ICON_SPKR_SL | ICON_SPKR_SR;
+ break;
+ case eIconSPDIF:
+ icon |= ICON_SPKR_SPDIF;
+ case eIconMute:
+ default: break;
+ }
+
+ icon |= ((state & eIconSRC) != 0) ? ICON_SRC : 0;
+ icon |= ((state & eIconFIT) != 0) ? ICON_FIT : 0;
+ icon |= ((state & eIconTV) != 0) ? ICON_TV_2 : 0;
+ icon |= ((state & eIconHDTV) != 0) ? ICON_HDTV : 0;
+ icon |= ((state & eIconSRC1) != 0) ? ICON_SCR1 : 0;
+ icon |= ((state & eIconSRC2) != 0) ? ICON_SCR2 : 0;
+
+ /* bottom-right icons (MP3,OGG,WMA,WAV) */
+ switch (state & eIconBR_Mask) {
+ case eIconBR_MP3: icon |= ICON_AUDIO_MP3; break;
+ case eIconBR_OGG: icon |= ICON_AUDIO_OGG; break;
+ case eIconBR_WMA: icon |= ICON_AUDIO_WMA2; break;
+ case eIconBR_WAV: icon |= ICON_AUDIO_WAV; break;
+ default:
+ break;
+ }
+
+ /* bottom-middle icons (MPG,AC3,DTS,WMA) */
+ switch (state & eIconBM_Mask) {
+ case eIconBM_MPG: icon |= ICON_AUDIO_MPG; break;
+ case eIconBM_AC3: icon |= ICON_AUDIO_AC3; break;
+ case eIconBM_DTS: icon |= ICON_AUDIO_DTS; break;
+ case eIconBM_WMA: icon |= ICON_AUDIO_WMA; break;
+ default: break;
+ }
+
+ /* bottom-left icons (MPG,DIVX,XVID,WMV) */
+ switch (state & eIconBL_Mask) {
+ case eIconBL_MPG: icon |= ICON_MPG; break;
+ case eIconBL_DIVX: icon |= ICON_DIVX; break;
+ case eIconBL_XVID: icon |= ICON_XVID; break;
+ case eIconBL_WMV: icon |= ICON_WMV; break;
+ default: break;
+ }
+
+ icon |= ((state & eIconVolume) != 0) ? ICON_VOL : 0;
+ icon |= ((state & eIconTIME) != 0) ? ICON_TIME : 0;
+ icon |= ((state & eIconALARM) != 0) ? ICON_ALARM : 0;
+ icon |= ((state & eIconRecording) != 0) ? ICON_REC : 0;
+ icon |= ((state & eIconRepeat) != 0) ? ICON_REP : 0;
+ icon |= ((state & eIconShuffle) != 0) ? ICON_SFL : 0;
+ icon |= ((state & eIconDiscEllispe) != 0) ? ICON_DISK_IN : 0;
+
+ return SendCmd(CMD_SET_ICONS | icon);
+}
+
+/**
+ * Sends a command to the screen. The kernel module expects data to be
+ * sent in 8 byte chunks, so for simplicity, we allow you to define
+ * the data as a 64-bit integer.
+ * However, we have to reverse the bytes to the order the display requires.
+ *
+ * \param value The data to send. Must be in a format that is recognized by
+ * the device. The kernel module doesn't actually do validation.
+ * \return <= 0 error writing to file descriptor.
+ */
+bool ciMonLCD::SendCmd(const uint64_t & cmdData) {
+ unsigned int i;
+ unsigned char buf[8];
+
+ //dsyslog("iMonLCD: writing : %08llx", cmdData);
+
+ /* Fill the send buffer. */
+ for (i = 0; i < sizeof(buf); i++) {
+ buf[i] = (unsigned char)((cmdData >> (i * 8)) & 0xFF);
+ }
+
+ int err;
+ err = write(this->imon_fd, buf, sizeof(buf));
+ cCondWait::SleepMs(2);
+
+ if (err <= 0)
+ esyslog("iMonLCD: error writing to file descriptor: %d (%s)", err, strerror(errno));
+
+ return (err > 0);
+}
+
+/**
+ * Sets the contrast of the display.
+ *
+ * \param promille The value the contrast is set to in promille (0 = lowest
+ * contrast; 1000 = highest contrast).
+ * \return 0 on failure, >0 on success.
+ */
+bool ciMonLCD::Contrast(int nContrast)
+{
+ if (nContrast < 0) {
+ nContrast = 0;
+ } else if (nContrast > 1000) {
+ nContrast = 1000;
+ }
+
+ /*
+ * Send contrast normalized to the hardware-understandable-value (0
+ * to 40). 0 is the lowest and 40 is the highest. The actual
+ * perceived contrast varies depending on the type of display.
+ */
+ return SendCmd(CMD_LOW_CONTRAST + (uint64_t) (nContrast / 25));
+}
+
+/**
+ * Sets the length of the built-in progress-bars and lines.
+ * Values from -32 to 32 are allowed. Positive values indicate that bars extend
+ * from left to right, negative values indicate that the run from right to left.
+ * Conventient method to simplify setting the bars with "human understandable
+ * values".
+ *
+ * \see setBuiltinProgressBars, lengthToPixels
+ *
+ * \param topLine Length of the top line (-32 to 32)
+ * \param botLine Length of the bottom line (-32 to 32)
+ * \param topProgress Length of the top progress bar (-32 to 32)
+ * \param botProgress Length of the bottom progress bar (-32 to 32)
+ */
+void ciMonLCD::setLineLength(int topLine, int botLine, int topProgress, int botProgress)
+{
+ setBuiltinProgressBars(lengthToPixels(topLine),
+ lengthToPixels(botLine),
+ lengthToPixels(topProgress),
+ lengthToPixels(botProgress)
+ );
+}
+
+
+/**
+ * Sets the length of the built-in progress-bars and lines.
+ * Values from -32 to 32 are allowed. Positive values indicate that bars extend
+ * from left to right, negative values indicate that the run from right to left.
+ *
+ * \param topLine Pitmap of the top line
+ * \param botLine Pitmap of the bottom line
+ * \param topProgress Pitmap of the top progress bar
+ * \param botProgress Pitmap of the bottom progress bar
+ */
+void ciMonLCD::setBuiltinProgressBars(int topLine, int botLine,
+ int topProgress, int botProgress)
+{
+ /* Least sig. bit is on the right */
+ uint64_t data;
+
+ /* send bytes 1-4 of topLine and 1-3 of topProgress */
+ data = (uint64_t) topLine & 0x00000000FFFFFFFFLL;
+ data |= (((uint64_t) topProgress) << 8 * 4) & 0x00FFFFFF00000000LL;
+ SendCmd(CMD_SET_LINES0 | data);
+
+ /* send byte 4 of topProgress, bytes 1-4 of botProgress and 1-2 of botLine */
+ data = (((uint64_t) topProgress) >> 8 * 3) & 0x00000000000000FFLL;
+ data |= (((uint64_t) botProgress) << 8) & 0x000000FFFFFFFF00LL;
+ data |= (((uint64_t) botLine) << 8 * 5) & 0x00FFFF0000000000LL;
+ SendCmd(CMD_SET_LINES1 | data);
+
+ /* send remaining bytes 3-4 of botLine */
+ data = ((uint64_t) botLine) >> 8 * 2;
+ SendCmd(CMD_SET_LINES2 | data);
+}
+
+/**
+ * Maps values to corresponding pixmaps for the built-in progress bars.
+ * Values from -32 to 32 are allowed. Positive values indicate that bars extend
+ * from left to right, negative values indicate that they run from right to left.
+ *
+ * \param length The length of the bar.
+ * \return The pixmap that represents the given length.
+ */
+int ciMonLCD::lengthToPixels(int length)
+{
+ int pixLen[] =
+ {
+ 0x00, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0,
+ 0x000000f8, 0x000000fc, 0x000000fe, 0x000000ff,
+ 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff,
+ 0x0000f8ff, 0x0000fcff, 0x0000feff, 0x0000ffff,
+ 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff,
+ 0x00f8ffff, 0x00fcffff, 0x00feffff, 0x00ffffff,
+ 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff,
+ 0xf8ffffff, 0xfcffffff, 0xfeffffff, 0xffffffff
+ };
+
+ if (abs(length) > 32)
+ return (0);
+
+ if (length >= 0)
+ return pixLen[length];
+ else
+ return (pixLen[32 + length] ^ 0xffffffff);
+}
+
+bool ciMonLCD::SetFont(const char *szFont) {
+
+ ciMonFont* tmpFont = NULL;
+
+ cString sFileName = cFont::GetFontFileName(szFont);
+ if(!isempty(sFileName)) {
+ tmpFont = new ciMonFont(sFileName,12,11);
+ } else {
+ esyslog("iMonLCD: unable to find file for font '%s'",szFont);
+ }
+ if(tmpFont) {
+ if(pFont) {
+ delete pFont;
+ }
+ pFont = tmpFont;
+ return true;
+ }
+ return false;
+}
diff --git a/imon.h b/imon.h
new file mode 100644
index 0000000..a28d35e
--- /dev/null
+++ b/imon.h
@@ -0,0 +1,136 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#ifndef __IMON_LCD_H_
+#define __IMON_LCD_H_
+
+#include "bitmap.h"
+
+enum eProtocol {
+ ePROTOCOL_FFDC = 0, /**< protocol ID for 15c2:ffdc device */
+ ePROTOCOL_0038 = 1 /**< protocol ID for 15c2:0038 device */
+};
+
+enum eOnExitMode {
+ eOnExitMode_SHOWMSG = 0, /**< Do nothing - just leave the "last" message there */
+ eOnExitMode_SHOWCLOCK = 1, /**< Show the big clock */
+ eOnExitMode_BLANKSCREEN = 2 /**< Blank the device completely */
+};
+
+enum eIcons {
+ eIconOff = 0,
+ eIconDiscSpin = 1 << 0,
+
+ eIconTopMusic = 1 << 1,
+ eIconTopMovie = 2 << 1,
+ eIconTopPhoto = 3 << 1,
+ eIconTopDVD = 4 << 1,
+ eIconTopTV = 5 << 1,
+ eIconTopWeb = 6 << 1,
+ eIconTopNews = 7 << 1,
+ eIconTopMask = (eIconTopMusic|eIconTopMovie|eIconTopPhoto|eIconTopDVD|eIconTopTV|eIconTopWeb|eIconTopNews),
+
+ eIconSpeakerL = 1 << 4,
+ eIconSpeakerR = 2 << 4,
+ eIconSpeakerLR = (eIconSpeakerL|eIconSpeakerR),
+ eIconSpeaker51 = 4 << 4,
+ eIconSpeaker71 = 5 << 4,
+ eIconSPDIF = 6 << 4,
+ eIconMute = 7 << 4,
+ eIconSpeakerMask = (eIconSpeakerLR|eIconSpeaker51|eIconSpeaker71|eIconSPDIF|eIconMute),
+
+ eIconSRC = 1 << 7,
+ eIconFIT = 1 << 8,
+ eIconTV = 1 << 9,
+ eIconHDTV = 1 << 10,
+ eIconSRC1 = 1 << 11,
+ eIconSRC2 = 1 << 12,
+
+ eIconBR_MP3 = 1 << 13,
+ eIconBR_OGG = 2 << 13,
+ eIconBR_WMA = 3 << 13,
+ eIconBR_WAV = 4 << 13,
+ eIconBR_Mask = (eIconBR_MP3|eIconBR_OGG|eIconBR_WMA|eIconBR_WAV),
+
+ eIconBM_MPG = 1 << 16,
+ eIconBM_AC3 = 2 << 16,
+ eIconBM_DTS = 3 << 16,
+ eIconBM_WMA = 4 << 16,
+ eIconBM_Mask = (eIconBM_MPG|eIconBM_AC3|eIconBM_DTS|eIconBM_WMA),
+
+ eIconBL_MPG = 1 << 19,
+ eIconBL_DIVX = 2 << 19,
+ eIconBL_XVID = 3 << 19,
+ eIconBL_WMV = 4 << 19,
+ eIconBL_Mask = (eIconBL_MPG|eIconBL_DIVX|eIconBL_XVID|eIconBL_WMV),
+
+ eIconVolume = 1 << 22,
+ eIconTIME = 1 << 23,
+ eIconALARM = 1 << 24,
+
+ eIconRecording = 1 << 25,
+
+ eIconRepeat = 1 << 26,
+ eIconShuffle = 1 << 27,
+
+ eIconDiscEllispe = 1 << 28,
+
+ eIconDiscRunSpin = 1 << 29,
+ eIconDiscSpinBackward = 1 << 30
+};
+
+class ciMonFont;
+class ciMonLCD {
+
+ int imon_fd;
+
+ ciMonFont* pFont;
+ /* framebuffer and backingstore for current contents */
+ ciMonBitmap* framebuf;
+ ciMonBitmap* backingstore;
+
+ /* store commands appropriate for the version of the iMON LCD */
+ uint64_t cmd_display;
+ uint64_t cmd_shutdown;
+ uint64_t cmd_display_on;
+ uint64_t cmd_clear_alarm;
+
+ /*
+ * record the last "state" of the CD icon so that we can "animate"
+ * it.
+ */
+ int last_cd_state;
+
+protected:
+
+ void setLineLength(int topLine, int botLine, int topProgress, int botProgress);
+ void setBuiltinProgressBars(int topLine, int botLine, int topProgress, int botProgress);
+ int lengthToPixels(int length);
+
+ bool SendCmd(const uint64_t & cmdData);
+ bool Contrast(int nContrast);
+public:
+ ciMonLCD();
+ virtual ~ciMonLCD();
+
+ virtual int open(const char* szDevice, eProtocol pro);
+ virtual void close ();
+
+
+ void clear ();
+ int DrawText(int x, int y, const char* string);
+ bool flush ();
+
+ bool icons(int state);
+ virtual bool SetFont(const char *szFont);
+};
+#endif
+
+
diff --git a/imonlcd.c b/imonlcd.c
new file mode 100644
index 0000000..0e60cd1
--- /dev/null
+++ b/imonlcd.c
@@ -0,0 +1,224 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#include <vdr/plugin.h>
+#include <getopt.h>
+#include <string.h>
+
+#include "imon.h"
+#include "watch.h"
+#include "status.h"
+#include "setup.h"
+
+static const char *VERSION = "0.0.1";
+
+static const char *DEFAULT_LCDDEVICE = "/dev/lcd0";
+
+class cPluginImonlcd : public cPlugin {
+private:
+ ciMonStatusMonitor *statusMonitor;
+ char* m_szDevice;
+ ciMonWatch m_dev;
+ eProtocol m_Protocol;
+
+public:
+ cPluginImonlcd(void);
+ virtual ~cPluginImonlcd();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return tr("Control a iMON LCD"); }
+ virtual const char *CommandLineHelp(void);
+ 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 NULL; }
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ 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);
+ };
+
+cPluginImonlcd::cPluginImonlcd(void)
+: m_Protocol(ePROTOCOL_0038)
+{
+ statusMonitor = NULL;
+ m_szDevice = NULL;
+}
+
+cPluginImonlcd::~cPluginImonlcd()
+{
+ //Cleanup if'nt throw housekeeping
+ if(statusMonitor) {
+ delete statusMonitor;
+ statusMonitor = NULL;
+ }
+
+ if(m_szDevice) {
+ free(m_szDevice);
+ m_szDevice = NULL;
+ }
+}
+
+const char *cPluginImonlcd::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return
+" -d DEV, --device=DEV sets the lcd-device to other device than /dev/lcd0\n"
+" -p MODE, --protocol=MODE sets the protocol of lcd-device\n"
+" '0038' For LCD with ID 15c2:0038 SoundGraph Inc (default)\n"
+" 'ffdc' For LCD with ID 15c2:ffdc SoundGraph Inc\n";
+
+}
+
+bool cPluginImonlcd::ProcessArgs(int argc, char *argv[])
+{
+ static struct option long_options[] =
+ {
+ { "device", required_argument, NULL, 'd'},
+ { "protocol", required_argument, NULL, 'p'},
+ { NULL}
+ };
+
+ int c;
+ int option_index = 0;
+ while ((c = getopt_long(argc, argv, "d:p:", long_options, &option_index)) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ {
+ if(m_szDevice) {
+ free(m_szDevice);
+ m_szDevice = NULL;
+ }
+ m_szDevice = strdup(optarg);
+ break;
+ }
+ case 'p':
+ {
+ if(strcasecmp(optarg,"0038") == 0) {
+ m_Protocol = ePROTOCOL_0038;
+ } else if(strcasecmp(optarg,"ffdc") == 0) {
+ m_Protocol = ePROTOCOL_FFDC;
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+ }
+
+ if (NULL == m_szDevice)
+ {
+ // neither Device given:
+ // => set "/dev/lcd0" it to default
+ m_szDevice = strdup(DEFAULT_LCDDEVICE);
+ }
+
+ return true;
+}
+
+bool cPluginImonlcd::Initialize(void)
+{
+ // Initialize any background activities the plugin shall perform.
+ return true;
+}
+
+bool cPluginImonlcd::Start(void)
+{
+ if(NULL != m_szDevice
+ && 0 == m_dev.open(m_szDevice,m_Protocol)) {
+ statusMonitor = new ciMonStatusMonitor(&m_dev);
+ if(NULL == statusMonitor){
+ esyslog("iMonLCD: can't create ciMonStatusMonitor!");
+ return (false);
+ }
+ }
+ return true;
+}
+
+void cPluginImonlcd::Stop(void)
+{
+ if(statusMonitor) {
+ delete statusMonitor;
+ statusMonitor = NULL;
+ }
+
+ m_dev.close();
+
+ if(m_szDevice) {
+ free(m_szDevice);
+ m_szDevice = NULL;
+ }
+}
+
+void cPluginImonlcd::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+}
+
+void cPluginImonlcd::MainThreadHook(void)
+{
+ // Perform actions in the context of the main program thread.
+ // WARNING: Use with great care - see PLUGINS.html!
+}
+
+cString cPluginImonlcd::Active(void)
+{
+ // Return a message string if shutdown should be postponed
+ return NULL;
+}
+
+time_t cPluginImonlcd::WakeupTime(void)
+{
+ // Return custom wakeup time for shutdown script
+ return 0;
+}
+
+cOsdObject *cPluginImonlcd::MainMenuAction(void)
+{
+ return NULL;
+}
+
+cMenuSetupPage *cPluginImonlcd::SetupMenu(void)
+{
+ return new ciMonMenuSetup(&m_dev);
+}
+
+bool cPluginImonlcd::SetupParse(const char *szName, const char *szValue)
+{
+ return theSetup.SetupParse(szName,szValue);
+}
+
+bool cPluginImonlcd::Service(const char *Id, void *Data)
+{
+ // Handle custom service requests from other plugins
+ return false;
+}
+
+const char **cPluginImonlcd::SVDRPHelpPages(void)
+{
+ // Return help text for SVDRP commands this plugin implements
+ return NULL;
+}
+
+cString cPluginImonlcd::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ // Process SVDRP commands this plugin implements
+ return NULL;
+}
+
+VDRPLUGINCREATOR(cPluginImonlcd); // Don't touch this!
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..9cc629f
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,52 @@
+# vdr-imonlcd-plugin language source file.
+# Copyright (C) Andreas Brachold <vdr07 AT deltab de>
+# This file is distributed under the same license as the PACKAGE package.
+# Andreas Brachold <vdr07 AT deltab de> 2009
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-imonlcd-plugin 0.0.1\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2009-05-21 17:44+0200\n"
+"PO-Revision-Date: 2009-05-21 17:13+0200\n"
+"Last-Translator: Andreas Brachold <vdr07 AT deltab de>\n"
+"Language-Team: Andreas Brachold <vdr07 AT deltab de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Control a iMON LCD"
+msgstr "Steuert ein iMON LCD"
+
+msgid "iMON LCD"
+msgstr "iMON LCD"
+
+msgid "Contrast"
+msgstr "Kontrast"
+
+msgid "Default font"
+msgstr "Zeichensatz"
+
+msgid "Disc spinning mode"
+msgstr "Disc Rotationsmode"
+
+msgid "Slim disc"
+msgstr "Schlanke Scheibe"
+
+msgid "Full disc"
+msgstr "Volle Scheibe"
+
+msgid "Do nothing"
+msgstr "Nicht unternehmen"
+
+msgid "Showing clock"
+msgstr "Uhrzeit anzeigen"
+
+msgid "Turning backlight off"
+msgstr "Hintergrund abschalten"
+
+msgid "Exit mode"
+msgstr "Ende Modus"
+
+msgid "Unknown title"
+msgstr "Unbekannter Titel"
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..9cb58a8
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,208 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "watch.h"
+#include "setup.h"
+
+#include <vdr/plugin.h>
+#include <vdr/tools.h>
+#include <vdr/config.h>
+#include <vdr/i18n.h>
+
+#define DEFAULT_ON_EXIT eOnExitMode_BLANKSCREEN /**< Blank the device completely */
+#define DEFAULT_CONTRAST 200
+#define DEFAULT_DISCMODE 1 /**< spin the "slim" disc */
+#define DEFAULT_WIDTH 96
+#define DEFAULT_HEIGHT 16
+#define DEFAULT_FONT "Sans:Bold"
+
+/// The one and only Stored setup data
+cIMonSetup theSetup;
+
+/// Ctor, load default values
+cIMonSetup::cIMonSetup(void)
+{
+ m_nOnExit = DEFAULT_ON_EXIT;
+ m_nContrast = DEFAULT_CONTRAST;
+ m_bDiscMode = DEFAULT_DISCMODE;
+
+ m_nWidth = DEFAULT_WIDTH;
+ m_nHeight = DEFAULT_HEIGHT;
+
+ strncpy(m_szFont,DEFAULT_FONT,sizeof(m_szFont));
+}
+
+cIMonSetup::cIMonSetup(const cIMonSetup& x)
+{
+ *this = x;
+}
+
+cIMonSetup& cIMonSetup::operator = (const cIMonSetup& x)
+{
+ m_nOnExit = x.m_nOnExit;
+ m_nContrast = x.m_nContrast;
+ m_bDiscMode = x.m_bDiscMode;
+
+ m_nWidth = x.m_nWidth;
+ m_nHeight = x.m_nHeight;
+
+ strncpy(m_szFont,x.m_szFont,sizeof(m_szFont));
+
+ return *this;
+}
+
+/// compare profilenames and load there value
+bool cIMonSetup::SetupParse(const char *szName, const char *szValue)
+{
+ // Width
+ if(!strcasecmp(szName, "Width")) {
+ int n = atoi(szValue);
+ if ((n < 0) || (n > 320)) {
+ esyslog("iMonLCD: Width must be between 0 and 320; using default %d",
+ DEFAULT_WIDTH);
+ n = DEFAULT_WIDTH;
+ }
+ m_nWidth = n;
+ return true;
+ }
+ // Height
+ if(!strcasecmp(szName, "Height")) {
+ int n = atoi(szValue);
+ if ((n < 0) || (n > 240)) {
+ esyslog("iMonLCD: Height must be between 0 and 240; using default %d",
+ DEFAULT_HEIGHT);
+ n = DEFAULT_HEIGHT;
+ }
+ m_nHeight = n;
+ return true;
+ }
+
+ // OnExit
+ if(!strcasecmp(szName, "OnExit")) {
+ int n = atoi(szValue);
+ if ((n < 0) || (n > 3)) {
+ esyslog("iMonLCD: OnExit must be between 0 and 3; using default %d",
+ DEFAULT_ON_EXIT);
+ n = DEFAULT_ON_EXIT;
+ }
+ m_nOnExit = n;
+ return true;
+ }
+
+ // Contrast
+ if(!strcasecmp(szName, "Contrast")) {
+ int n = atoi(szValue);
+ if ((n < 0) || (n > 1000)) {
+ esyslog("iMonLCD: Contrast must be between 0 and 1000; using default %d",
+ DEFAULT_CONTRAST);
+ n = DEFAULT_CONTRAST;
+ }
+ m_nContrast = n;
+ return true;
+ }
+ // Font
+ if(!strcasecmp(szName, "Font")) {
+ if(szValue) {
+ cStringList fontNames;
+ cFont::GetAvailableFontNames(&fontNames);
+ if(fontNames.Find(szValue)>=0) {
+ strncpy(m_szFont,szValue,sizeof(m_szFont));
+ return true;
+ }
+ }
+ esyslog("iMonLCD: Font '%s' not found; using default %s",
+ szValue, DEFAULT_FONT);
+ strncpy(m_szFont,DEFAULT_FONT,sizeof(m_szFont));
+ return true;
+ }
+
+ // DiscMode
+ if(!strcasecmp(szName, "DiscMode")) {
+ m_bDiscMode = atoi(szValue) == 0?0:1;
+ return true;
+ }
+
+ //Unknow parameter
+ return false;
+}
+
+
+// --- ciMonMenuSetup --------------------------------------------------------
+void ciMonMenuSetup::Store(void)
+{
+ theSetup = m_tmpSetup;
+
+ SetupStore("Width", theSetup.m_nWidth);
+ SetupStore("Height", theSetup.m_nHeight);
+ SetupStore("OnExit", theSetup.m_nOnExit);
+ SetupStore("Contrast", theSetup.m_nContrast);
+ SetupStore("DiscMode", theSetup.m_bDiscMode);
+ SetupStore("Contrast", theSetup.m_nContrast);
+ SetupStore("Font", theSetup.m_szFont);
+}
+
+ciMonMenuSetup::ciMonMenuSetup(ciMonWatch* pDev)
+: m_tmpSetup(theSetup)
+, m_pDev(pDev)
+{
+ SetSection(tr("iMON LCD"));
+
+ cFont::GetAvailableFontNames(&fontNames);
+ fontNames.Insert(strdup(DEFAULT_FONT));
+ fontIndex = max(0, fontNames.Find(m_tmpSetup.m_szFont));
+
+ Add(new cMenuEditIntItem (tr("Contrast"),
+ &m_tmpSetup.m_nContrast,
+ 0, 1000));
+
+ Add(new cMenuEditStraItem(tr("Default font"),
+ &fontIndex, fontNames.Size(), &fontNames[0]));
+
+ Add(new cMenuEditBoolItem(tr("Disc spinning mode"),
+ &m_tmpSetup.m_bDiscMode,
+ tr("Slim disc"), tr("Full disc")));
+
+
+ static const char * szExitModes[3];
+ szExitModes[eOnExitMode_SHOWMSG] = tr("Do nothing");
+ szExitModes[eOnExitMode_SHOWCLOCK] = tr("Showing clock");
+ szExitModes[eOnExitMode_BLANKSCREEN] = tr("Turning backlight off");
+
+ Add(new cMenuEditStraItem (tr("Exit mode"),
+ &m_tmpSetup.m_nOnExit,
+ memberof(szExitModes), szExitModes));
+
+/* Adjust need add moment restart
+ Add(new cMenuEditIntItem (tr("Display width"),
+ &m_tmpSetup.m_nWidth,
+ 0, 320));
+
+ Add(new cMenuEditIntItem (tr("Display height"),
+ &m_tmpSetup.m_nHeight,
+ 0, 240));
+*/
+}
+
+eOSState ciMonMenuSetup::ProcessKey(eKeys nKey)
+{
+ if(nKey == kOk) {
+ // Store edited Values
+ Utf8Strn0Cpy(m_tmpSetup.m_szFont, fontNames[fontIndex], sizeof(m_tmpSetup.m_szFont));
+ if (0 != strcmp(m_tmpSetup.m_szFont, theSetup.m_szFont)) {
+ m_pDev->SetFont(m_tmpSetup.m_szFont);
+ }
+ }
+ return cMenuSetupPage::ProcessKey(nKey);
+}
+
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..88bf574
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,56 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#ifndef __IMON_SETUP_H___
+#define __IMON_SETUP_H___
+
+#include <vdr/menuitems.h>
+#define memberof(x) (sizeof(x)/sizeof(*x))
+
+struct cIMonSetup
+{
+ int m_nOnExit;
+ int m_nContrast;
+ int m_bDiscMode;
+
+ int m_nWidth;
+ int m_nHeight;
+
+ char m_szFont[256];
+
+ cIMonSetup(void);
+ cIMonSetup(const cIMonSetup& x);
+ cIMonSetup& operator = (const cIMonSetup& x);
+
+ /// Parse our own setup parameters and store their values.
+ bool SetupParse(const char *szName, const char *szValue);
+
+};
+
+class ciMonWatch;
+class ciMonMenuSetup
+ :public cMenuSetupPage
+{
+ cIMonSetup m_tmpSetup;
+ ciMonWatch* m_pDev;
+ cStringList fontNames;
+ int fontIndex;
+protected:
+ virtual void Store(void);
+ virtual eOSState ProcessKey(eKeys nKey);
+public:
+ ciMonMenuSetup(ciMonWatch* pDev);
+};
+
+
+/// The exported one and only Stored setup data
+extern cIMonSetup theSetup;
+
+#endif //__IMON_SETUP_H___
diff --git a/status.c b/status.c
new file mode 100644
index 0000000..b786ffb
--- /dev/null
+++ b/status.c
@@ -0,0 +1,128 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#include <stdint.h>
+#include <time.h>
+#include <vdr/eitscan.h>
+
+#include "watch.h"
+#include "status.h"
+
+//#define MOREDEBUGMSG
+
+// ---
+ciMonStatusMonitor::ciMonStatusMonitor(ciMonWatch* pDev)
+: m_pDev(pDev)
+{
+
+}
+
+void ciMonStatusMonitor::ChannelSwitch(const cDevice *pDevice, int nChannelNumber)
+{
+ if (nChannelNumber > 0
+ && pDevice->IsPrimaryDevice()
+ && !EITScanner.UsesDevice(pDevice)
+ && (nChannelNumber == cDevice::CurrentChannel()))
+ {
+#ifdef MOREDEBUGMSG
+ dsyslog("iMonLCD: channel switched to %d on DVB %d", nChannelNumber, pDevice->CardIndex());
+#endif
+ m_pDev->Channel(nChannelNumber);
+ }
+}
+
+void ciMonStatusMonitor::SetVolume(int Volume, bool Absolute)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("iMonLCD: SetVolume %d %d", Volume, Absolute);
+#endif
+ m_pDev->Volume(Volume,Absolute);
+}
+
+void ciMonStatusMonitor::Recording(const cDevice *pDevice, const char *szName, const char *szFileName, bool bOn)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("iMonLCD: Recording %d %s", pDevice->CardIndex(), szName);
+#endif
+ m_pDev->Recording(pDevice,szName,szFileName,bOn);
+}
+
+void ciMonStatusMonitor::Replaying(const cControl *pControl, const char *szName, const char *szFileName, bool bOn)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("iMonLCD: Replaying %s", szName);
+#endif
+ m_pDev->Replaying(pControl,szName,szFileName,bOn);
+}
+
+void ciMonStatusMonitor::OsdClear(void)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("iMonLCD: OsdClear");
+#endif
+}
+
+void ciMonStatusMonitor::OsdTitle(const char *Title)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("iMonLCD: OsdTitle '%s'", Title);
+#endif
+}
+
+void ciMonStatusMonitor::OsdStatusMessage(const char *szMessage)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("iMonLCD: OsdStatusMessage '%s'", szMessage ? szMessage : "NULL");
+#endif
+ m_pDev->StatusMessage(szMessage);
+}
+
+void ciMonStatusMonitor::OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("iMonLCD: OsdHelpKeys %s - %s - %s - %s", Red, Green, Yellow, Blue);
+#endif
+}
+
+void ciMonStatusMonitor::OsdCurrentItem(const char *Text)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("iMonLCD: OsdCurrentItem %s", Text);
+#endif
+}
+
+void ciMonStatusMonitor::OsdTextItem(const char *Text, bool Scroll)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("iMonLCD: OsdTextItem %s %d", Text, Scroll);
+#endif
+}
+
+void ciMonStatusMonitor::OsdChannel(const char *Text)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("iMonLCD: OsdChannel %s", Text);
+#endif
+}
+
+void ciMonStatusMonitor::OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle)
+{
+#ifdef unusedMOREDEBUGMSG
+ char buffer[25];
+ struct tm tm_r;
+ dsyslog("iMonLCD: OsdProgramme");
+ strftime(buffer, sizeof(buffer), "%R", localtime_r(&PresentTime, &tm_r));
+ dsyslog("%5s %s", buffer, PresentTitle);
+ dsyslog("%5s %s", "", PresentSubtitle);
+ strftime(buffer, sizeof(buffer), "%R", localtime_r(&FollowingTime, &tm_r));
+ dsyslog("%5s %s", buffer, FollowingTitle);
+ dsyslog("%5s %s", "", FollowingSubtitle);
+#endif
+}
diff --git a/status.h b/status.h
new file mode 100644
index 0000000..b74dc0c
--- /dev/null
+++ b/status.h
@@ -0,0 +1,38 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#ifndef __IMON_STATUS__H
+#define __IMON_STATUS__H
+
+#include "imon.h"
+#include <vdr/status.h>
+
+class ciMonWatch;
+
+class ciMonStatusMonitor : public cStatus {
+ ciMonWatch* m_pDev;
+ public:
+ ciMonStatusMonitor(ciMonWatch* pDev);
+ protected:
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+ virtual void Recording(const cDevice *pDevice, const char *szName, const char *szFileName, bool bOn);
+ virtual void Replaying(const cControl *pControl, const char *szName, const char *szFileName, bool bOn);
+ virtual void SetVolume(int Volume, bool Absolute);
+ virtual void OsdClear(void);
+ virtual void OsdTitle(const char *Title);
+ virtual void OsdStatusMessage(const char *Message);
+ virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue);
+ virtual void OsdCurrentItem(const char *Text);
+ virtual void OsdTextItem(const char *Text, bool Scroll);
+ virtual void OsdChannel(const char *Text);
+ virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
+};
+
+#endif
diff --git a/watch.c b/watch.c
new file mode 100644
index 0000000..7dc40c2
--- /dev/null
+++ b/watch.c
@@ -0,0 +1,684 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+
+#include "watch.h"
+#include "setup.h"
+
+#include <vdr/tools.h>
+
+struct cMutexLooker {
+ cMutex& mutex;
+ cMutexLooker(cMutex& m):
+ mutex(m){
+ mutex.Lock();
+ }
+ virtual ~cMutexLooker() {
+ mutex.Unlock();
+ }
+};
+
+
+ciMonWatch::ciMonWatch()
+: cThread("iMonLCD: watch thread")
+, m_bShutdown(false)
+{
+ unsigned int n;
+ for(n=0;n<memberof(m_nCardIsRecording);++n) {
+ m_nCardIsRecording[n] = 0;
+ }
+ chPresentTime = 0;
+ chFollowingTime = 0;
+ chName = NULL;
+ chPresentTitle = NULL;
+ chPresentShortTitle = NULL;
+
+ m_nLastVolume = cDevice::CurrentVolume();
+ m_bVolumeMute = false;
+
+ m_bShowOsdMessage = false;
+ osdMessage = NULL;
+
+ m_pControl = NULL;
+ replayTitle = NULL;
+ replayShortTitle = NULL;
+ replayTitleLast = NULL;
+ m_eWatchMode = eLiveTV;
+ m_eVideoMode = eVideoNone;
+ m_eAudioMode = eAudioNone;
+
+ m_nScrollOffset = -1;
+ m_bScrollBackward = false;
+}
+
+ciMonWatch::~ciMonWatch()
+{
+ close();
+ if(chName) {
+ delete chName;
+ chName = NULL;
+ }
+ if(chPresentTitle) {
+ delete chPresentTitle;
+ chPresentTitle = NULL;
+ }
+ if(chPresentShortTitle) {
+ delete chPresentShortTitle;
+ chPresentShortTitle = NULL;
+ }
+ if(osdMessage) {
+ delete osdMessage;
+ osdMessage = NULL;
+ }
+ if(replayTitle) {
+ delete replayTitle;
+ replayTitle = NULL;
+ }
+ if(replayShortTitle) {
+ delete replayShortTitle;
+ replayShortTitle = NULL;
+ }
+}
+
+int ciMonWatch::open(const char* szDevice, eProtocol pro) {
+ int iRet = ciMonLCD::open(szDevice,pro);
+ if(0==iRet) {
+ Start();
+ }
+ return iRet;
+}
+
+void ciMonWatch::close() {
+
+ if(Running()) {
+ m_bShutdown = true;
+ usleep(500000);
+ Cancel();
+ }
+ ciMonLCD::close();
+}
+
+void ciMonWatch::Action(void)
+{
+ int nLastIcons = -1;
+ int nContrast = -1;
+
+ unsigned int n;
+ int nCnt = 0;
+ int nLastTopProgressBar = -1;
+ int nTopProgressBar = 0;
+ int nLastBottomProgressBar = -1;
+ int nBottomProgressBar = 0;
+ eTrackType eAudioTrackType = ttNone;
+ int nAudioChannel = 0;
+
+ cTimeMs runTime;
+
+ for (;!m_bShutdown;++nCnt) {
+
+ LOCK_THREAD;
+
+ int nIcons = 0;
+ bool bUpdateIcons = false;
+ bool bFlush = false;
+ if(m_bShutdown)
+ break;
+ else {
+ cMutexLooker m(mutex);
+
+ switch(m_eWatchMode) {
+ default:
+ case eLiveTV: nIcons |= eIconTV;break;
+ case eReplayNormal: nIcons |= eIconDiscSpin | eIconDiscEllispe | eIconTopMovie; break;
+ case eReplayMusic: nIcons |= eIconDiscSpin | eIconDiscEllispe | eIconTopMusic; break;
+ case eReplayDVD: nIcons |= eIconDiscSpin | eIconDiscEllispe | eIconTopDVD; break;
+ case eReplayFile: nIcons |= eIconDiscSpin | eIconDiscEllispe | eIconTopWeb; break;
+ case eReplayImage: nIcons |= eIconDiscSpin | eIconDiscEllispe | eIconTopPhoto; break;
+ case eReplayAudioCD: nIcons |= eIconDiscSpin | eIconDiscEllispe | eIconTopDVD; break;
+ }
+
+ bFlush = RenderScreen();
+ if(m_eWatchMode == eLiveTV) {
+ if((chFollowingTime - chPresentTime) > 0) {
+ nBottomProgressBar = (time(NULL) - chPresentTime) * 32 / (chFollowingTime - chPresentTime);
+ if(nBottomProgressBar > 32) nBottomProgressBar = 32;
+ if(nBottomProgressBar < 0) nBottomProgressBar = 0;
+ } else {
+ nBottomProgressBar = 0;
+ }
+ } else {
+ int current = 0,total = 0;
+ if(ReplayPosition(current,total) && total) {
+ nBottomProgressBar = current * 32 / total;
+ if(nBottomProgressBar > 32) nBottomProgressBar = 32;
+ if(nBottomProgressBar < 0) nBottomProgressBar = 0;
+
+ switch(ReplayMode()) {
+ case eReplayNone:
+ case eReplayPaused:
+ bUpdateIcons = false;
+ break;
+ default:
+ case eReplayPlay:
+ bUpdateIcons = (0 == (nCnt % 4));
+ nIcons |= eIconDiscRunSpin;
+ break;
+ case eReplayBackward1:
+ nIcons |= eIconDiscSpinBackward;
+ case eReplayForward1:
+ break;
+ bUpdateIcons = (0 == (nCnt % 3));
+ nIcons |= eIconDiscRunSpin;
+ case eReplayBackward2:
+ nIcons |= eIconDiscSpinBackward;
+ case eReplayForward2:
+ bUpdateIcons = (0 == (nCnt % 2));
+ nIcons |= eIconDiscRunSpin;
+ break;
+ case eReplayBackward3:
+ nIcons |= eIconDiscSpinBackward;
+ case eReplayForward3:
+ bUpdateIcons = true;
+ nIcons |= eIconDiscRunSpin;
+ break;
+ }
+ switch(m_eReplayMode) {
+ case eReplayModeShuffle: nIcons |= eIconShuffle; break;
+ case eReplayModeRepeat: nIcons |= eIconRepeat; break;
+ case eReplayModeRepeatShuffle: nIcons |= eIconShuffle | eIconRepeat; break;
+ default: break;
+ }
+
+ } else {
+ nBottomProgressBar = 0;
+ }
+ }
+
+ switch(m_eVideoMode) {
+ case eVideoMPG: nIcons |= eIconBL_MPG; break;
+ case eVideoDivX: nIcons |= eIconBL_DIVX; break;
+ case eVideoXviD: nIcons |= eIconBL_XVID; break;
+ case eVideoWMV: nIcons |= eIconBL_WMV; break;
+ default:
+ case eVideoNone: break;
+ }
+
+ if(m_eAudioMode & eAudioMPG) nIcons |= eIconBM_MPG;
+ if(m_eAudioMode & eAudioAC3) nIcons |= eIconBM_AC3;
+ if(m_eAudioMode & eAudioDTS) nIcons |= eIconBM_DTS;
+ if(m_eAudioMode & eAudioWMA) nIcons |= eIconBR_WMA;
+ if(m_eAudioMode & eAudioMP3) nIcons |= eIconBR_MP3;
+ if(m_eAudioMode & eAudioOGG) nIcons |= eIconBR_OGG;
+ if(m_eAudioMode & eAudioWAV) nIcons |= eIconBR_WAV;
+
+ for(n=0;n<memberof(m_nCardIsRecording);++n) {
+ if(0 != m_nCardIsRecording[n]) {
+ nIcons |= eIconRecording;
+ switch(n) {
+ case 0: nIcons |= eIconSRC; break;
+ case 1: nIcons |= eIconSRC1; break;
+ case 2: nIcons |= eIconSRC2; break;
+ }
+ }
+ }
+
+ if(m_bVolumeMute) {
+ nIcons |= eIconVolume;
+ } else {
+ if(eAudioTrackType == ttNone || (0 == nCnt % 10)) {
+ eAudioTrackType = cDevice::PrimaryDevice()->GetCurrentAudioTrack(); //Stereo/Dolby
+ nAudioChannel = cDevice::PrimaryDevice()->GetAudioChannel(); //0-Stereo,1-Left, 2-Right
+ }
+ switch(eAudioTrackType) {
+ default:
+ break;
+ case ttAudioFirst ... ttAudioLast: {
+ switch(nAudioChannel) {
+ case 1: nIcons |= eIconSpeakerL; break;
+ case 2: nIcons |= eIconSpeakerR; break;
+ case 0:
+ default: nIcons |= eIconSpeakerLR; break;
+ }
+ break;
+ }
+ case ttDolbyFirst ... ttDolbyLast:
+ nIcons |= eIconSpeaker51;
+ break;
+ }
+ }
+ }
+
+ runTime.Set();
+ if(theSetup.m_nContrast != nContrast) {
+ nContrast = theSetup.m_nContrast;
+ Contrast(nContrast);
+ }
+
+ if(bUpdateIcons || nIcons != nLastIcons) {
+ icons(nIcons);
+ nLastIcons = nIcons;
+ }
+ if(nTopProgressBar != nLastTopProgressBar
+ || nBottomProgressBar != nLastBottomProgressBar ) {
+
+ setLineLength(nTopProgressBar, nBottomProgressBar, nTopProgressBar, nBottomProgressBar);
+ nLastTopProgressBar = nTopProgressBar;
+ nLastBottomProgressBar = nBottomProgressBar;
+
+ }
+ if(bFlush) {
+ flush();
+ }
+ int nDelay = 100 - runTime.Elapsed();
+ if(nDelay <= 10) {
+ nDelay = 10;
+ }
+ cCondWait::SleepMs(nDelay);
+ }
+ dsyslog("iMonLCD: watch thread closed (pid=%d)", getpid());
+}
+
+bool ciMonWatch::RenderScreen() {
+ cString* scRender;
+ bool bForce = m_bUpdateScreen;
+ if(m_eWatchMode == eLiveTV) {
+ if(Program()) {
+ bForce = true;
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+ }
+ if(chPresentTitle)
+ scRender = chPresentTitle;
+ else
+ scRender = chName;
+ } else {
+ if(Replay()) {
+ bForce = true;
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+ }
+ scRender = replayTitle;
+ }
+ if(bForce || m_nScrollOffset > 0 || m_bScrollBackward) {
+ this->clear();
+ if(scRender) {
+ int iRet = this->DrawText(0 - m_nScrollOffset,0,(*scRender));
+ switch(iRet) {
+ case 0:
+ if(m_nScrollOffset <= 0) {
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+ break; //Fit to screen
+ }
+ m_bScrollBackward = true;
+ case 2:
+ case 1:
+ if(m_bScrollBackward) m_nScrollOffset -= 2;
+ else m_nScrollOffset += 2;
+ if(m_nScrollOffset >= 0)
+ break;
+ case -1:
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+ break;
+ }
+ }
+
+ m_bUpdateScreen = false;
+ return true;
+ }
+ return false;
+}
+
+bool ciMonWatch::Replay() {
+
+ if(replayTitleLast != replayTitle) {
+ replayTitleLast = replayTitle;
+ return true;
+ }
+ return false;
+}
+
+void ciMonWatch::Replaying(const cControl * Control, const char * Name, const char *FileName, bool On)
+{
+ cMutexLooker m(mutex);
+ m_bUpdateScreen = true;
+ if (On)
+ {
+ m_eVideoMode = eVideoMPG;
+ m_eAudioMode = eAudioMPG;
+
+ m_pControl = (cControl *) Control;
+ m_eWatchMode = eReplayNormal;
+ if(replayTitle) {
+ delete replayTitle;
+ replayTitle = NULL;
+ }
+ m_eReplayMode = eReplayModeNormal;
+ if (Name && !isempty(Name))
+ {
+ int slen = strlen(Name);
+ bool bFound = false;
+ ///////////////////////////////////////////////////////////////////////
+ //Looking for mp3/muggle-plugin replay : [LS] (444/666) title
+ //
+ if (slen > 6 &&
+ *(Name+0)=='[' &&
+ *(Name+3)==']' &&
+ *(Name+5)=='(') {
+ unsigned int i;
+ for (i=6; *(Name + i) != '\0'; ++i) { //search for [xx] (xxxx) title
+ if (*(Name+i)==' ' && *(Name+i-1)==')') {
+ bFound = true;
+ break;
+ }
+ }
+ if (bFound) { //found mp3/muggle-plugin
+ // get loopmode
+ if ((*(Name+1) != '.') && (*(Name+2) != '.')) {
+ m_eReplayMode = eReplayModeRepeatShuffle;
+ } else {
+ if (*(Name+1) != '.') m_eReplayMode = eReplayModeRepeat;
+ if (*(Name+2) != '.') m_eReplayMode = eReplayModeShuffle;
+ }
+ if (strlen(Name+i) > 0) { //if name isn't empty, then copy
+ replayTitle = new cString(skipspace(Name + i));
+ }
+ m_eWatchMode = eReplayMusic;
+ m_eVideoMode = eVideoNone;
+ m_eAudioMode = eAudioMP3;
+ }
+ }
+ ///////////////////////////////////////////////////////////////////////
+ //Looking for DVD-Plugin replay : 1/8 4/28, de 2/5 ac3, no 0/7, 16:9, VOLUMENAME
+ // cDvdPlayerControl::GetDisplayHeaderLine
+ // titleinfo, audiolang, spulang, aspect, title
+ if (!bFound && slen>7)
+ {
+ unsigned int i,n;
+ for (n=0,i=0;*(Name+i) != '\0';++i)
+ { //search volumelabel after 4*", " => xxx, xxx, xxx, xxx, title
+ if (*(Name+i)==' ' && *(Name+i-1)==',') {
+ if (++n == 4) {
+ bFound = true;
+ break;
+ }
+ }
+ }
+ if (bFound) //found DVD replay
+ {
+ if (strlen(Name+i) > 0)
+ { // if name isn't empty, then copy
+ replayTitle = new cString(skipspace(Name + i));
+ }
+ m_eWatchMode = eReplayDVD;
+ m_eVideoMode = eVideoMPG;
+ m_eAudioMode = eAudioMPG;
+ }
+ }
+ if (!bFound) {
+ int i;
+ for (i=slen-1;i>0;--i)
+ { //search reverse last Subtitle
+ // - filename contains '~' => subdirectory
+ // or filename contains '/' => subdirectory
+ switch (*(Name+i)) {
+ case '/': {
+ // look for file extentsion like .xxx or .xxxx
+ if (slen>5 && ((*(Name+slen-4) == '.') || (*(Name+slen-5) == '.')))
+ {
+ m_eWatchMode = eReplayFile;
+ }
+ else
+ {
+ break;
+ }
+ }
+ case '~': {
+ replayTitle = new cString(Name + i + 1);
+ bFound = true;
+ i = 0;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ if (0 == strncmp(Name,"[image] ",8)) {
+ if (m_eWatchMode != eReplayFile) //if'nt already Name stripped-down as filename
+ replayTitle = new cString(Name + 8);
+ m_eWatchMode = eReplayImage;
+ m_eVideoMode = eVideoMPG;
+ m_eAudioMode = eAudioNone;
+ bFound = true;
+ }
+ else if (0 == strncmp(Name,"[audiocd] ",10)) {
+ replayTitle = new cString(Name + 10);
+ m_eWatchMode = eReplayAudioCD;
+ m_eVideoMode = eVideoNone;
+ m_eAudioMode = eAudioWAV;
+ bFound = true;
+ }
+ if (!bFound) {
+ replayTitle = new cString(Name);
+ }
+ }
+ if (!replayTitle) {
+ replayTitle = new cString(tr("Unknown title"));
+ }
+ }
+ else
+ {
+ m_eWatchMode = eLiveTV;
+ m_pControl = NULL;
+ }
+}
+
+
+eReplayState ciMonWatch::ReplayMode() const
+{
+ bool Play = false, Forward = false;
+ int Speed = -1;
+ if (m_pControl
+ && ((cControl *)m_pControl)->GetReplayMode(Play,Forward,Speed))
+ {
+ // 'Play' tells whether we are playing or pausing, 'Forward' tells whether
+ // we are going forward or backward and 'Speed' is -1 if this is normal
+ // play/pause mode, 0 if it is single speed fast/slow forward/back mode
+ // and >0 if this is multi speed mode.
+ switch(Speed) {
+ default:
+ case -1:
+ return Play ? eReplayPlay : eReplayPaused;
+ case 0:
+ case 1:
+ return Forward ? eReplayForward1 : eReplayBackward1;
+ case 2:
+ return Forward ? eReplayForward2 : eReplayBackward2;
+ case 3:
+ return Forward ? eReplayForward3 : eReplayBackward3;
+ }
+ }
+ return eReplayNone;
+}
+
+bool ciMonWatch::ReplayPosition(int &current, int &total) const
+{
+ if (m_pControl && ((cControl *)m_pControl)->GetIndex(current, total, false))
+ {
+ total = (total == 0) ? 1 : total;
+ return true;
+ }
+ return false;
+}
+
+void ciMonWatch::Recording(const cDevice *pDevice, const char *szName, const char *szFileName, bool bOn)
+{
+ cMutexLooker m(mutex);
+
+ unsigned int nCardIndex = pDevice->CardIndex();
+ if (nCardIndex > memberof(m_nCardIsRecording) - 1 )
+ nCardIndex = memberof(m_nCardIsRecording)-1;
+
+ if (nCardIndex < memberof(m_nCardIsRecording)) {
+ if (bOn) {
+ ++m_nCardIsRecording[nCardIndex];
+ }
+ else {
+ if (m_nCardIsRecording[nCardIndex] > 0)
+ --m_nCardIsRecording[nCardIndex];
+ }
+ }
+ else {
+ esyslog("iMonLCD: Recording: only up to %d devices are supported by this plugin", memberof(m_nCardIsRecording));
+ }
+}
+
+void ciMonWatch::Channel(int ChannelNumber)
+{
+ cMutexLooker m(mutex);
+ if(chPresentTitle) {
+ delete chPresentTitle;
+ chPresentTitle = NULL;
+ }
+ if(chPresentShortTitle) {
+ delete chPresentShortTitle;
+ chPresentShortTitle = NULL;
+ }
+ if(chName) {
+ delete chName;
+ chName = NULL;
+ }
+
+ m_eVideoMode = eVideoNone;
+ m_eAudioMode = eAudioNone;
+
+ cChannel * ch = Channels.GetByNumber(ChannelNumber);
+ if(ch) {
+ chID = ch->GetChannelID();
+ chPresentTime = 0;
+ chFollowingTime = 0;
+ if (!isempty(ch->Name())) {
+ chName = new cString(ch->Name());
+ }
+ if(ch->Vpid()) m_eVideoMode = eVideoMPG;
+ if(ch->Apid(0)) m_eAudioMode |= eAudioMPG;
+ if(ch->Dpid(0)) m_eAudioMode |= eAudioAC3;
+ }
+ m_eWatchMode = eLiveTV;
+ m_bUpdateScreen = true;
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+}
+
+bool ciMonWatch::Program() {
+
+ bool bChanged = false;
+ const cEvent * p = NULL;
+ cSchedulesLock schedulesLock;
+ const cSchedules * schedules = cSchedules::Schedules(schedulesLock);
+ if (chID.Valid() && schedules)
+ {
+ const cSchedule * schedule = schedules->GetSchedule(chID);
+ if (schedule)
+ {
+ if ((p = schedule->GetPresentEvent()) != NULL)
+ {
+ if(chPresentTime && chEventID == p->EventID()) {
+ return false;
+ }
+
+ bChanged = true;
+ chEventID = p->EventID();
+ chPresentTime = p->StartTime();
+ chFollowingTime = p->EndTime();
+
+ if(chPresentTitle) {
+ delete chPresentTitle;
+ chPresentTitle = NULL;
+ }
+ if (!isempty(p->Title())) {
+ chPresentTitle = new cString(p->Title());
+ }
+
+ if(chPresentShortTitle) {
+ delete chPresentShortTitle;
+ chPresentShortTitle = NULL;
+ }
+ if (!isempty(p->ShortText())) {
+ chPresentShortTitle = new cString(p->ShortText());
+ }
+ }
+ }
+ }
+ return bChanged;
+}
+
+
+bool ciMonWatch::Volume(int nVolume, bool bAbsolute)
+{
+ cMutexLooker m(mutex);
+
+ int nAbsVolume;
+
+ nAbsVolume = m_nLastVolume;
+ if (bAbsolute) {
+ nAbsVolume=100*nVolume/255;
+ } else {
+ nAbsVolume=nAbsVolume+100*nVolume/255;
+ }
+
+ bool bStateIsChanged = false;
+ if(m_nLastVolume > 0 && 0 == nAbsVolume) {
+ m_bVolumeMute = true;
+ bStateIsChanged = true;
+ }
+ else if(0 == m_nLastVolume && nAbsVolume > 0) {
+ m_bVolumeMute = false;
+ bStateIsChanged = true;
+ }
+ m_nLastVolume = nAbsVolume;
+
+ return bStateIsChanged;
+}
+
+void ciMonWatch::StatusMessage(const char *szMessage)
+{
+ cMutexLooker m(mutex);
+ if(szMessage) {
+ if(osdMessage) {
+ delete osdMessage;
+ osdMessage = NULL;
+ }
+ if (!isempty(szMessage)) {
+ osdMessage = new cString(szMessage);
+ m_bShowOsdMessage = true;
+ m_bUpdateScreen = true;
+ }
+ } else {
+ m_bShowOsdMessage = false;
+ m_bUpdateScreen = true;
+ }
+}
+
+bool ciMonWatch::SetFont(const char *szFont) {
+ cMutexLooker m(mutex);
+ if(ciMonLCD::SetFont(szFont)) {
+ m_bUpdateScreen = true;
+ return true;
+ }
+ return false;
+}
+
diff --git a/watch.h b/watch.h
new file mode 100644
index 0000000..d22e0fe
--- /dev/null
+++ b/watch.h
@@ -0,0 +1,128 @@
+/*
+ * iMON LCD plugin to VDR (C++)
+ *
+ * (C) 2009 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ *
+ */
+
+#ifndef __IMON_WATCH_H
+#define __IMON_WATCH_H
+
+#include <vdr/thread.h>
+#include <vdr/status.h>
+#include "imon.h"
+
+enum eWatchMode {
+ eUndefined,
+ eLiveTV,
+ eReplayNormal,
+ eReplayMusic,
+ eReplayDVD,
+ eReplayFile,
+ eReplayImage,
+ eReplayAudioCD
+};
+
+enum eReplayState {
+ eReplayNone,
+ eReplayPlay,
+ eReplayPaused,
+ eReplayForward1,
+ eReplayForward2,
+ eReplayForward3,
+ eReplayBackward1,
+ eReplayBackward2,
+ eReplayBackward3
+};
+
+enum eReplayMode {
+ eReplayModeNormal,
+ eReplayModeShuffle,
+ eReplayModeRepeat,
+ eReplayModeRepeatShuffle,
+};
+
+enum eVideoMode {
+ eVideoNone,
+ eVideoMPG,
+ eVideoDivX,
+ eVideoXviD,
+ eVideoWMV
+};
+
+enum eAudioMode {
+ eAudioNone = 0,
+ eAudioMPG = 1 << 0,
+ eAudioAC3 = 1 << 1,
+ eAudioDTS = 1 << 2,
+ eAudioWMA = 1 << 3,
+ eAudioMP3 = 1 << 4,
+ eAudioOGG = 1 << 5,
+ eAudioWAV = 1 << 6
+};
+
+class ciMonWatch
+ : public ciMonLCD
+ , protected cThread {
+private:
+ cMutex mutex;
+
+ volatile bool m_bShutdown;
+
+ eWatchMode m_eWatchMode;
+ eVideoMode m_eVideoMode;
+ int m_eAudioMode;
+
+ int m_nScrollOffset;
+ bool m_bScrollBackward;
+ bool m_bUpdateScreen;
+
+ int m_nCardIsRecording[16];
+
+ const cControl *m_pControl;
+
+ tChannelID chID;
+ tEventID chEventID;
+ time_t chPresentTime;
+ time_t chFollowingTime;
+ cString* chName;
+ cString* chPresentTitle;
+ cString* chPresentShortTitle;
+
+ int m_nLastVolume;
+ bool m_bVolumeMute;
+
+ bool m_bShowOsdMessage;
+ cString* osdMessage;
+
+ eReplayMode m_eReplayMode;
+ cString* replayTitle;
+ cString* replayShortTitle;
+ cString* replayTitleLast;
+protected:
+ virtual void Action(void);
+ bool Program();
+ bool Replay();
+ bool RenderScreen();
+ eReplayState ReplayMode() const;
+ bool ReplayPosition(int &current, int &total) const;
+public:
+ ciMonWatch();
+ virtual ~ciMonWatch();
+
+ virtual int open(const char* szDevice, eProtocol pro);
+ virtual void close ();
+
+ void Replaying(const cControl *pControl, const char *szName, const char *szFileName, bool bOn);
+ void Recording(const cDevice *pDevice, const char *szName, const char *szFileName, bool bOn);
+ void Channel(int nChannelNumber);
+ bool Volume(int nVolume, bool bAbsolute);
+ void StatusMessage(const char *szMessage);
+
+ virtual bool SetFont(const char *szFont);
+};
+
+#endif