diff options
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 6 | ||||
-rw-r--r-- | Makefile | 116 | ||||
-rw-r--r-- | README | 103 | ||||
-rw-r--r-- | bitmap.c | 98 | ||||
-rw-r--r-- | bitmap.h | 37 | ||||
-rw-r--r-- | ffont.c | 222 | ||||
-rw-r--r-- | ffont.h | 79 | ||||
-rw-r--r-- | imon.c | 640 | ||||
-rw-r--r-- | imon.h | 136 | ||||
-rw-r--r-- | imonlcd.c | 224 | ||||
-rw-r--r-- | po/de_DE.po | 52 | ||||
-rw-r--r-- | setup.c | 208 | ||||
-rw-r--r-- | setup.h | 56 | ||||
-rw-r--r-- | status.c | 128 | ||||
-rw-r--r-- | status.h | 38 | ||||
-rw-r--r-- | watch.c | 684 | ||||
-rw-r--r-- | watch.h | 128 |
18 files changed, 3295 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. @@ -0,0 +1,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 @@ -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 @@ -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; +} + @@ -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 @@ -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; +} @@ -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" @@ -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); +} + @@ -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 @@ -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 ¤t, 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; +} + @@ -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 ¤t, 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 |