summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoranbr <vdr07@deltab.de>2010-04-29 20:16:56 +0200
committeranbr <vdr07@deltab.de>2010-04-29 20:16:56 +0200
commitabf620e610be57231b2fc0d3859581ba600662c0 (patch)
treec85b841a26dfb80866322c8ba482b0d57d964a0b
downloadvdr-plugin-targavfd-abf620e610be57231b2fc0d3859581ba600662c0.tar.gz
vdr-plugin-targavfd-abf620e610be57231b2fc0d3859581ba600662c0.tar.bz2
initial import0.0.3
-rw-r--r--COPYING675
-rw-r--r--HISTORY7
-rw-r--r--Makefile127
-rw-r--r--README120
-rw-r--r--bitmap.c102
-rw-r--r--bitmap.h41
-rw-r--r--ffont.c232
-rw-r--r--ffont.h81
-rw-r--r--po/de_DE.po58
-rw-r--r--po/it_IT.po61
-rw-r--r--setup.c187
-rw-r--r--setup.h69
-rw-r--r--status.c135
-rw-r--r--status.h42
-rw-r--r--targavfd.c364
-rw-r--r--vfd.c472
-rw-r--r--vfd.h100
-rw-r--r--watch.c874
-rw-r--r--watch.h129
19 files changed, 3876 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..10926e8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,675 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU 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. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..83a996e
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,7 @@
+VDR Plugin 'targavfd' Revision History
+-------------------------------------
+
+2010-04-18: Version 0.0.3
+
+- Initial revision.
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..eaaa370
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,127 @@
+#
+# Makefile for targavfd plugin to VDR (C++)
+#
+# (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+#
+# This plugin 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, version 3 of the License.
+#
+# See the files README and COPYING for details.
+#
+################################################################################
+#
+# 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 = targavfd
+
+### 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)
+
+INCLUDES += $(shell pkg-config --cflags libhid)
+LIBS += $(shell pkg-config --libs libhid)
+DEFINES += -DHAVE_STDBOOL_H
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o bitmap.o vfd.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 $(PODIR)/*~
+
diff --git a/README b/README
new file mode 100644
index 0000000..33cd768
--- /dev/null
+++ b/README
@@ -0,0 +1,120 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by : Andreas Brachold <vdr07 AT deltab de>
+
+Project's homepage:
+
+This plugin for VDR 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, version 3 of the License.
+
+This plugin for VDR 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 plugin for VDR. If not, see <http://www.gnu.org/licenses/>.
+
+See the file COPYING for license information.
+
+Description:
+------------
+targavfd is a plugin for the Video Disc Recorder and shows information
+about the current state of VDR on Targa USB Graphic Vacuum Fluorescent Display.
+
+
+Install libhid:
+-------------------------------------
+You need installed library libhid to use the vdr-plugin-targavfd.
+This library libhid is used to access and interact with a USB HID device.
+
+1. http://libhid.alioth.debian.org/
+
+Install vdr-plugin-targavfd:
+---------------------------
+Unpack the vdr-targavfd tarball to $VDRSOURCE/PLUGINS/src directory.
+Variable $VDRSOURCE stands for a directory, where source archive of VDR package
+was be decompressed.
+
+#> cd $VDRSOURCE/PLUGINS/src
+#> tar -xzvf vdr-targavfd-0.0.1.tgz
+#> ln -s targavfd-0.0.1 targavfd
+
+Compile the plugin (from VDR's source directory)
+
+Change the working directory to VDR source root and compile this plugin
+like all other VDR plugins.
+
+#> cd $VDRSOURCE
+#> make plugins
+
+After everything has been compiled without errors, copy the plugin to their
+target directory.
+
+#> make install
+
+
+Check follow requirements
+-------------------------
+* Device still detected and writable
+
+ #> lsusb -vd 19c2:6a11 | grep iProduct
+ iProduct 2 Targa USB Graphic Vacuum Fluorescent Display
+
+* Add a udev permission rule, if required (writable for group vdr) e.g.
+ /etc/udev/rules.d/92-vfd.rules
+ ACTION=="add", BUS=="usb", SYSFS{idVendor}=="19c2", SYSFS{idProduct}=="6a11", GROUP="vdr"
+
+Start VDR with the plugin.
+---------------------------
+ Examples:
+ vdr -P'targavfd'
+
+Setup options
+-------------
+This options are editable at run time. (Menu: Setup > Plugin > targavfd ... )
+
+* Brightness
+ - Set brightness from display. (Default: 1)
+
+* Default font
+ - Used font, there should installed like other FreeType supported fonts
+
+* Exit mode
+ - Do nothing - Just leave the "last" message there
+ - Showing clock - Show the big clock
+ - Turning display off - Blank the device completely
+ - Show next timer - Show time and title of next timer
+
+
+Plugin SVDRP commands
+---------------------
+* HELP - List known commands
+* OFF - Suspend driver of display.
+* ON - Resume driver of display.
+* ICON [name] [on|off|auto] - Force state of icon.
+
+Use this commands like follow samples
+ #> svdrpsend.pl PLUG targavfd OFF
+ 220 vdr SVDRP VideoDiskRecorder ....
+ 250 driver suspended
+ 221 vdr closing connection
+
+ #> svdrpsend.pl PLUG targavfd HELP ICON
+ 214-ICON [name] [on|off|auto]
+ 214- Force state of icon. Names of icons are:
+ 214- Play,Pause,Record,Message,Message,Mute...
+
+This commands can have follow responses
+OFF : 250 driver suspended
+ 251 driver already suspended
+ON : 250 driver resumed
+ 251 driver already resumed
+ 554 driver could not resumed
+ICON : 250 icon state 'auto'
+ 251 icon state 'on'
+ 252 icon state 'off'
+* 501 unknown command
+
+
diff --git a/bitmap.c b/bitmap.c
new file mode 100644
index 0000000..44ebdbd
--- /dev/null
+++ b/bitmap.c
@@ -0,0 +1,102 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#include <vdr/tools.h>
+#include "bitmap.h"
+
+cVFDBitmap::cVFDBitmap(int w, int h) {
+ width = w;
+ height = h;
+
+ // lines are byte aligned
+ bytesPerLine = (width + 7) / 8;
+
+ bitmap = MALLOC(uchar, bytesPerLine * height);
+ clear();
+}
+
+cVFDBitmap::cVFDBitmap() {
+ height = 0;
+ width = 0;
+ bitmap = NULL;
+}
+
+cVFDBitmap::~cVFDBitmap() {
+
+ if(bitmap)
+ free(bitmap);
+ bitmap = NULL;
+}
+
+cVFDBitmap& cVFDBitmap::operator = (const cVFDBitmap& 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 cVFDBitmap::operator == (const cVFDBitmap& 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 cVFDBitmap::clear() {
+ if (bitmap)
+ memset(bitmap, 0x00, bytesPerLine * height);
+}
+
+bool cVFDBitmap::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..6f4691e
--- /dev/null
+++ b/bitmap.h
@@ -0,0 +1,41 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#ifndef __VFD_BITMAP_H___
+#define __VFD_BITMAP_H___
+
+class cVFDBitmap {
+ int height;
+ int width;
+ unsigned int bytesPerLine;
+ uchar *bitmap;
+protected:
+ cVFDBitmap();
+public:
+ cVFDBitmap( int w, int h );
+
+ virtual ~cVFDBitmap();
+ cVFDBitmap& operator = (const cVFDBitmap& x);
+ bool operator == (const cVFDBitmap& x) const;
+
+ void clear();
+ int Height() const { return height; }
+ int Width() const { return width; }
+ bool SetPixel(int x, int y);
+
+ uchar * getBitmap() const { return bitmap; };
+};
+
+
+#endif
+
diff --git a/ffont.c b/ffont.c
new file mode 100644
index 0000000..2afac15
--- /dev/null
+++ b/ffont.c
@@ -0,0 +1,232 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ * Glyph handling based on <vdr/font.c>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#include <vdr/tools.h>
+#include "ffont.h"
+
+// --- cVFDFont ---------------------------------------------------------
+
+#define KERNING_UNKNOWN (-10000)
+
+cVFDGlyph::cVFDGlyph(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);
+}
+
+cVFDGlyph::~cVFDGlyph()
+{
+ free(bitmap);
+}
+
+int cVFDGlyph::GecVFDKerningCache(uint PrevSym) const
+{
+ for (int i = kerningCache.Size(); --i > 0; ) {
+ if (kerningCache[i].prevSym == PrevSym)
+ return kerningCache[i].kerning;
+ }
+ return KERNING_UNKNOWN;
+}
+
+void cVFDGlyph::SecVFDKerningCache(uint PrevSym, int Kerning)
+{
+ kerningCache.Append(cVFDKerning(PrevSym, Kerning));
+}
+
+
+
+cVFDFont::cVFDFont(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("targaVFD: FreeType: error %d in FT_Render_Glyph", error);
+ }
+ else
+ esyslog("targaVFD: 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("targaVFD: FreeType: error %d during FT_Set_Char_Size (font = %s)\n", error, Name);
+ }
+ }
+ else
+ esyslog("targaVFD: FreeType: load error %d (font = %s)", error, Name);
+ }
+ else
+ esyslog("targaVFD: FreeType: initialization error %d (font = %s)", error, Name);
+}
+
+cVFDFont::~cVFDFont()
+{
+ FT_Done_Face(face);
+ FT_Done_FreeType(library);
+}
+
+int cVFDFont::Kerning(cVFDGlyph *Glyph, uint PrevSym) const
+{
+ int kerning = 0;
+ if (Glyph && PrevSym) {
+ kerning = Glyph->GecVFDKerningCache(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->SecVFDKerningCache(PrevSym, kerning);
+ }
+ }
+ return kerning;
+}
+
+cVFDGlyph* cVFDFont::Glyph(uint CharCode) const
+{
+ // Non-breaking space:
+ if (CharCode == 0xA0)
+ CharCode = 0x20;
+
+ // Lookup in cache:
+ cList<cVFDGlyph> *glyphCache = &glyphCacheMonochrome;
+ for (cVFDGlyph *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("targaVFD: FreeType: error during FT_Load_Glyph");
+ else {
+#if ((FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 7) \
+ || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 2 && FREETYPE_PATCH <= 1))
+ if (CharCode == 32) // workaround for libfreetype bug
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+ else
+#endif
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
+ if (error)
+ esyslog("targaVFD: FreeType: error during FT_Render_Glyph %d, %d\n", CharCode, glyph_index);
+ else { //new bitmap
+ cVFDGlyph *Glyph = new cVFDGlyph(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 cVFDFont::Width(uint c) const
+{
+ cVFDGlyph *g = Glyph(c);
+ return g ? g->AdvanceX() : 0;
+}
+
+int cVFDFont::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;
+ cVFDGlyph *g = Glyph(sym);
+ if (g)
+ w += g->AdvanceX() + Kerning(g, prevSym);
+ prevSym = sym;
+ }
+ }
+ return w;
+}
+
+int cVFDFont::DrawText(cVFDBitmap *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;
+ cVFDGlyph *g = Glyph(sym);
+ if (!g)
+ continue;
+ int kerning = Kerning(g, prevSym);
+ prevSym = sym;
+ uchar *buffer = g->Bitmap();
+ int symWidth = g->Width();
+ if (Width && x + symWidth + g->Left() + kerning - 1 > Width)
+ return 1; // we don't draw partial characters
+ if (x + symWidth + g->Left() + kerning > 0) {
+ for (int row = 0; row < g->Rows(); row++) {
+ for (int pitch = 0; pitch < g->Pitch(); pitch++) {
+ uchar bt = *(buffer + (row * g->Pitch() + pitch));
+ for (int col = 0; col < 8 && col + pitch * 8 <= symWidth; col++) {
+ if (bt & 0x80)
+ Bitmap->SetPixel(x + col + pitch * 8 + g->Left() + kerning,
+ y + row + (height - Bottom() - g->Top()));
+ bt <<= 1;
+ }
+ }
+ }
+ }
+ x += g->AdvanceX() + kerning;
+ if (x > Bitmap->Width() - 1)
+ return 1;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+
diff --git a/ffont.h b/ffont.h
new file mode 100644
index 0000000..186f207
--- /dev/null
+++ b/ffont.h
@@ -0,0 +1,81 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ * Glyph handling based on <vdr/font.c>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#ifndef __VFD_FONT_H___
+#define __VFD_FONT_H___
+
+#include <vdr/font.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "bitmap.h"
+
+struct cVFDKerning {
+ uint prevSym;
+ int kerning;
+ cVFDKerning(uint PrevSym, int Kerning = 0) { prevSym = PrevSym; kerning = Kerning; }
+ };
+
+class cVFDGlyph : 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<cVFDKerning> kerningCache;
+public:
+ cVFDGlyph(uint CharCode, FT_GlyphSlotRec_ *GlyphData);
+ virtual ~cVFDGlyph();
+ 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 GecVFDKerningCache(uint PrevSym) const;
+ void SecVFDKerningCache(uint PrevSym, int Kerning);
+ };
+
+
+class cVFDFont : public cFont {
+private:
+ int height;
+ int bottom;
+ FT_Library library; ///< Handle to library
+ FT_Face face; ///< Handle to face object
+ mutable cList<cVFDGlyph> glyphCacheMonochrome;
+ int Bottom(void) const { return bottom; }
+ int Kerning(cVFDGlyph *Glyph, uint PrevSym) const;
+ cVFDGlyph* Glyph(uint CharCode) const;
+ virtual void DrawText(cBitmap*, int, int, const char*, tColor, tColor, int) const {};
+public:
+ cVFDFont(const char *Name, int CharHeight, int CharWidth = 0);
+ virtual ~cVFDFont();
+ virtual int Width(uint c) const;
+ virtual int Width(const char *s) const;
+ virtual int Height(void) const { return height; }
+
+ int DrawText(cVFDBitmap *Bitmap, int x, int y, const char *s, int Width) const;
+};
+
+
+#endif
+
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..7262aa5
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,58 @@
+# vdr-targavfd-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-targavfd-plugin 0.0.1\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2010-04-17 11:55+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=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "targavfd"
+msgstr "TargaVFD"
+
+msgid "Brightness"
+msgstr "Helligkeit"
+
+msgid "Default font"
+msgstr "Zeichensatz"
+
+msgid "Render mode"
+msgstr "Anzeigemodus"
+
+msgid "Single line"
+msgstr "Einzelne Zeile"
+
+msgid "Dual lines"
+msgstr "Zwei Zeilen"
+
+msgid "Do nothing"
+msgstr "Nichts unternehmen"
+
+msgid "Showing clock"
+msgstr "Uhrzeit anzeigen"
+
+msgid "Turning display off"
+msgstr "Abschalten der Anzeige"
+
+msgid "Show next timer"
+msgstr "Nächsten Timer anzeigen"
+
+msgid "Exit mode"
+msgstr "Ende Modus"
+
+msgid "Control a targa vfd"
+msgstr "Steuert ein Targa VFD"
+
+msgid "None active timer"
+msgstr "Kein aktiver Timer"
+
+msgid "Unknown title"
+msgstr "Unbekannter Titel"
diff --git a/po/it_IT.po b/po/it_IT.po
new file mode 100644
index 0000000..04e0008
--- /dev/null
+++ b/po/it_IT.po
@@ -0,0 +1,61 @@
+# vdr-targavfd-plugin language source file.
+# Copyright (C) Diego Pierotto <vdr-italian at tiscali.it>
+# This file is distributed under the same license as the PACKAGE package.
+# Diego Pierotto <vdr-italian at tiscali.it> 2009
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-targavfd-plugin 0.0.1\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2010-04-17 11:55+0200\n"
+"PO-Revision-Date: 2009-06-07 23:30+0100\n"
+"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Italian\n"
+"X-Poedit-Country: ITALY\n"
+"X-Poedit-SourceCharset: utf-8\n"
+
+msgid "targavfd"
+msgstr "TargaVFD"
+
+msgid "Brightness"
+msgstr ""
+
+msgid "Default font"
+msgstr "Carattere predefinito"
+
+msgid "Render mode"
+msgstr ""
+
+msgid "Single line"
+msgstr ""
+
+msgid "Dual lines"
+msgstr ""
+
+msgid "Do nothing"
+msgstr "Non fare nulla"
+
+msgid "Showing clock"
+msgstr "Mostra orologio"
+
+msgid "Turning display off"
+msgstr "Spegni retroilluminazione"
+
+msgid "Show next timer"
+msgstr "Mostra prossimo timer"
+
+msgid "Exit mode"
+msgstr "Modalità d'uscita"
+
+msgid "Control a targa vfd"
+msgstr "Controlla un VFD targa"
+
+msgid "None active timer"
+msgstr "Nessun timer attivo"
+
+msgid "Unknown title"
+msgstr "Titolo sconosciuto"
diff --git a/setup.c b/setup.c
new file mode 100644
index 0000000..3374da9
--- /dev/null
+++ b/setup.c
@@ -0,0 +1,187 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and 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_BRIGHTNESS 1
+#define DEFAULT_WIDTH 96
+#define DEFAULT_HEIGHT 16
+#define DEFAULT_FONT "Sans:Bold"
+#define DEFAULT_TWO_LINE_MODE 0
+
+/// The one and only Stored setup data
+cVFDSetup theSetup;
+
+/// Ctor, load default values
+cVFDSetup::cVFDSetup(void)
+: m_cWidth(DEFAULT_WIDTH)
+, m_cHeight(DEFAULT_HEIGHT)
+{
+ m_nOnExit = DEFAULT_ON_EXIT;
+ m_nBrightness = DEFAULT_BRIGHTNESS;
+ m_bTwoLineMode = DEFAULT_TWO_LINE_MODE;
+
+ strncpy(m_szFont,DEFAULT_FONT,sizeof(m_szFont));
+}
+
+cVFDSetup::cVFDSetup(const cVFDSetup& x)
+: m_cWidth(DEFAULT_WIDTH)
+, m_cHeight(DEFAULT_HEIGHT)
+{
+ *this = x;
+}
+
+cVFDSetup& cVFDSetup::operator = (const cVFDSetup& x)
+{
+ m_nOnExit = x.m_nOnExit;
+ m_nBrightness = x.m_nBrightness;
+
+ m_bTwoLineMode = x.m_bTwoLineMode;
+
+ strncpy(m_szFont,x.m_szFont,sizeof(m_szFont));
+
+ return *this;
+}
+
+/// compare profilenames and load there value
+bool cVFDSetup::SetupParse(const char *szName, const char *szValue)
+{
+ // OnExit
+ if(!strcasecmp(szName, "OnExit")) {
+ int n = atoi(szValue);
+ if ((n < eOnExitMode_SHOWMSG) || (n >= eOnExitMode_LASTITEM)) {
+ esyslog("targaVFD: OnExit must be between %d and %d; using default %d",
+ eOnExitMode_SHOWMSG, eOnExitMode_LASTITEM, DEFAULT_ON_EXIT);
+ n = DEFAULT_ON_EXIT;
+ }
+ m_nOnExit = n;
+ return true;
+ }
+
+ // Brightness
+ if(!strcasecmp(szName, "Brightness")) {
+ int n = atoi(szValue);
+ if ((n < 0) || (n > 2)) {
+ esyslog("targaVFD: Brightness must be between 0 and 2; using default %d",
+ DEFAULT_BRIGHTNESS);
+ n = DEFAULT_BRIGHTNESS;
+ }
+ m_nBrightness = 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("targaVFD: Font '%s' not found; using default %s",
+ szValue, DEFAULT_FONT);
+ strncpy(m_szFont,DEFAULT_FONT,sizeof(m_szFont));
+ return true;
+ }
+
+ // Two Line Mode
+ if(!strcasecmp(szName, "TwoLineMode")) {
+ int n = atoi(szValue);
+ if ((n != 0) && (n != 1))
+ {
+ esyslog("targaVFD: TwoLineMode must be 0 or 1. using default %d",
+ DEFAULT_TWO_LINE_MODE );
+ n = DEFAULT_TWO_LINE_MODE;
+ }
+
+ if (n) {
+ m_bTwoLineMode = 1;
+ } else {
+ m_bTwoLineMode = 0;
+ }
+ return true;
+ }
+ //Unknow parameter
+ return false;
+}
+
+
+// --- cVFDMenuSetup --------------------------------------------------------
+void cVFDMenuSetup::Store(void)
+{
+ theSetup = m_tmpSetup;
+
+ SetupStore("OnExit", theSetup.m_nOnExit);
+ SetupStore("Brightness", theSetup.m_nBrightness);
+ SetupStore("Font", theSetup.m_szFont);
+ SetupStore("TwoLineMode",theSetup.m_bTwoLineMode);
+}
+
+cVFDMenuSetup::cVFDMenuSetup(cVFDWatch* pDev)
+: m_tmpSetup(theSetup)
+, m_pDev(pDev)
+{
+ SetSection(tr("targavfd"));
+
+ cFont::GetAvailableFontNames(&fontNames);
+ fontNames.Insert(strdup(DEFAULT_FONT));
+ fontIndex = max(0, fontNames.Find(m_tmpSetup.m_szFont));
+
+ Add(new cMenuEditIntItem (tr("Brightness"),
+ &m_tmpSetup.m_nBrightness,
+ 0, 2));
+
+ Add(new cMenuEditStraItem(tr("Default font"),
+ &fontIndex, fontNames.Size(), &fontNames[0]));
+
+ Add(new cMenuEditBoolItem(tr("Render mode"),
+ &m_tmpSetup.m_bTwoLineMode,
+ tr("Single line"), tr("Dual lines")));
+
+ static const char * szExitModes[eOnExitMode_LASTITEM];
+ szExitModes[eOnExitMode_SHOWMSG] = tr("Do nothing");
+ szExitModes[eOnExitMode_SHOWCLOCK] = tr("Showing clock");
+ szExitModes[eOnExitMode_BLANKSCREEN] = tr("Turning display off");
+ szExitModes[eOnExitMode_NEXTTIMER] = tr("Show next timer");
+
+ Add(new cMenuEditStraItem (tr("Exit mode"),
+ &m_tmpSetup.m_nOnExit,
+ memberof(szExitModes), szExitModes));
+}
+
+eOSState cVFDMenuSetup::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_tmpSetup.m_bTwoLineMode != theSetup.m_bTwoLineMode) {
+ m_pDev->SetFont(m_tmpSetup.m_szFont, m_tmpSetup.m_bTwoLineMode);
+ }
+ }
+ return cMenuSetupPage::ProcessKey(nKey);
+}
+
+
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..9b74e5e
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,69 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#ifndef __VFD_SETUP_H___
+#define __VFD_SETUP_H___
+
+#include <vdr/menuitems.h>
+#define memberof(x) (sizeof(x)/sizeof(*x))
+
+enum eOnExitMode {
+ eOnExitMode_SHOWMSG /**< Do nothing - just leave the "last" message there */
+ ,eOnExitMode_SHOWCLOCK /**< Show the big clock */
+ ,eOnExitMode_BLANKSCREEN /**< Blank the device completely */
+ ,eOnExitMode_NEXTTIMER /**< Show next active timer */
+ ,eOnExitMode_LASTITEM
+};
+
+struct cVFDSetup
+{
+ int m_nOnExit;
+ int m_nBrightness;
+
+ const int m_cWidth;
+ const int m_cHeight;
+
+ char m_szFont[256];
+
+ int m_bTwoLineMode; /** enable two line mode */
+
+ cVFDSetup(void);
+ cVFDSetup(const cVFDSetup& x);
+ cVFDSetup& operator = (const cVFDSetup& x);
+
+ /// Parse our own setup parameters and store their values.
+ bool SetupParse(const char *szName, const char *szValue);
+
+};
+
+class cVFDWatch;
+class cVFDMenuSetup
+ :public cMenuSetupPage
+{
+ cVFDSetup m_tmpSetup;
+ cVFDWatch* m_pDev;
+ cStringList fontNames;
+ int fontIndex;
+protected:
+ virtual void Store(void);
+ virtual eOSState ProcessKey(eKeys nKey);
+public:
+ cVFDMenuSetup(cVFDWatch* pDev);
+};
+
+
+/// The exported one and only Stored setup data
+extern cVFDSetup theSetup;
+
+#endif //__VFD_SETUP_H___
+
diff --git a/status.c b/status.c
new file mode 100644
index 0000000..115d238
--- /dev/null
+++ b/status.c
@@ -0,0 +1,135 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#include <stdint.h>
+#include <time.h>
+#include <vdr/eitscan.h>
+
+#include "watch.h"
+#include "status.h"
+
+//#define MOREDEBUGMSG
+
+// ---
+cVFDStatusMonitor::cVFDStatusMonitor(cVFDWatch* pDev)
+: m_pDev(pDev)
+{
+
+}
+
+void cVFDStatusMonitor::ChannelSwitch(const cDevice *pDevice, int nChannelNumber)
+{
+ if (nChannelNumber > 0
+ && pDevice->IsPrimaryDevice()
+ && !EITScanner.UsesDevice(pDevice)
+ && (nChannelNumber == cDevice::CurrentChannel()))
+ {
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: channel switched to %d on DVB %d", nChannelNumber, pDevice->CardIndex());
+#endif
+ m_pDev->Channel(nChannelNumber);
+ }
+}
+
+void cVFDStatusMonitor::SetVolume(int Volume, bool Absolute)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: SetVolume %d %d", Volume, Absolute);
+#endif
+ m_pDev->Volume(Volume,Absolute);
+}
+
+void cVFDStatusMonitor::Recording(const cDevice *pDevice, const char *szName, const char *szFileName, bool bOn)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: Recording %d %s", pDevice->CardIndex(), szName);
+#endif
+ m_pDev->Recording(pDevice,szName,szFileName,bOn);
+}
+
+void cVFDStatusMonitor::Replaying(const cControl *pControl, const char *szName, const char *szFileName, bool bOn)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: Replaying %s", szName);
+#endif
+ m_pDev->Replaying(pControl,szName,szFileName,bOn);
+}
+
+void cVFDStatusMonitor::OsdClear(void)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: OsdClear");
+#endif
+ m_pDev->OsdClear();
+}
+
+void cVFDStatusMonitor::OsdTitle(const char *Title)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: OsdTitle '%s'", Title);
+#endif
+ m_pDev->OsdTitle(Title);
+}
+
+void cVFDStatusMonitor::OsdStatusMessage(const char *szMessage)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: OsdStatusMessage '%s'", szMessage ? szMessage : "NULL");
+#endif
+ m_pDev->OsdStatusMessage(szMessage);
+}
+
+void cVFDStatusMonitor::OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue)
+{
+#ifdef unusedMOREDEBUGMSG
+ dsyslog("targaVFD: OsdHelpKeys %s - %s - %s - %s", Red, Green, Yellow, Blue);
+#endif
+}
+
+void cVFDStatusMonitor::OsdCurrentItem(const char *szText)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: OsdCurrentItem %s", szText);
+#endif
+ m_pDev->OsdCurrentItem(szText);
+}
+
+void cVFDStatusMonitor::OsdTextItem(const char *Text, bool Scroll)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: OsdTextItem %s %d", Text, Scroll);
+#endif
+}
+
+void cVFDStatusMonitor::OsdChannel(const char *Text)
+{
+#ifdef MOREDEBUGMSG
+ dsyslog("targaVFD: OsdChannel %s", Text);
+#endif
+}
+
+void cVFDStatusMonitor::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("targaVFD: 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..7602c41
--- /dev/null
+++ b/status.h
@@ -0,0 +1,42 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#ifndef __VFD_STATUS__H
+#define __VFD_STATUS__H
+
+#include "vfd.h"
+#include <vdr/status.h>
+
+class cVFDWatch;
+
+class cVFDStatusMonitor : public cStatus {
+ cVFDWatch* m_pDev;
+ public:
+ cVFDStatusMonitor(cVFDWatch* pDev);
+ protected:
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+ virtual void Recording(const cDevice *pDevice, const char *szName, const char *szFileName, bool bOn);
+ virtual void Replaying(const cControl *pControl, const char *szName, const char *szFileName, bool bOn);
+ virtual void SetVolume(int Volume, bool Absolute);
+ virtual void OsdClear(void);
+ virtual void OsdTitle(const char *Title);
+ virtual void OsdStatusMessage(const char *Message);
+ virtual void OsdHelpKeys(const char *Red, const char *Green, const char *Yellow, const char *Blue);
+ virtual void OsdCurrentItem(const char *Text);
+ virtual void OsdTextItem(const char *Text, bool Scroll);
+ virtual void OsdChannel(const char *Text);
+ virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle);
+};
+
+#endif
+
diff --git a/targavfd.c b/targavfd.c
new file mode 100644
index 0000000..5b7bfc8
--- /dev/null
+++ b/targavfd.c
@@ -0,0 +1,364 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#include <vdr/plugin.h>
+#include <getopt.h>
+#include <string.h>
+
+#include "vfd.h"
+#include "watch.h"
+#include "status.h"
+#include "setup.h"
+
+static const char *VERSION = "0.0.3";
+
+class cPluginTargaVFD : public cPlugin {
+private:
+ cVFDStatusMonitor *statusMonitor;
+ cVFDWatch m_dev;
+ bool m_bSuspend;
+ char* m_szIconHelpPage;
+protected:
+ bool resume();
+ bool suspend();
+
+ const char* SVDRPCommandOn(const char *Option, int &ReplyCode);
+ const char* SVDRPCommandOff(const char *Option, int &ReplyCode);
+ const char* SVDRPCommandIcon(const char *Option, int &ReplyCode);
+
+public:
+ cPluginTargaVFD(void);
+ virtual ~cPluginTargaVFD();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return tr("Control a targa vfd"); }
+ 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);
+ };
+
+cPluginTargaVFD::cPluginTargaVFD(void)
+{
+ m_bSuspend = true;
+ statusMonitor = NULL;
+ m_szIconHelpPage = NULL;
+}
+
+cPluginTargaVFD::~cPluginTargaVFD()
+{
+ //Cleanup if'nt throw housekeeping
+ if(statusMonitor) {
+ delete statusMonitor;
+ statusMonitor = NULL;
+ }
+
+ if(m_szIconHelpPage) {
+ free(m_szIconHelpPage);
+ m_szIconHelpPage = NULL;
+ }
+}
+
+const char *cPluginTargaVFD::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return "";
+}
+
+bool cPluginTargaVFD::ProcessArgs(int argc, char *argv[])
+{
+ return true;
+}
+
+bool cPluginTargaVFD::Initialize(void)
+{
+ // Initialize any background activities the plugin shall perform.
+ return true;
+}
+
+bool cPluginTargaVFD::resume() {
+
+ if(m_bSuspend
+ && m_dev.open()) {
+ m_bSuspend = false;
+ return true;
+ }
+ return false;
+}
+
+bool cPluginTargaVFD::suspend() {
+ if(!m_bSuspend) {
+ m_dev.close();
+ m_bSuspend = true;
+ return true;
+ }
+ return false;
+}
+
+bool cPluginTargaVFD::Start(void)
+{
+ if(resume()) {
+ statusMonitor = new cVFDStatusMonitor(&m_dev);
+ if(NULL == statusMonitor){
+ esyslog("targaVFD: can't create cVFDStatusMonitor!");
+ return (false);
+ }
+ }
+ return true;
+}
+
+void cPluginTargaVFD::Stop(void)
+{
+ if(statusMonitor) {
+ delete statusMonitor;
+ statusMonitor = NULL;
+ }
+ m_dev.close();
+}
+
+void cPluginTargaVFD::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+}
+
+void cPluginTargaVFD::MainThreadHook(void)
+{
+ // Perform actions in the context of the main program thread.
+ // WARNING: Use with great care - see PLUGINS.html!
+}
+
+cString cPluginTargaVFD::Active(void)
+{
+ // Return a message string if shutdown should be postponed
+ return NULL;
+}
+
+time_t cPluginTargaVFD::WakeupTime(void)
+{
+ // Return custom wakeup time for shutdown script
+ return 0;
+}
+
+cOsdObject *cPluginTargaVFD::MainMenuAction(void)
+{
+ return NULL;
+}
+
+cMenuSetupPage *cPluginTargaVFD::SetupMenu(void)
+{
+ return new cVFDMenuSetup(&m_dev);
+}
+
+bool cPluginTargaVFD::SetupParse(const char *szName, const char *szValue)
+{
+ return theSetup.SetupParse(szName,szValue);
+}
+
+bool cPluginTargaVFD::Service(const char *Id, void *Data)
+{
+ // Handle custom service requests from other plugins
+ return false;
+}
+
+const char* cPluginTargaVFD::SVDRPCommandOn(const char *Option, int &ReplyCode)
+{
+ if(!m_bSuspend) {
+ ReplyCode=251;
+ return "driver already resumed";
+ }
+ if(resume()) {
+ ReplyCode=250;
+ return "driver resumed";
+ } else {
+ ReplyCode=554;
+ return "driver could not resumed";
+ }
+}
+
+const char* cPluginTargaVFD::SVDRPCommandOff(const char *Option, int &ReplyCode)
+{
+ if(suspend()) {
+ ReplyCode=250;
+ return "driver suspended";
+ } else {
+ ReplyCode=251;
+ return "driver already suspended";
+ }
+}
+
+static const struct {
+ unsigned int nIcon;
+ const char* szIcon;
+} icontable[] = {
+ { eIconPLAY , "Play" },
+ { eIconPAUSE , "Pause" },
+ { eIconRECORD , "Record" },
+ { eIconMESSAGE , "Msg" },
+ { eIconMSGAT , "MsgAt" },
+ { eIconMUTE , "Mute" },
+ { eIconWLAN1 , "WLAN1" },
+ { eIconWLAN2 , "WLAN2" },
+ { eIconWLAN3 , "WLAN3" },
+ { eIconWLAN4 , "WLAN4" },
+ { eIconVOLUME , "Volume" },
+ { eIconVOL1 , "Level1" },
+ { eIconVOL2 , "Level2" },
+ { eIconVOL3 , "Level3" },
+ { eIconVOL4 , "Level4" },
+ { eIconVOL5 , "Level5" },
+ { eIconVOL6 , "Level6" },
+ { eIconVOL7 , "Level7" },
+ { eIconVOL8 , "Level8" },
+ { eIconVOL9 , "Level9" },
+ { eIconVOL10 , "Level10" },
+ { eIconVOL11 , "Level11" },
+ { eIconVOL12 , "Level12" },
+ { eIconVOL13 , "Level13" },
+ { eIconVOL14 , "Level14" }
+};
+
+const char* cPluginTargaVFD::SVDRPCommandIcon(const char *Option, int &ReplyCode)
+{
+ if(m_bSuspend) {
+ ReplyCode=251;
+ return "driver suspended";
+ }
+ if( Option && strlen(Option) < 256) {
+ char* request = strdup(Option);
+ char* cmd = NULL;
+ if( request ) {
+ char* tmp = request;
+ eIconState m = eIconStateQuery;
+ cmd = strtok_r(request, " ", &tmp);
+ if(cmd) {
+ char* param = strtok_r(0, " ", &tmp);
+ if(param) {
+ if(!strcasecmp(param,"ON")) {
+ m = eIconStateOn;
+ } else if(!strcasecmp(param,"OFF")) {
+ m = eIconStateOff;
+ } else if(!strcasecmp(param,"AUTO")) {
+ m = eIconStateAuto;
+ } else {
+ ReplyCode=501;
+ free(request);
+ return "unknown icon state";
+ }
+ }
+ }
+
+ ReplyCode=501;
+ const char* szReplay = "unknown icon title";
+ if(cmd) {
+ unsigned int i;
+ for(i = 0; i < (sizeof(icontable)/sizeof(*icontable));++i)
+ {
+ if(0 == strcasecmp(cmd,icontable[i].szIcon))
+ {
+ eIconState r = m_dev.ForceIcon(icontable[i].nIcon, m);
+ switch(r) {
+ case eIconStateAuto:
+ ReplyCode=250;
+ szReplay = "icon state 'auto'";
+ break;
+ case eIconStateOn:
+ ReplyCode=251;
+ szReplay = "icon state 'on'";
+ break;
+ case eIconStateOff:
+ ReplyCode=252;
+ szReplay = "icon state 'off'";
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ }
+ free(request);
+ return szReplay;
+ }
+ }
+ ReplyCode=501;
+ return "wrong parameter";
+}
+
+cString cPluginTargaVFD::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ ReplyCode=501;
+ const char* szReplay = "unknown command";
+
+ if(!strcasecmp(Command, "ON")) {
+ szReplay = SVDRPCommandOn(Option,ReplyCode);
+ } else if(!strcasecmp(Command, "OFF")) {
+ szReplay = SVDRPCommandOff(Option,ReplyCode);
+ } else if(!strcasecmp(Command, "ICON")) {
+ szReplay = SVDRPCommandIcon(Option,ReplyCode);
+ }
+
+ dsyslog("targaVFD: SVDRP %s %s - %d (%s)", Command, Option, ReplyCode, szReplay);
+ return szReplay;
+}
+
+const char **cPluginTargaVFD::SVDRPHelpPages(void)
+{
+ if(!m_szIconHelpPage) {
+ unsigned int i,l,k;
+ for(i = 0,l = 0, k = (sizeof(icontable)/sizeof(*icontable)); i < k;++i) {
+ l += strlen(icontable[i].szIcon);
+ l += 2;
+ }
+ l += 80;
+
+ m_szIconHelpPage = (char*) calloc(l + 1,1);
+ if(m_szIconHelpPage) {
+ strncat(m_szIconHelpPage, "ICON [name] [on|off|auto]\n Force state of icon. Names of icons are:", l);
+ for(i = 0; i < k;++i) {
+ if((i % 7) == 0) {
+ strncat(m_szIconHelpPage, "\n ", l - (strlen(m_szIconHelpPage) + 5));
+ } else {
+ strncat(m_szIconHelpPage, ",", l - (strlen(m_szIconHelpPage) + 1));
+ }
+ strncat(m_szIconHelpPage, icontable[i].szIcon,
+ l - (strlen(m_szIconHelpPage) + strlen(icontable[i].szIcon)));
+ }
+ }
+ }
+
+ // Return help text for SVDRP commands this plugin implements
+ static const char *HelpPages[] = {
+ "ON\n"
+ " Resume driver of display.\n",
+ "OFF\n"
+ " Suspend driver of display.\n",
+ "ICON [name] [on|off|auto]\n"
+ " Force state of icon.\n",
+ NULL
+ };
+ if(m_szIconHelpPage)
+ HelpPages[2] = m_szIconHelpPage;
+ return HelpPages;
+}
+VDRPLUGINCREATOR(cPluginTargaVFD); // Don't touch this!
diff --git a/vfd.c b/vfd.c
new file mode 100644
index 0000000..1670eab
--- /dev/null
+++ b/vfd.c
@@ -0,0 +1,472 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and 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 "vfd.h"
+
+static const byte ICON_PLAY = 0x00; //Play
+static const byte ICON_PAUSE = 0x01; //Pause
+static const byte ICON_RECORD = 0x02; //Record
+static const byte ICON_MESSAGE = 0x03; //Message symbol (without the inner @)
+static const byte ICON_MSGAT = 0x04; //Message @
+static const byte ICON_MUTE = 0x05; //Mute
+static const byte ICON_WLAN1 = 0x06; //WLAN (tower base)
+static const byte ICON_WLAN2 = 0x07; //WLAN strength (1 of 3)
+static const byte ICON_WLAN3 = 0x08; //WLAN strength (2 of 3)
+static const byte ICON_WLAN4 = 0x09; //WLAN strength (3 of 3)
+static const byte ICON_VOLUME = 0x0A; //Volume (the word)
+static const byte ICON_VOL1 = 0x0B; //Volume level 1 of 14
+static const byte ICON_VOL2 = 0x0C; //Volume level 2 of 14
+static const byte ICON_VOL3 = 0x0D; //Volume level 3 of 14
+static const byte ICON_VOL4 = 0x0E; //Volume level 4 of 14
+static const byte ICON_VOL5 = 0x0F; //Volume level 5 of 14
+static const byte ICON_VOL6 = 0x10; //Volume level 6 of 14
+static const byte ICON_VOL7 = 0x11; //Volume level 7 of 14
+static const byte ICON_VOL8 = 0x12; //Volume level 8 of 14
+static const byte ICON_VOL9 = 0x13; //Volume level 9 of 14
+static const byte ICON_VOL10 = 0x14; //Volume level 10 of 14
+static const byte ICON_VOL11 = 0x15; //Volume level 11 of 14
+static const byte ICON_VOL12 = 0x16; //Volume level 12 of 14
+static const byte ICON_VOL13 = 0x17; //Volume level 13 of 14
+static const byte ICON_VOL14 = 0x18; //Volume level 14 of 14
+
+static const byte STATE_OFF = 0x00; //Symbol off
+static const byte STATE_ON = 0x01; //Symbol on
+static const byte STATE_ONHIGH = 0x02; //Symbol on, high intensity, can only be used with the volume symbols
+
+static const byte CMD_PREFIX = 0x1b;
+static const byte CMD_SETCLOCK = 0x00; //Actualize the time of the display
+static const byte CMD_SMALLCLOCK = 0x01; //Display small clock on display
+static const byte CMD_BIGCLOCK = 0x02; //Display big clock on display
+static const byte CMD_SETSYMBOL = 0x30; //Enable or disable symbol
+static const byte CMD_SETDIMM = 0x40; //Set the dimming level of the display
+static const byte CMD_RESET = 0x50; //Reset all configuration data to default and clear
+static const byte CMD_SETRAM = 0x60; //Set the actual graphics RAM offset for next data write
+static const byte CMD_SETPIXEL = 0x70; //Write pixel data to RAM of the display
+static const byte CMD_TEST1 = 0xf0; //Show vertical test pattern
+static const byte CMD_TEST2 = 0xf1; //Show horizontal test pattern
+
+static const byte TIME_12 = 0x00; //12 hours format
+static const byte TIME_24 = 0x01; //24 hours format
+
+static const byte BRIGHT_OFF = 0x00; //Display off
+static const byte BRIGHT_DIMM = 0x01; //Display dimmed
+static const byte BRIGHT_FULL = 0x02; //Display full brightness
+
+cVFDQueue::cVFDQueue() {
+ hid = NULL;
+ bInit = false;
+}
+
+cVFDQueue::~cVFDQueue() {
+ cVFDQueue::close();
+}
+
+bool cVFDQueue::open()
+{
+ HIDInterfaceMatcher matcher = { 0x19c2, 0x6a11, NULL, NULL, 0 };
+ hid_return ret;
+
+ /* see include/debug.h for possible values */
+ hid_set_debug(HID_DEBUG_NONE);
+ hid_set_debug_stream(0);
+ /* passed directly to libusb */
+ hid_set_usb_debug(0);
+
+ ret = hid_init();
+ if (ret != HID_RET_SUCCESS) {
+ esyslog("targaVFD: init - %s (%d)", hiderror(ret), ret);
+ return false;
+ }
+ bInit = true;
+
+ hid = hid_new_HIDInterface();
+ if (hid == 0) {
+ esyslog("targaVFD: hid_new_HIDInterface() failed, out of memory?\n");
+ return false;
+ }
+
+ ret = hid_force_open(hid, 0, &matcher, 3);
+ if (ret != HID_RET_SUCCESS) {
+ esyslog("targaVFD: open - %s (%d)", hiderror(ret), ret);
+ hid_close(hid);
+ hid_delete_HIDInterface(&hid);
+ hid = 0;
+ return false;
+ }
+
+ while (!empty()) {
+ pop();
+ }
+ //ret = hid_write_identification(stdout, hid);
+ //if (ret != HID_RET_SUCCESS) {
+ // esyslog("targaVFD: write_identification %s (%d)", hiderror(ret), ret);
+ // return false;
+ //}
+ return true;
+}
+
+void cVFDQueue::close() {
+ hid_return ret;
+ if (hid != 0) {
+ ret = hid_close(hid);
+ if (ret != HID_RET_SUCCESS) {
+ esyslog("targaVFD: close - %s (%d)", hiderror(ret), ret);
+ }
+
+ hid_delete_HIDInterface(&hid);
+ hid = 0;
+ }
+ if(bInit) {
+ ret = hid_cleanup();
+ if (ret != HID_RET_SUCCESS) {
+ esyslog("targaVFD: cleanup - %s (%d)", hiderror(ret), ret);
+ }
+ bInit = false;
+ }
+}
+
+void cVFDQueue::QueueCmd(const byte & cmd) {
+ this->push(CMD_PREFIX);
+ this->push(cmd);
+}
+
+void cVFDQueue::QueueData(const byte & data) {
+ this->push(data);
+}
+
+bool cVFDQueue::QueueFlush() {
+
+ if(empty())
+ return true;
+ if(!isopen()) {
+ return false;
+ }
+
+ int const PATH_OUT[1] = { 0xff7f0004 };
+ char buf[64];
+ hid_return ret;
+
+ while (!empty()) {
+ buf[0] = (char) std::min((size_t)63,size());
+ for(unsigned int i = 0;i < 63 && !empty();++i) {
+ buf[i+1] = (char) front(); //the first element in the queue
+ pop(); //remove the first element of the queue
+ }
+ ret = hid_set_output_report(hid, PATH_OUT, sizeof(PATH_OUT), buf, (buf[0] + 1));
+ if (ret != HID_RET_SUCCESS) {
+ esyslog("targaVFD: set_output_report - %s (%d)", hiderror(ret), ret);
+ while (!empty()) {
+ pop();
+ }
+ cVFDQueue::close();
+ return false;
+ }
+ }
+ return true;
+}
+
+const char *cVFDQueue::hiderror(hid_return ret) const
+{
+ switch(ret) {
+ case HID_RET_SUCCESS:
+ return "success";
+ case HID_RET_INVALID_PARAMETER:
+ return "invalid parameter";
+ case HID_RET_NOT_INITIALISED:
+ return "not initialized";
+ case HID_RET_ALREADY_INITIALISED:
+ return "hid_init() already called";
+ case HID_RET_FAIL_FIND_BUSSES:
+ return "failed to find any USB busses";
+ case HID_RET_FAIL_FIND_DEVICES:
+ return "failed to find any USB devices";
+ case HID_RET_FAIL_OPEN_DEVICE:
+ return "failed to open device";
+ case HID_RET_DEVICE_NOT_FOUND:
+ return "device not found";
+ case HID_RET_DEVICE_NOT_OPENED:
+ return "device not yet opened";
+ case HID_RET_DEVICE_ALREADY_OPENED:
+ return "device already opened";
+ case HID_RET_FAIL_CLOSE_DEVICE:
+ return "could not close device";
+ case HID_RET_FAIL_CLAIM_IFACE:
+ return "failed to claim interface; is another driver using it?";
+ case HID_RET_FAIL_DETACH_DRIVER:
+ return "failed to detach kernel driver";
+ case HID_RET_NOT_HID_DEVICE:
+ return "not recognized as a HID device";
+ case HID_RET_HID_DESC_SHORT:
+ return "HID interface descriptor too short";
+ case HID_RET_REPORT_DESC_SHORT:
+ return "HID report descriptor too short";
+ case HID_RET_REPORT_DESC_LONG:
+ return "HID report descriptor too long";
+ case HID_RET_FAIL_ALLOC:
+ return "failed to allocate memory";
+ case HID_RET_OUT_OF_SPACE:
+ return "no space left in buffer";
+ case HID_RET_FAIL_SET_REPORT:
+ return "failed to set report";
+ case HID_RET_FAIL_GET_REPORT:
+ return "failed to get report";
+ case HID_RET_FAIL_INT_READ:
+ return "interrupt read failed";
+ case HID_RET_NOT_FOUND:
+ return "not found";
+#ifdef HID_RET_TIMEOUT
+ case HID_RET_TIMEOUT:
+ return "timeout";
+#endif
+ }
+ return "unknown error";
+}
+
+cVFD::cVFD()
+{
+ this->pFont = NULL;
+ this->lastIconState = 0;
+}
+
+cVFD::~cVFD() {
+ this->close();
+}
+
+
+/**
+ * Initialize the driver.
+ * \retval 0 Success.
+ * \retval <0 Error.
+ */
+bool cVFD::open()
+{
+ if(!SetFont(theSetup.m_szFont,theSetup.m_bTwoLineMode)) {
+ return false;
+ }
+ if(!cVFDQueue::open()) {
+ return false;
+ }
+
+ isyslog("targaVFD: open Device successful");
+
+ /* Make sure the frame buffer is there... */
+ this->framebuf = new cVFDBitmap(theSetup.m_cWidth,theSetup.m_cHeight);
+ if (this->framebuf == NULL) {
+ esyslog("targaVFD: unable to allocate framebuffer");
+ return false;
+ }
+
+ /* Make sure the framebuffer backing store is there... */
+ this->backingstore = new cVFDBitmap(theSetup.m_cWidth,theSetup.m_cHeight);
+ if (this->backingstore == NULL) {
+ esyslog("targaVFD: unable to create framebuffer backing store");
+ return false;
+ }
+ backingstore->SetPixel(0,0);//make dirty
+
+ this->lastIconState = 0;
+
+ QueueCmd(CMD_RESET);
+ //Brightness(theSetup.m_nBrightness);
+ if(QueueFlush()) {
+ dsyslog("targaVFD: init() done");
+ return true;
+ }
+ return false;
+}
+
+/*
+ * turning display off
+ */
+bool cVFD::SendCmdShutdown() {
+ QueueCmd(CMD_RESET);
+ return QueueFlush();
+}
+
+inline byte toBCD(int x){
+ return (byte)(((x) / 10 * 16) + ((x) % 10));
+}
+
+/*
+ * Show the big clock. We need to set it to the current time, then it just
+ * keeps counting automatically.
+ */
+bool cVFD::SendCmdClock() {
+
+ time_t tt;
+ struct tm l;
+
+ tt = time(NULL);
+ localtime_r(&tt, &l);
+
+ // Set time
+ QueueCmd(CMD_SETCLOCK);
+ QueueData(toBCD(l.tm_min));
+ QueueData(toBCD(l.tm_hour));
+
+ // Show it
+ QueueCmd(CMD_BIGCLOCK);
+ QueueData(TIME_24);
+ return QueueFlush();
+}
+
+/**
+ * Close the driver (do necessary clean-up).
+ */
+void cVFD::close()
+{
+ cVFDQueue::close();
+
+ if(pFont) {
+ delete pFont;
+ pFont = NULL;
+ }
+ if(framebuf) {
+ delete framebuf;
+ framebuf = NULL;
+ }
+ if(backingstore) {
+ delete backingstore;
+ backingstore = NULL;
+ }
+
+ dsyslog("targaVFD: close() done");
+}
+
+
+/**
+ * Clear the screen.
+ */
+void cVFD::clear()
+{
+ if(framebuf)
+ framebuf->clear();
+}
+
+
+/**
+ * Flush data on screen to the LCD.
+ */
+bool cVFD::flush()
+{
+ /*
+ * The display only provides for a complete screen refresh. If
+ * nothing has changed, don't refresh.
+ */
+ if (!((*backingstore) == (*framebuf))) {
+ /* send buffer for one command or display data */
+ const uchar* fb = framebuf->getBitmap();
+ int bytes = framebuf->Width() * framebuf->Height() / 8;
+ int width = framebuf->Width();
+ QueueCmd(CMD_SETRAM);
+ QueueData(0);
+ QueueCmd(CMD_SETPIXEL);
+ QueueData(bytes);
+ for (int i=0;i<width;i+=1)
+ {
+ QueueData(*(fb + i));
+ QueueData(*(fb + (i + width)));
+ }
+ /* Update the backing store. */
+ (*backingstore) = (*framebuf);
+ }
+ return QueueFlush();
+}
+
+
+/**
+ * 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 cVFD::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.
+ */
+void cVFD::icons(unsigned int state)
+{
+ for(unsigned i = 0; i <= 0x18; i++) {
+ if((state & (1 << i)) != (lastIconState & (1 << i)))
+ {
+ QueueCmd(CMD_SETSYMBOL);
+ QueueData(i);
+ QueueData((state & (1 << i)) ? STATE_ON : STATE_OFF );
+ }
+ }
+ lastIconState = state;
+}
+
+/**
+ * Sets the brightness of the display.
+ *
+ * \param nBrightness The value the brightness (0 = off
+ * 1 = half brightness; 2 = highest brightness).
+ */
+void cVFD::Brightness(int nBrightness)
+{
+ if (nBrightness < 0) {
+ nBrightness = 0;
+ } else if (nBrightness > 2) {
+ nBrightness = 2;
+ }
+ this->QueueCmd(CMD_SETDIMM);
+ this->QueueData((byte) (nBrightness));
+}
+
+bool cVFD::SetFont(const char *szFont, int bTwoLineMode) {
+
+ cVFDFont* tmpFont = NULL;
+
+ cString sFileName = cFont::GetFontFileName(szFont);
+ if(!isempty(sFileName))
+ {
+ if (bTwoLineMode)
+ {
+ tmpFont = new cVFDFont(sFileName,6,8);
+ } else {
+ tmpFont = new cVFDFont(sFileName,12,11);
+ }
+ } else {
+ esyslog("targaVFD: unable to find font '%s'",szFont);
+ }
+ if(tmpFont) {
+ if(pFont) {
+ delete pFont;
+ }
+ pFont = tmpFont;
+ return true;
+ }
+ return false;
+}
diff --git a/vfd.h b/vfd.h
new file mode 100644
index 0000000..8486810
--- /dev/null
+++ b/vfd.h
@@ -0,0 +1,100 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#ifndef __VFD_H_
+#define __VFD_H_
+
+#include <queue>
+#include <hid.h>
+#include "bitmap.h"
+
+enum eIcons {
+ eIconOff = 0,
+ eIconPLAY = 1 << 0x00, // Play
+ eIconPAUSE = 1 << 0x01, // Pause
+ eIconRECORD = 1 << 0x02, // Record
+ eIconMESSAGE = 1 << 0x03, // Message symbol (without the inner @)
+ eIconMSGAT = 1 << 0x04, // Message @
+ eIconMUTE = 1 << 0x05, // Mute
+ eIconWLAN1 = 1 << 0x06, // WLAN (tower base)
+ eIconWLAN2 = 1 << 0x07, // WLAN strength (1 of 3)
+ eIconWLAN3 = 1 << 0x08, // WLAN strength (2 of 3)
+ eIconWLAN4 = 1 << 0x09, // WLAN strength (3 of 3)
+ eIconVOLUME = 1 << 0x0A, // Volume (the word)
+ eIconVOL1 = 1 << 0x0B, // Volume level 1 of 14
+ eIconVOL2 = 1 << 0x0C, // Volume level 2 of 14
+ eIconVOL3 = 1 << 0x0D, // Volume level 3 of 14
+ eIconVOL4 = 1 << 0x0E, // Volume level 4 of 14
+ eIconVOL5 = 1 << 0x0F, // Volume level 5 of 14
+ eIconVOL6 = 1 << 0x10, // Volume level 6 of 14
+ eIconVOL7 = 1 << 0x11, // Volume level 7 of 14
+ eIconVOL8 = 1 << 0x12, // Volume level 8 of 14
+ eIconVOL9 = 1 << 0x13, // Volume level 9 of 14
+ eIconVOL10 = 1 << 0x14, // Volume level 10 of 14
+ eIconVOL11 = 1 << 0x15, // Volume level 11 of 14
+ eIconVOL12 = 1 << 0x16, // Volume level 12 of 14
+ eIconVOL13 = 1 << 0x17, // Volume level 13 of 14
+ eIconVOL14 = 1 << 0x18 // Volume level 14 of 14
+};
+
+class cVFDFont;
+
+class cVFDQueue : public std::queue<byte> {
+ HIDInterface* hid;
+ bool bInit;
+public:
+ cVFDQueue();
+ virtual ~cVFDQueue();
+ virtual bool open();
+ virtual void close();
+ virtual bool isopen() const { return hid != 0; }
+ void QueueCmd(const byte & cmd);
+ void QueueData(const byte & data);
+ bool QueueFlush();
+private:
+ const char *hiderror(hid_return ret) const;
+};
+
+class cVFD : public cVFDQueue {
+
+ cVFDFont* pFont;
+ /* framebuffer and backingstore for current contents */
+ cVFDBitmap* framebuf;
+ cVFDBitmap* backingstore;
+ unsigned int lastIconState;
+protected:
+
+ bool SendCmdClock();
+ bool SendCmdShutdown();
+ void Brightness(int nBrightness);
+public:
+ cVFD();
+ virtual ~cVFD();
+
+ virtual bool open();
+ virtual void close ();
+
+
+ void clear ();
+ int DrawText(int x, int y, const char* string);
+ bool flush ();
+
+ void icons(unsigned int state);
+ virtual bool SetFont(const char *szFont, int m_bTwoLineMode);
+};
+
+
+#endif
+
+
+
diff --git a/watch.c b/watch.c
new file mode 100644
index 0000000..179ae1d
--- /dev/null
+++ b/watch.c
@@ -0,0 +1,874 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and 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();
+ }
+};
+
+
+cVFDWatch::cVFDWatch()
+: cThread("targaVFD: watch thread")
+, m_bShutdown(false)
+{
+ m_nIconsForceOn = 0;
+ m_nIconsForceOff = 0;
+ m_nIconsForceMask = 0;
+
+ 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;
+
+ osdTitle = NULL;
+ osdItem = NULL;
+ osdMessage = NULL;
+
+ m_pControl = NULL;
+ replayTitle = NULL;
+ replayTitleLast = NULL;
+ replayTime = NULL;
+
+ currentTime = NULL;
+
+ m_eWatchMode = eLiveTV;
+
+ m_nScrollOffset = -1;
+ m_bScrollBackward = false;
+ m_bScrollNeeded = false;
+}
+
+cVFDWatch::~cVFDWatch()
+{
+ 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(osdTitle) {
+ delete osdTitle;
+ osdTitle = NULL;
+ }
+ if(osdItem) {
+ delete osdItem;
+ osdItem = NULL;
+ }
+ if(replayTitle) {
+ delete replayTitle;
+ replayTitle = NULL;
+ }
+ if(replayTime) {
+ delete replayTime;
+ replayTime = NULL;
+ }
+ if(currentTime) {
+ delete currentTime;
+ currentTime = NULL;
+ }
+}
+
+bool cVFDWatch::open() {
+ if(cVFD::open()) {
+ m_bShutdown = false;
+ m_bUpdateScreen = true;
+ Start();
+ return true;
+ }
+ return false;
+}
+
+void cVFDWatch::close() {
+
+ if(Running()) {
+ m_bShutdown = true;
+ usleep(500000);
+ Cancel();
+ }
+
+ if(this->isopen()) {
+ cTimer* t = Timers.GetNextActiveTimer();
+
+ switch(theSetup.m_nOnExit) {
+ case eOnExitMode_NEXTTIMER: {
+ isyslog("targaVFD: closing, show only next timer.");
+
+ this->clear();
+ if(t) {
+ struct tm l;
+ cString topic;
+ time_t tn = time(NULL);
+ time_t tt = t->StartTime();
+ localtime_r(&tt, &l);
+ if((tt - tn) > 86400) {
+ // next timer more then 24h
+ topic = cString::sprintf("%d. %02d:%02d %s", l.tm_mday, l.tm_hour, l.tm_min, t->File());
+ } else {
+ // next timer (today)
+ topic = cString::sprintf("%02d:%02d %s", l.tm_hour, l.tm_min, t->File());
+ }
+ this->DrawText(0,0,topic);
+ this->icons(eIconRECORD);
+ } else {
+ this->DrawText(0,0,tr("None active timer"));
+ this->icons(0);
+ }
+ this->flush();
+ break;
+ }
+ case eOnExitMode_SHOWMSG: {
+ isyslog("targaVFD: closing, leaving \"last\" message.");
+ break;
+ }
+ default:
+ case eOnExitMode_BLANKSCREEN: {
+ isyslog("targaVFD: closing, turning backlight off.");
+ SendCmdShutdown();
+ break;
+ }
+ case eOnExitMode_SHOWCLOCK: {
+ isyslog("targaVFD: closing, showing clock.");
+ SendCmdClock();
+ break;
+ }
+ }
+ }
+ cVFD::close();
+}
+
+void cVFDWatch::Action(void)
+{
+ unsigned int nLastIcons = -1;
+ int nBrightness = -1;
+
+ unsigned int n;
+ unsigned int nCnt = 0;
+
+ cTimeMs runTime;
+
+ for (;!m_bShutdown;++nCnt) {
+
+ LOCK_THREAD;
+
+ unsigned int nIcons = 0;
+ bool bFlush = false;
+ bool bReDraw = false;
+ if(m_bShutdown)
+ break;
+ else {
+ cMutexLooker m(mutex);
+ runTime.Set();
+
+ // every second the clock need updates.
+ if (theSetup.m_bTwoLineMode) {
+ if((0 == (nCnt % 5))) {
+ if(m_eWatchMode == eLiveTV) {
+ bReDraw = CurrentTime();
+ } else {
+ bReDraw = ReplayTime();
+ }
+ }
+ }
+
+ bFlush = RenderScreen(bReDraw);
+ 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 {
+ switch(ReplayMode()) {
+ case eReplayNone:
+ case eReplayPaused:
+ nIcons |= eIconPAUSE;
+ break;
+ default:
+ case eReplayPlay:
+ nIcons |= eIconPLAY;
+ break;
+ case eReplayBackward1:
+ case eReplayBackward2:
+ case eReplayBackward3:
+ break;
+ case eReplayForward1:
+ case eReplayForward2:
+ case eReplayForward3:
+ break;
+ }
+ }
+
+ for(n=0;n<memberof(m_nCardIsRecording);++n) {
+ if(0 != m_nCardIsRecording[n]) {
+ nIcons |= eIconRECORD;
+ break;
+ }
+ }
+
+ if(m_bVolumeMute) {
+ nIcons |= eIconMUTE;
+ } else {
+ nIcons |= eIconVOLUME;
+ const int nVolSteps = (MAXVOLUME/14);
+ nIcons |= (((1 << (m_nLastVolume / nVolSteps)) - 1) << 0x0B);
+ }
+
+ if(theSetup.m_nBrightness != nBrightness) {
+ nBrightness = theSetup.m_nBrightness;
+ Brightness(nBrightness);
+ }
+
+ //Force icon state (defined by svdrp)
+ nIcons &= ~(m_nIconsForceMask);
+ nIcons |= (m_nIconsForceOn);
+ nIcons &= ~(m_nIconsForceOff);
+
+ if(nIcons != nLastIcons) {
+ icons(nIcons);
+ nLastIcons = nIcons;
+ bFlush = true;
+ }
+
+ if(bFlush) {
+ flush();
+ }
+ }
+ int nDelay = 100 - runTime.Elapsed();
+ if(nDelay <= 10) {
+ nDelay = 10;
+ }
+ cCondWait::SleepMs(nDelay);
+ }
+ dsyslog("targaVFD: watch thread closed (pid=%d)", getpid());
+}
+
+bool cVFDWatch::RenderScreen(bool bReDraw) {
+ cString* scRender;
+ cString* scHeader = NULL;
+ bool bForce = m_bUpdateScreen;
+ if(osdMessage) {
+ scRender = osdMessage;
+ } else if(osdItem) {
+ scHeader = osdTitle;
+ scRender = osdItem;
+ } else if(m_eWatchMode == eLiveTV) {
+ scHeader = chName;
+ if(Program()) {
+ bForce = true;
+ }
+ if(chPresentTitle)
+ scRender = chPresentTitle;
+ else {
+ scHeader = currentTime;
+ scRender = chName;
+ }
+ } else {
+ if(Replay()) {
+ bForce = true;
+ }
+ scHeader = replayTime;
+ scRender = replayTitle;
+ }
+
+
+ if(bForce) {
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+ m_bScrollNeeded = true;
+ }
+ if(bForce || bReDraw || m_nScrollOffset > 0 || m_bScrollBackward) {
+ this->clear();
+ if(scRender) {
+
+ int iRet = -1;
+ if(theSetup.m_bTwoLineMode) {
+ iRet = this->DrawText(0 - m_nScrollOffset,8, *scRender);
+ } else {
+ iRet = this->DrawText(0 - m_nScrollOffset,0, *scRender);
+ }
+ if(m_bScrollNeeded) {
+ switch(iRet) {
+ case 0:
+ if(m_nScrollOffset <= 0) {
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+ m_bScrollNeeded = 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;
+ m_bScrollNeeded = false;
+ break;
+ }
+ }
+ }
+
+ if(scHeader && theSetup.m_bTwoLineMode) {
+ this->DrawText(0, 0, *scHeader);
+ }
+
+ m_bUpdateScreen = false;
+ return true;
+ }
+ return false;
+}
+
+bool cVFDWatch::CurrentTime() {
+ time_t ts = time(NULL);
+
+ if((ts / 60) != (tsCurrentLast / 60)) {
+
+ if(currentTime)
+ delete currentTime;
+
+ tsCurrentLast = ts;
+ currentTime = new cString(TimeString(ts));
+ return currentTime != NULL;
+ }
+ return false;
+}
+
+bool cVFDWatch::Replay() {
+
+ if(!replayTitleLast
+ || !replayTitle
+ || strcmp(*replayTitleLast,*replayTitle)) {
+ replayTitleLast = replayTitle;
+ return true;
+ }
+ return false;
+}
+
+void cVFDWatch::Replaying(const cControl * Control, const char * Name, const char *FileName, bool On)
+{
+ cMutexLooker m(mutex);
+ m_bUpdateScreen = true;
+ if (On)
+ {
+ m_pControl = (cControl *) Control;
+ m_eWatchMode = eReplayNormal;
+ if(replayTitle) {
+ delete replayTitle;
+ replayTitle = NULL;
+ }
+ 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
+ if (strlen(Name+i) > 0) { //if name isn't empty, then copy
+ replayTitle = new cString(skipspace(Name + i));
+ }
+ m_eWatchMode = eReplayMusic;
+ }
+ }
+ ///////////////////////////////////////////////////////////////////////
+ //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;
+ }
+ }
+ 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;
+ bFound = true;
+ }
+ else if (0 == strncmp(Name,"[audiocd] ",10)) {
+ replayTitle = new cString(Name + 10);
+ m_eWatchMode = eReplayAudioCD;
+ bFound = true;
+ }
+ if (!bFound) {
+ replayTitle = new cString(Name);
+ }
+ }
+ if (!replayTitle) {
+ replayTitle = new cString(tr("Unknown title"));
+ }
+ }
+ else
+ {
+ m_eWatchMode = eLiveTV;
+ m_pControl = NULL;
+ }
+}
+
+
+eReplayState cVFDWatch::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 cVFDWatch::ReplayPosition(int &current, int &total) const
+{
+ if (m_pControl && ((cControl *)m_pControl)->GetIndex(current, total, false)) {
+ total = (total == 0) ? 1 : total;
+ return true;
+ }
+ return false;
+}
+
+const char * cVFDWatch::FormatReplayTime(int current, int total) const
+{
+ static char s[32];
+#if VDRVERSNUM >= 10701
+ int cs = (current / DEFAULTFRAMESPERSECOND);
+ int ts = (total / DEFAULTFRAMESPERSECOND);
+ bool g = (((current / DEFAULTFRAMESPERSECOND) / 3600) > 0)
+ || (((total / DEFAULTFRAMESPERSECOND) / 3600) > 0);
+#else
+ int cs = (current / FRAMESPERSEC);
+ int ts = (total / FRAMESPERSEC);
+ bool g = (((current / FRAMESPERSEC) / 3600) > 0)
+ || (((total / FRAMESPERSEC) / 3600) > 0);
+#endif
+ int cm = cs / 60;
+ cs %= 60;
+ int tm = ts / 60;
+ ts %= 60;
+
+ if (total > 1) {
+ if(g) {
+ snprintf(s, sizeof(s), "%s (%s)", (const char*)IndexToHMSF(current), (const char*)IndexToHMSF(total));
+ } else {
+ snprintf(s, sizeof(s), "%02d:%02d (%02d:%02d)", cm, cs, tm, ts);
+ }
+ }
+ else {
+ if(g) {
+ snprintf(s, sizeof(s), "%s", (const char*)IndexToHMSF(current));
+ } else {
+ snprintf(s, sizeof(s), "%02d:%02d", cm, cs);
+ }
+ }
+ return s;
+}
+
+bool cVFDWatch::ReplayTime() {
+ int current = 0,total = 0;
+ if(ReplayPosition(current,total)) {
+ const char * sz = FormatReplayTime(current,total);
+ if(!replayTime || strcmp(sz,*replayTime)) {
+ if(replayTime)
+ delete replayTime;
+ replayTime = new cString(sz);
+ return replayTime != NULL;
+ }
+ }
+ return false;
+}
+
+void cVFDWatch::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("targaVFD: Recording: only up to %d devices are supported by this plugin", memberof(m_nCardIsRecording));
+ }
+}
+
+void cVFDWatch::Channel(int ChannelNumber)
+{
+ cMutexLooker m(mutex);
+ if(chPresentTitle) {
+ delete chPresentTitle;
+ chPresentTitle = NULL;
+ }
+ if(chPresentShortTitle) {
+ delete chPresentShortTitle;
+ chPresentShortTitle = NULL;
+ }
+ if(chName) {
+ delete chName;
+ chName = NULL;
+ }
+
+ cChannel * ch = Channels.GetByNumber(ChannelNumber);
+ if(ch) {
+ chID = ch->GetChannelID();
+ chPresentTime = 0;
+ chFollowingTime = 0;
+ if (!isempty(ch->Name())) {
+ chName = new cString(ch->Name());
+ }
+ }
+ m_eWatchMode = eLiveTV;
+ m_bUpdateScreen = true;
+ m_nScrollOffset = 0;
+ m_bScrollBackward = false;
+}
+
+bool cVFDWatch::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;
+}
+
+
+void cVFDWatch::Volume(int nVolume, bool bAbsolute)
+{
+ cMutexLooker m(mutex);
+
+ int nAbsVolume;
+
+ nAbsVolume = m_nLastVolume;
+ if (bAbsolute) {
+ nAbsVolume = nVolume;
+ } else {
+ nAbsVolume += nVolume;
+ }
+ if(nAbsVolume > MAXVOLUME) {
+ nAbsVolume = MAXVOLUME;
+ }
+ else if(nAbsVolume < 0) {
+ nAbsVolume = 0;
+ }
+
+ if(m_nLastVolume > 0 && 0 == nAbsVolume) {
+ m_bVolumeMute = true;
+ }
+ else if(0 == m_nLastVolume && nAbsVolume > 0) {
+ m_bVolumeMute = false;
+ }
+ m_nLastVolume = nAbsVolume;
+}
+
+
+void cVFDWatch::OsdClear() {
+ cMutexLooker m(mutex);
+ if(osdMessage) {
+ delete osdMessage;
+ osdMessage = NULL;
+ m_bUpdateScreen = true;
+ }
+ if(osdTitle) {
+ delete osdTitle;
+ osdTitle = NULL;
+ m_bUpdateScreen = true;
+ }
+ if(osdItem) {
+ delete osdItem;
+ osdItem = NULL;
+ m_bUpdateScreen = true;
+ }
+}
+
+void cVFDWatch::OsdTitle(const char *sz) {
+ char *s = NULL;
+ char *sc = NULL;
+ if(sz && !isempty(sz)) {
+ s = strdup(sz);
+ sc = compactspace(strreplace(s,'\t',' '));
+ }
+ if(sc
+ && osdTitle
+ && 0 == strcmp(sc, *osdTitle)) {
+ if(s) {
+ free(s);
+ }
+ return;
+ }
+ cMutexLooker m(mutex);
+ if(osdTitle) {
+ delete osdTitle;
+ osdTitle = NULL;
+ m_bUpdateScreen = true;
+ }
+ if(sc) {
+ osdTitle = new cString(sc);
+ m_bUpdateScreen = true;
+ }
+ if(s) {
+ free(s);
+ }
+}
+
+void cVFDWatch::OsdCurrentItem(const char *sz)
+{
+ char *s = NULL;
+ char *sc = NULL;
+ if(sz && !isempty(sz)) {
+ s = strdup(sz);
+ sc = compactspace(strreplace(s,'\t',' '));
+ }
+ if(sc
+ && osdItem
+ && 0 == strcmp(sc, *osdItem)) {
+ if(s) {
+ free(s);
+ }
+ return;
+ }
+ cMutexLooker m(mutex);
+ if(osdItem) {
+ delete osdItem;
+ osdItem = NULL;
+ m_bUpdateScreen = true;
+ }
+ if(sc) {
+ osdItem = new cString(sc);
+ m_bUpdateScreen = true;
+ }
+ if(s) {
+ free(s);
+ }
+}
+
+void cVFDWatch::OsdStatusMessage(const char *sz)
+{
+ char *s = NULL;
+ char *sc = NULL;
+ if(sz && !isempty(sz)) {
+ s = strdup(sz);
+ sc = compactspace(strreplace(s,'\t',' '));
+ }
+ if(sc
+ && osdMessage
+ && 0 == strcmp(sc, *osdMessage)) {
+ if(s) {
+ free(s);
+ }
+ return;
+ }
+ cMutexLooker m(mutex);
+ if(osdMessage) {
+ delete osdMessage;
+ osdMessage = NULL;
+ m_bUpdateScreen = true;
+ }
+ if(sc) {
+ osdMessage = new cString(sc);
+ m_bUpdateScreen = true;
+ }
+ if(s) {
+ free(s);
+ }
+}
+
+bool cVFDWatch::SetFont(const char *szFont, int bTwoLineMode) {
+ cMutexLooker m(mutex);
+ if(cVFD::SetFont(szFont, bTwoLineMode)) {
+ m_bUpdateScreen = true;
+ return true;
+ }
+ return false;
+}
+
+eIconState cVFDWatch::ForceIcon(unsigned int nIcon, eIconState nState) {
+
+ unsigned int nIconOff = nIcon;
+
+ switch(nState) {
+ case eIconStateAuto:
+ m_nIconsForceOn &= ~(nIconOff);
+ m_nIconsForceOff &= ~(nIconOff);
+ m_nIconsForceMask &= ~(nIconOff);
+ break;
+ case eIconStateOn:
+ m_nIconsForceOn |= nIcon;
+ m_nIconsForceOff &= ~(nIconOff);
+ m_nIconsForceMask |= nIconOff;
+ break;
+ case eIconStateOff:
+ m_nIconsForceOff |= nIcon;
+ m_nIconsForceOn &= ~(nIconOff);
+ m_nIconsForceMask |= nIconOff;
+ break;
+ default:
+ break;
+ }
+ if(m_nIconsForceOn & nIcon) return eIconStateOn;
+ if(m_nIconsForceOff & nIcon) return eIconStateOff;
+ return eIconStateAuto;
+}
+
diff --git a/watch.h b/watch.h
new file mode 100644
index 0000000..7aed236
--- /dev/null
+++ b/watch.h
@@ -0,0 +1,129 @@
+/*
+ * targavfd plugin for VDR (C++)
+ *
+ * (C) 2010 Andreas Brachold <vdr07 AT deltab de>
+ *
+ * This targavfd plugin 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, version 3 of the License.
+ *
+ * See the files README and COPYING for details.
+ *
+ */
+
+#ifndef __VFD_WATCH_H
+#define __VFD_WATCH_H
+
+#include <vdr/thread.h>
+#include <vdr/status.h>
+#include "vfd.h"
+
+enum eWatchMode {
+ eUndefined,
+ eLiveTV,
+ eReplayNormal,
+ eReplayMusic,
+ eReplayDVD,
+ eReplayFile,
+ eReplayImage,
+ eReplayAudioCD
+};
+
+enum eReplayState {
+ eReplayNone,
+ eReplayPlay,
+ eReplayPaused,
+ eReplayForward1,
+ eReplayForward2,
+ eReplayForward3,
+ eReplayBackward1,
+ eReplayBackward2,
+ eReplayBackward3
+};
+
+enum eIconState {
+ eIconStateQuery,
+ eIconStateOn,
+ eIconStateOff,
+ eIconStateAuto
+};
+
+
+class cVFDWatch
+ : public cVFD
+ , protected cThread {
+private:
+ cMutex mutex;
+
+ volatile bool m_bShutdown;
+
+ eWatchMode m_eWatchMode;
+
+ int m_nScrollOffset;
+ bool m_bScrollBackward;
+ bool m_bScrollNeeded;
+ bool m_bUpdateScreen;
+
+ int m_nCardIsRecording[MAXDEVICES];
+
+ unsigned int m_nIconsForceOn;
+ unsigned int m_nIconsForceOff;
+ unsigned int m_nIconsForceMask;
+
+ 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;
+
+ cString* osdTitle;
+ cString* osdItem;
+ cString* osdMessage;
+
+ cString* replayTitle;
+ cString* replayTitleLast;
+ cString* replayTime;
+
+ time_t tsCurrentLast;
+ cString* currentTime;
+protected:
+ virtual void Action(void);
+ bool Program();
+ bool Replay();
+ bool RenderScreen(bool bReDraw);
+ eReplayState ReplayMode() const;
+ bool ReplayPosition(int &current, int &total) const;
+ bool CurrentTime();
+ bool ReplayTime();
+ const char * FormatReplayTime(int current, int total) const;
+public:
+ cVFDWatch();
+ virtual ~cVFDWatch();
+
+ virtual bool open();
+ 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);
+ void Volume(int nVolume, bool bAbsolute);
+
+ void OsdClear();
+ void OsdTitle(const char *sz);
+ void OsdCurrentItem(const char *sz);
+ void OsdStatusMessage(const char *sz);
+
+ virtual bool SetFont(const char *szFont, int bTwoLineMode);
+
+ eIconState ForceIcon(unsigned int nIcon, eIconState nState);
+};
+
+#endif
+