summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Grimm <tobias@e-tobi.loc>2008-12-02 21:00:33 +0100
committerTobias Grimm <tobias@e-tobi.loc>2008-12-02 21:00:33 +0100
commitb451fdb5a36c0f749d63d53165cdf4e84a8f476a (patch)
treeaa3b6548ea52ef133028098c8fbaebbe47ed8a5d
downloadvdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.gz
vdr-plugin-osdteletext-b451fdb5a36c0f749d63d53165cdf4e84a8f476a.tar.bz2
Initial commit of version 0.5.1v0.5.1release/v0.5.1
-rw-r--r--COPYING340
-rw-r--r--HISTORY207
-rw-r--r--Makefile86
-rw-r--r--README98
-rw-r--r--README.DE86
-rw-r--r--display.c240
-rw-r--r--display.h131
-rw-r--r--displaybase.c507
-rw-r--r--displaybase.h287
-rw-r--r--i18n.c445
-rw-r--r--i18n.h16
-rw-r--r--menu.c681
-rw-r--r--menu.h82
-rw-r--r--osdteletext.c481
-rw-r--r--setup.h65
-rw-r--r--tables.h112
-rw-r--r--txtfont.c3371
-rw-r--r--txtfont.h14
-rw-r--r--txtrecv.c884
-rw-r--r--txtrecv.h204
-rw-r--r--txtrender.c543
-rw-r--r--txtrender.h311
22 files changed, 9191 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..295c5c1
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,207 @@
+VDR Plugin 'teletextosd' Revision History
+-----------------------------------------
+
+2005-08-16: version 0.5.1
+
+- show page if it was initially not found
+ but is received later
+ (suggested by Luca Olivetti)
+- added timeout for user inactivity after
+ which the plugin is closed. Without timeout the plugin would
+ prevent VDR's auto-shutdown mechanism if it remains open.
+ The value is the same as VDR's min user inactivity
+ setup option.
+ (suggested by Peter Bieringer)
+- fixed gcc4 warnings
+ (thanks to Ville Skyttä)
+- updated Finnish translation
+ (thanks to Rolf Ahrenberg)
+- added command line parameter documentation
+ to READMEs
+- added /var/cache/vdr/osdteletext to the list of recommended
+ cache directories
+ (suggested by Ville Skyttä)
+
+2005-04-21: version 0.5
+
+ Udo Richter:
+- font subsystem now supports Teletext level 1.
+ Fonts are provided for English, German, French,
+ Italian, Spanish, Portuguese, Swedish and Finnish.
+ The correct font is chosen automatically.
+- support for "boxed mode" (newstickers, subtitles):
+ in 4Bpp mode the area not covered by the box
+ will be completely transparent
+- OSD can now be aligned on screen:
+ - in horizontal alignment mode, 0 means on the left,
+ 50 in the center and 100 on the right
+ - in vertical alignment mode, 0 means at the top,
+ 50 in the center and 100 at the bottom
+ - default is central alignment
+- changed palette system, no longer depending on
+ order of indexing
+- fixed compilation failure with gcc 2.95
+- changed OSD minimum size from 480x324 to 320x250
+- some bugfixes and comments in txtrecv.c
+ Marcel Wiesweg:
+- avoid crash and improve behavior when an
+ invalid channel number is entered
+
+2005-03-30: version 0.5-pre1
+
+ Udo Richter:
+- extensive rewrite of display code
+- removed display.*, txtbitmap.*, colormapping.h
+- added txtrender.*, displaybase.*, display.*
+- menu.c adapted to new display engine
+- speed improvements by incremental drawing
+- strict adherence to standard
+
+2005-03-21: version 0.4.9-inofficial
+
+- rewrite of scaling and drawing code, better scaling
+ algorithm, removed inefficient double painting.
+ Increases speed by a factor of 4. (Udo Richter)
+- minor fixes for pagenumber, channel number and clock
+ fields to minimize overdrawing (Rolf Ahrenberg)
+- fix for graphical errors if normal characters are
+ introduced after double high ones (Rolf Ahrenberg)
+- fix in receiving code to make osdteletext work
+ with some Swedish channels (thanks to Magnus Andersson)
+- pseudo target in Makefile allows a simple "make".
+ Previously, this would fail and you needed "make all"
+
+2005-03-03: version 0.4.2
+
+- fixes for double-high characters, scaling and localization
+ (thanks to Rolf Ahrenberg for his patch edition)
+- adapted to VDR API >= 1.3.18, reentrancy fixes
+- added Spanish and Catalan translation
+ (thanks to Luca Olivetti)
+- create stored files with 644 permissions
+ (suggested by Andreas Brachold)
+
+2004-09-21: version 0.4.1
+
+- fixed problem with undefined file permissions
+ of created files (thanks to whoever created the patch)
+- fixed hexadecimal/decimal misinterpretation for "Jump to"
+ key bindings (thanks to Peter Bieringer for pointing this out)
+- cosmetic change: key Left when entering channel number
+ now resets the cursor by one position, other keys stop
+ entering of page number
+
+2004-06-18: version 0.4
+
+- ported to VDR 1.3/1.4 series (>=1.3.8 now required)
+ This mostly involved changes in the OSD graphics code,
+- now supports OSDs with color depth of 3
+ (thanks to Sascha Volkenandt)
+- rewrote the storage system:
+ - cache directory is now configurable (option -d)
+ Default value is still /vtx to allow seamless migration,
+ but /tmp/vtx is recommended (conforms to LSB etc.)
+ - changed the default file format: Now more than one
+ page is stored in one file. On filesystems that depend
+ on a blocksize the increases storage efficiency.
+ For tmpfs the improvement factor is approx. 4.
+ - The old system is still available via a
+ command line option (though it now uses a slightly
+ different naming)
+ - when no more space is available on disk
+ or a specified number of harddisk space is exceeded
+ (option -n) the folder least recently modified
+ will be deleted.
+ On exit, all files will be deleted, i.e.
+ (!) on exit, all files with suffix .vtx
+ below the storage directory will be deleted
+ - the option -r is now obsolete (will be ignored)
+ option -R/--no-receive is deprecated
+- code cleanups, removed broken or unused code
+- fixed quite a few bugs
+- Added Russian translation (thanks to Vyacheslav Dikonov)
+
+2003-12-2: version 0.3.2
+
+- receiver now uses a ring buffer and a thread to reduce
+ time spent in Receive() function, thus delaying VDR's
+ receiver thread (several people reported problems
+ with bitstreamout - thanks to Christian Jacobsen
+ and Dr. Werner Fink)
+- fixed and improved the newly introduced receiver thread
+ (thanks to Dr. Werner Fink)
+- fixed a bug that if there is a double high title on a page,
+ the last line on that page will be missing
+ (fixed by Rolf Ahrenberg)
+- fixed Finnish translation (thanks to Rolf Ahrenberg)
+- added Italian translation (thanks to "kikko77")
+- fixed bug that you could not enter 0 when switching
+ channel (thanks to Dietmar Hilbrich)
+
+2003-04-28: version 0.3.1
+
+- added support for DXR3 systems. Patches contributed by Kai Moeller
+ and Sascha Volkenandt, thanks to them.
+- the "0" if pressed as first digit now switches between current
+ and last page (as VDR does it with channels)
+- fixed autosuspend thread
+
+2003-04-03: version 0.3
+
+- fixed two serious memory leaks, thanks to Martin Pley
+- added feature to automatically update the page if it changed.
+- moved color definitions to colormapping.h
+- made width and height configurable, independent from, but with the same
+ mechanism as VDR
+- made setup menu items dynamic, i.e. the "Page Number" entries are hidden
+ when "Jump to..." is not selected
+- Experimental: added option to suspend the receiving automatically
+ for 5min after 30s. This may enable you to use your TV set's
+ teletext decoder if you like to. (patch to VDR needed)
+- Experimental: added an action to immediately suspend receiving,
+ respectively reenable it
+- added an action to switch the background color between the value
+ you configured in the setup and black
+- improved color handling when foreground and background
+ color are the same, thanks to Martin Pley
+- fixed small bug in ChangePageRelative, thanks to Martin Pley
+- improvements in page switching, thanks to Martin Pley
+- rewrote parts of the README
+- added a German README.DE
+- several fixes and code clean-ups
+
+
+
+2003-02-26: version 0.2.1
+
+- fixed two compiling problems with gcc versions other than 3.2
+ (asprintf, <map>)
+- included Finnish translations, thanks to Lauri Tischler
+- improved Makefile, now uses install instead of mkdir/cp
+
+2003-02-15: version 0.2
+
+- Copied code to receive and save teletext data from original teletext plugin.
+ (appreciating Peter Seyringer's great work)
+- added command line option to enable the receiving code
+- added setup options to make key bindings fully configurable.
+ For each key you can choose between the three actions "Zoom", "Half page" or
+ "Switch channel" or use it to jump to a page
+- added setup option to make background transparency configurable
+ (0...255, VDR's default value being 127)
+- included Emil Naepflein's patch to improve changing pages relatively
+- added feature to view saved pages of other channels than the current
+ ("Switch Channel"). Last pages are remembered over channel switching.
+- fixed bug when the upper half of a page was not automatically shown
+ when using the number keys
+- page and channel numbers now persist when returning to VDR
+- added clock which can regularly be updated.
+ (the clock shows the system time, which may definitely be different
+ from the time broadcast via teletext)
+- added setup option to enable clock
+- now copies README to ../../man, as Reinhard Walter Buchner suggested
+
+
+2003-02-05: Version 0.1
+
+- Initial revision.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1e0a0ac
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,86 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id$
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = osdteletext
+
+### 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:
+
+OPTLEVEL ?= 2
+CXXFLAGS = -O$(OPTLEVEL) -g -Wall -Woverloaded-virtual -fPIC -DPIC
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g')
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include -I$(DVBDIR)/include
+
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -D_GNU_SOURCE
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o menu.o txtfont.o i18n.o txtrecv.o txtrender.o displaybase.o display.o
+
+### Implicit rules:
+
+all-redirect: all
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+ @install -d ../../man
+ @install README ../../man/$(PLUGIN).man
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+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* *~
diff --git a/README b/README
new file mode 100644
index 0000000..865dc52
--- /dev/null
+++ b/README
@@ -0,0 +1,98 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Marcel Wiesweg <marcel.wiesweg@gmx.de>
+
+Project's homepage: http://www.wiesweg-online.de/linux/vdr
+
+Latest version available at: http://www.wiesweg-online.de/linux/vdr
+
+See the file COPYING for license information.
+
+Description:
+
+Osd-Teletext displays the teletext directly on the OSD.
+Both sound and video are played in the background.
+
+
+Keys:
+ 1,...,9: insert page number
+ Up: page+
+ Down: page-
+ Right: sub page+
+ Left: sub page-
+ Back: close teletext plugin
+
+ All other user interaction ("Actions") is configurably assigned to the other
+ available keys.
+ You can e.g. configure that you jump to page 100 when you press Red.
+ In this example, the Action "Jump to 100" is assigned to key "Red".
+ Have a look at the plugin's setup page to learn the current assignment
+ and adapt it to your needs.
+
+ Available Keys: Blue, Red, Yellow, Green, Play, Stop, FastFwd, FastRwd
+ Actions: "Zoom", "Half page", "Switch channel", "Switch background",
+ "Jump to..." a specific page.
+
+ Description of the actions:
+ Zoom: Zoom to upper half/lower half/back to full page
+ Half Page: Reduce OSD window to the lower half of the screen and display upper half/lower half/back to full size
+ Switch channel:Show pages of a channel different from the one currently tuned to.
+ This does _not_ include any tuning or channel switching with vdr's core.
+ You must have tuned to the channel chosen some time before so that the pages have been stored on disk.
+ When you press the key associated with that action, you are asked for the channel number.
+ Press OK after you entered it with the number keys.
+ Jump to...: Jumps to the page you configure.
+ Switch background: Changes the in the setup configurable background color immediately
+ to black and back to your degree of transparency.
+
+ How to configure the key bindings:
+ In the plugins setup menu, you can assign one of actions to each key.
+ You can choose freely which actions you need, you are not forced to assign
+ an action to a key at all if you do not need it.
+ If you select "Jump to...", specify the page number in the line immediately below.
+
+
+Other Setup options:
+ Background transparency:
+ number between 0 (transparent) and 255 (black). Default is 127 (also used by VDR)
+ Show Clock: Toggles whether an additional clock is drawn approximately every second.
+ The clock shows the current system time, not any time broadcast via teletext.
+ Let VDR set the system time from a transponder to have the exact time.
+ Auto-update pages:
+ Continuously checks whether a page has changed and updates it if yes.
+ OSD width, OSD height:
+ Adjusts the width and height of the OSD independent from VDR's settings.
+ The valid range is 40 to 56 for the width and 12 to 21 for the height.
+ Minimum user inactivity:
+ Sets a timeout (in minutes) for user inactivity. When this timespan has elapsed
+ and the user did not press any keys, the plugin will be closed. Set to 0 to disable this.
+ Note that disabling timeout will also effectively disable VDR's auto-shutdown feature
+ as long as the plugin is active.
+ Key bindings: See above.
+
+Command line options:
+ A few settings are given on the command line rather than in the setup menu.
+ Available options:
+
+ -d --directory=DIR The directory where the temporary
+ files will be stored.
+ (standard value: /vtx, recommended: /tmp/vtx
+ or /var/cache/vdr/osdteletext.)
+ Ensure that the directory exists and is writable.
+ -n --max-cache=NUM Maximum size in megabytes of cache used
+ to store the pages on the harddisk.
+ (standard value: a calculated value below 50 MB)
+ -s --cache-system=SYS Set the cache system to be used.
+ Choose "legacy" for the traditional
+ one-file-per-page system.
+ Default is "packed" for the
+ one-file-for-a-few-pages system.
+
+Colors:
+ On all sorts of output devices which are not limited as to color depth
+ the original teletext colors will be displayed. (Only difference: Cyan is used instead of
+ white to make reading easier).
+ On the classic full-featured DVB card and other limited devices, the colors will be reduced to four.
+ The mapping is currently optimized for German ARD, ZDF and RTL. If you are for some reason
+ really and definitely not satisfied with my choices, edit colormapping.h and recompile.
+
diff --git a/README.DE b/README.DE
new file mode 100644
index 0000000..2384e81
--- /dev/null
+++ b/README.DE
@@ -0,0 +1,86 @@
+Beschreibung:
+
+OSD-Teletext zeigt Videotext direkt auf dem OSD an.
+Im Hintergrund gibt es weiterhin Bild und Ton.
+
+
+Tasten:
+ 1,...,9: Seitenzahl eingeben
+ Hoch: Seite weiter
+ Herunter:Seite zurück
+ Rechts: Unterseite weiter
+ Links: Unterseite zurück
+ Zurück: Videotext-Plugin schließen
+
+ Die restliche Bedienung ("Aktionen") durch die anderen Tasten ist frei konfigurierbar.
+ Man kann z.B. einstellen, das die man mit der Taste Rot auf die Seite 100 springt.
+ Bei dieser Einstellung wäre die Aktion "Springe zu 100" der Taste Rot zugeordnet.
+
+ Verfügbare Tasten: Blau, Rot, Gelb, Grün, Play, Stop, Schneller Vorlauf, Schn. Rücklauf
+ Aktionen: "Vergrößern", "Halbe Seite", "Kanal wechseln",
+ "Hintergrund wechseln", "Springe zu..." einer bestimmten Seite
+
+ Beschreibung der Aktionen:
+ Vergrößern: Obere / untere Hälfte vergrößern / zurück zur ganzen Seite
+ Halbe Seite: OSD-Fenster nur noch in unterer Hälfte des Bildschirms zeigen
+ und obere / untere Hälfte anzeigen bzw. zurück
+ Kanal wechseln:Seiten eines anderen Senders als des gerade eingestellten anzeigen.
+ Dabei wird keine Frequenz gewechselt oder mit VDR ein anderer Kanal eingestellt.
+ Damit Seiten verfügbar sind, muss irgendwann vorher der gewählte
+ Kanal eingestellt gewesen sein. Bei Aufruf der Aktion wird nach der Kanalnummer
+ gefragt. Die Nummer mit den Zifferntasten eingeben und OK drücken.
+ Springe zu...: Springt zu der entsprechenden Seite
+ Hintergrund wechseln: Ändert die im Setup einstellbare Hintergrundfarbe sofort zu Schwarz
+ und nach erneutem Aufruf wieder zurück.
+
+ Wie man Tasten Aktionen zuordnet:
+ Im Einstellungsmenü des Plugins kann jeder Taste eine Aktion zugeordnet werden.
+ Dabei ist nichts vorgeschrieben - keine Aktion muss irgendeiner Taste zugewiesen werden,
+ wenn sie nicht benötigt wird.
+ Bei Auswahl von "Springe zu..." wird die Seitennummer in der Zeile direkt darunter
+ angegeben.
+
+Andere Optionen:
+ Hintergrund-Transparenz: Zahl zwischen 0 (transparent) und 255 (schwarz). Vorgegeben ist 127 (wie auch von VDR)
+ Zeige Uhr: Diese Option bestimmt, ob etwa im Sekundenabstand zusätzlich eine Uhr angezeigt wird.
+ Die Uhr zeigt die aktuelle Systemzeit, nicht die mit dem Videotext ausgestrahlte Zeit.
+ Um genaue Werte zu haben, kann VDR die Systemzeit von einem Transponder einstellen.
+ Automatisch aktualisieren:
+ Überprüft ständig, ob sich die Seite geändert hat und aktualisiert sie wenn nötig
+ OSD-Breite, OSD-Höhe:
+ Hier kann die Breite des OSD unabhängig von den Einstellungen für VDR
+ bestimmt werden. Für die Breite liegt die Zahl zwischen 40 und 56,
+ für die Höhe zwischen 12 und 21.
+ Mindest Benutzer-Inaktivität:
+ Bestimmt die Zeit (in Minuten), nach der das Plugin automatisch geschlossen wird, wenn
+ der Benutzer solange keine Taste betätigt hat. Das kann durch setzen des Wertes auf 0
+ verhindert werden. Dann wird jedoch auch das automatische Abschalten von VDR effektiv
+ außer Kraft gesetzt, solange das Plugin geöffnet ist.
+ Tasten einrichten: siehe oben
+
+Kommandozeilen-Optionen:
+ Einige Einstellungen werden über die Kommandozeile anstatt über das Menü gesetzt.
+ Verfügbare Optionen:
+
+ -d --directory=DIR Das Verzeichnis für die temporären Dateien.
+ (Voreinstellung: /vtx, empfohlen: /tmp/vtx
+ oder /var/cache/vdr/osdteletext.)
+ Stellen Sie sicher, dass das Verzeichnis existiert
+ und beschreibbar ist.
+ -n --max-cache=NUM Maximale Größe des Zwischenspeichers für Seiten
+ auf der Festplatte.
+ (Voreinstellung: ein berechneter Wert unter 50 MB)
+ -s --cache-system=SYS Das zu benutzende Zwischenspeichersystem.
+ Wählen Sie "legacy" für das althergebrachte
+ System "Eine Datei - eine Seite".
+ Voreinstellung ist "packed" für ein System, das
+ in eine Datei mehrere Seiten speichert.
+
+Farben:
+ Auf allen Ausgabegeräten, die nicht in der Farbtiefe des OSD beschränkt sind,
+ werden die unveränderten Farben des Videotexts dargestellt (einzig Weiß wurde zum Zwecke der besseren
+ Lesbarkeit durch Cyan ersetzt).
+ Für die klassische DVB-Karte mit Hardware-Dekoder und anderen so beschränkten Geräten werden nur vier Farben dargestellt. Die Zuordnung ist auf ARD, ZDF und RTL optimiert. Sollten Sie aus irgendeinem Grund absolut nicht
+ meiner Meinung sein, passen Sie die Datei colormapping.h an und kompilieren Sie neu.
+
+ \ No newline at end of file
diff --git a/display.c b/display.c
new file mode 100644
index 0000000..c9ac59f
--- /dev/null
+++ b/display.c
@@ -0,0 +1,240 @@
+/***************************************************************************
+ * *
+ * display.c - Actual implementation of OSD display variants and *
+ * Display:: namespace that encapsulates a single cDisplay. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#include <strings.h>
+#include <vdr/config.h>
+#include "setup.h"
+#include "display.h"
+#include "txtfont.h"
+
+// Static variables of Display:: namespace
+Display::Mode Display::mode=Display::Full;
+cDisplay *Display::display=NULL;
+
+
+void Display::SetMode(Display::Mode NewMode) {
+ // (re-)set display mode.
+
+ if (display!=NULL && NewMode==mode) return;
+ // No change, nothing to do
+
+ // OSD origin, centered on VDR OSD
+ int x0=Setup.OSDLeft+(Setup.OSDWidth-ttSetup.OSDwidth)*ttSetup.OSDHAlign/100;
+ int y0=Setup.OSDTop +(Setup.OSDHeight-ttSetup.OSDheight)*ttSetup.OSDVAlign/100;
+
+ switch (NewMode) {
+ case Display::Full:
+ // Need to re-initialize *display:
+ Delete();
+ // Try 4BPP display first:
+ display=new cDisplay4BPP(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight);
+ if (!display->Valid()) {
+ // Failed, possibly out of memory
+ delete display;
+ // Try 2BPP display
+ display=new cDisplay2BPP(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight);
+ }
+ break;
+ case Display::HalfUpper:
+ // Shortcut to switch from HalfUpper to HalfLower:
+ if (mode==Display::HalfLower) {
+ // keep instance.
+ ((cDisplay4BPPHalf*)display)->SetUpper(true);
+ break;
+ }
+ // Need to re-initialize *display:
+ Delete();
+ display=new cDisplay4BPPHalf(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight,true);
+ break;
+ case Display::HalfLower:
+ // Shortcut to switch from HalfUpper to HalfLower:
+ if (mode==Display::HalfUpper) {
+ // keep instance.
+ ((cDisplay4BPPHalf*)display)->SetUpper(false);
+ break;
+ }
+ // Need to re-initialize *display:
+ Delete();
+ display=new cDisplay4BPPHalf(x0,y0,ttSetup.OSDwidth,ttSetup.OSDheight,false);
+ break;
+ }
+ mode=NewMode;
+ // If display is invalid, clean up immediately:
+ if (!display->Valid()) Delete();
+ // Pass through OSD black transparency
+ SetBackgroundColor((tColor)ttSetup.configuredClrBackground);
+}
+
+void Display::ShowUpperHalf() {
+ // Enforce upper half of screen to be visible
+ if (GetZoom()==cDisplay::Zoom_Lower)
+ SetZoom(cDisplay::Zoom_Upper);
+ if (mode==HalfLower)
+ SetMode(HalfUpper);
+}
+
+
+
+
+
+
+cDisplay2BPP::cDisplay2BPP(int x0, int y0, int width, int height)
+ : cDisplay(width,height) {
+ // 2BPP display with color mapping
+
+ osd = cOsdProvider::NewOsd(x0, y0);
+ if (!osd) return;
+
+ width=(width+3)&~3;
+ // Width has to end on byte boundary, so round up
+
+ tArea Areas[] = { { 0, 0, width - 1, height - 1, 2 } };
+ if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) {
+ delete osd;
+ osd=NULL;
+ return;
+ }
+ osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+
+ InitPalette();
+
+ InitScaler();
+
+ CleanDisplay();
+}
+
+tColor cDisplay2BPP::GetColorRGB(enumTeletextColor ttc, int Area) {
+ switch (ttc) {
+ case ttcBlack: return Background;
+ case ttcRed: return clrRed;
+ case ttcGreen: return clrYellow;
+ case ttcYellow: return clrYellow;
+ case ttcBlue: return Background;
+ case ttcMagenta: return clrRed;
+ case ttcCyan: return clrCyan;
+ case ttcWhite: return clrCyan;
+ case ttcTransparent: return Background;
+ default: return Background;
+ }
+}
+
+tColor cDisplay2BPP::GetColorRGBAlternate(enumTeletextColor ttc, int Area) {
+ switch (ttc) {
+ case ttcBlack: return clrCyan;
+ case ttcRed: return clrYellow;
+ case ttcGreen: return clrRed;
+ case ttcYellow: return clrRed;
+ case ttcBlue: return clrCyan;
+ case ttcMagenta: return clrYellow;
+ case ttcCyan: return Background;
+ case ttcWhite: return Background;
+ case ttcTransparent: return clrCyan;
+ default: return Background;
+ }
+}
+
+
+
+
+
+cDisplay4BPP::cDisplay4BPP(int x0, int y0, int width, int height)
+ : cDisplay(width,height) {
+ // 4BPP display for memory-modded DVB cards and other OSD providers
+
+ osd = cOsdProvider::NewOsd(x0, y0);
+ if (!osd) return;
+
+ width=(width+1)&~1;
+ // Width has to end on byte boundary, so round up
+
+ tArea Areas[] = { { 0, 0, width - 1, height - 1, 4 } };
+ if (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) {
+ delete osd;
+ osd=NULL;
+ return;
+ }
+ osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+
+ InitPalette();
+
+ InitScaler();
+
+ CleanDisplay();
+}
+
+
+cDisplay4BPPHalf::cDisplay4BPPHalf(int x0, int y0, int width, int height, bool upper)
+ : cDisplay(width,height) {
+
+ OsdX0=x0;
+ OsdY0=y0;
+ Upper=upper;
+ osd=NULL;
+
+ // Redirect all real init work to method
+ InitOSD();
+}
+
+void cDisplay4BPPHalf::InitOSD() {
+ if (osd) delete osd;
+ osd = cOsdProvider::NewOsd(OsdX0, OsdY0);
+ if (!osd) return;
+
+ int width=(Width+1)&~1;
+ // Width has to end on byte boundary, so round up
+
+ tArea Areas[] = { { 0, 0, width - 1, Height - 1, 4 } };
+ // Try full-size area first
+
+ while (osd->CanHandleAreas(Areas, sizeof(Areas) / sizeof(tArea)) != oeOk) {
+ // Out of memory, so shrink
+ if (Upper) {
+ // Move up lower border
+ Areas[0].y2=Areas[0].y2-1;
+ } else {
+ // Move down upper border
+ Areas[0].y1=Areas[0].y1+1;
+ }
+ if (Areas[0].y1>Areas[0].y2) {
+ // Area is empty, fail miserably
+ delete osd;
+ osd=NULL;
+ return;
+ }
+ }
+ // Add some backup
+ // CanHandleAreas is not accurate enough
+ if (Upper) {
+ Areas[0].y2=Areas[0].y2-10;
+ } else {
+ Areas[0].y1=Areas[0].y1+10;
+ }
+
+ osd->SetAreas(Areas, sizeof(Areas) / sizeof(tArea));
+
+ InitPalette();
+
+ InitScaler();
+
+ CleanDisplay();
+
+ // In case we switched on the fly, do a full redraw
+ Dirty=true;
+ DirtyAll=true;
+ Flush();
+}
+
+
+
diff --git a/display.h b/display.h
new file mode 100644
index 0000000..37c76c2
--- /dev/null
+++ b/display.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * *
+ * display.h - Actual implementation of OSD display variants and *
+ * Display:: namespace that encapsulates a single cDisplay. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#ifndef OSDTELETEXT_DISPLAY_H_
+#define OSDTELETEXT_DISPLAY_H_
+
+#include "displaybase.h"
+#include <vdr/osd.h>
+
+namespace Display {
+ // The Display:: namespace mainly encapsulates a cDisplay *display variable
+ // and allows NULL-safe access to display members.
+ // Additionally, selects via mode the actually used instance for *display.
+
+ enum Mode { Full, HalfUpper, HalfLower };
+ // Full mode: 2BPP or 4BPP full screen display, depending on memory constrains
+ // HalfUpper: 4BPP display of upper half, drop lower half if out of memory
+ // HalfLower: 4BPP display of lower half, drop upper half if out of memory
+
+ extern Mode mode;
+ extern cDisplay *display;
+
+ // Access to display mode:
+ void SetMode(Display::Mode mode);
+ inline void Delete()
+ { if (display) { delete display; display=NULL; } }
+
+ void ShowUpperHalf();
+ // Make sure the upper half of screen is visible
+ // eg. for entering numbers etc.
+
+
+ // Wrapper calls for various *display members:
+ inline bool GetBlink()
+ { if (display) return display->GetBlink(); else return false; }
+ inline bool SetBlink(bool blink)
+ { if (display) display->SetBlink(blink); else return false; }
+ inline bool GetConceal()
+ { if (display) return display->GetConceal(); else return false; }
+ inline bool SetConceal(bool conceal)
+ { if (display) display->SetConceal(conceal); else return false; }
+ inline cDisplay::enumZoom GetZoom()
+ { if (display) return display->GetZoom(); else return cDisplay::Zoom_Off; }
+ inline void SetZoom(cDisplay::enumZoom zoom)
+ { if (display) display->SetZoom(zoom); }
+
+ inline void SetBackgroundColor(tColor c)
+ { if (display) display->SetBackgroundColor(c); }
+
+ inline tColor GetBackgroundColor()
+ { if (display) return display->GetBackgroundColor(); else return 0; }
+
+ inline void HoldFlush()
+ { if (display) display->HoldFlush(); }
+ inline void ReleaseFlush()
+ { if (display) display->ReleaseFlush(); }
+
+ inline void RenderTeletextCode(unsigned char *PageCode)
+ { if (display) display->RenderTeletextCode(PageCode); }
+
+ inline void DrawClock()
+ { if (display) display->DrawClock(); }
+ inline void DrawPageId(const char *text)
+ { if (display) display->DrawPageId(text); }
+ inline void DrawMessage(const char *txt)
+ { if (display) display->DrawMessage(txt); }
+ inline void ClearMessage()
+ { if (display) display->ClearMessage(); }
+}
+
+
+
+
+class cDisplay2BPP : public cDisplay {
+ // 2BPP (4 color) OSD display
+ // Use static color mapping to limit color depth
+
+public:
+ cDisplay2BPP(int x0, int y0, int width, int height);
+
+ virtual tColor GetColorRGB(enumTeletextColor ttc, int Area);
+ virtual tColor GetColorRGBAlternate(enumTeletextColor ttc, int Area);
+};
+
+
+
+class cDisplay4BPP : public cDisplay {
+ // 4BPP (16 color) OSD display
+ // No need for color mapping
+public:
+ cDisplay4BPP(int x0, int y0, int width, int height);
+};
+
+
+
+
+class cDisplay4BPPHalf : public cDisplay {
+ // 4BPP (16 color) OSD display with auto size reduction on memory constrains
+ // Automatically tries to make visible area as big as possible
+ // No need for color mapping
+ bool Upper;
+ // Prefer to show upper half or lower half?
+
+ int OsdX0,OsdY0;
+ // Needed to re-initialize osd
+
+public:
+ cDisplay4BPPHalf(int x0, int y0, int width, int height, bool upper);
+ bool GetUpper() { return Upper; }
+ void SetUpper(bool upper)
+ { if (Upper!=upper) { Upper=upper; InitOSD(); } }
+protected:
+ void InitOSD();
+};
+
+
+
+
+#endif
diff --git a/displaybase.c b/displaybase.c
new file mode 100644
index 0000000..b46fa25
--- /dev/null
+++ b/displaybase.c
@@ -0,0 +1,507 @@
+/***************************************************************************
+ * *
+ * displaybase.c - Base class for rendering a teletext cRenderPage to *
+ * an actual VDR OSD. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#include <strings.h>
+#include <time.h>
+#include "displaybase.h"
+#include "txtfont.h"
+
+
+cDisplay::cDisplay(int width, int height) {
+ Concealed=false;
+ Blinked=false;
+ FlushLock=0;
+ Zoom=Zoom_Off;
+ osd=NULL;
+ ScaleX=1;
+ ScaleY=1;
+ OffsetX=0;
+ OffsetY=0;
+ Width=width;
+ Height=height;
+ Background=clrGray50;
+ Boxed=false;
+
+ MessageX=0;
+ MessageY=0;
+ MessageW=0;
+ MessageH=0;
+ MessageFont=cFont::GetFont(fontSml);
+}
+
+cDisplay::~cDisplay() {
+ if (osd) delete osd;
+ osd=NULL;
+}
+
+void cDisplay::InitScaler() {
+ // Set up the scaling factors. Also do zoom mode by
+ // scaling differently.
+
+ if (!osd) return;
+
+ int height=Height-6;
+ int width=Width-6;
+ OffsetX=3;
+ OffsetY=3;
+
+ switch (Zoom) {
+ case Zoom_Upper:
+ height=height*2;
+ break;
+ case Zoom_Lower:
+ OffsetY=OffsetY-height;
+ height=height*2;
+ break;
+ default:;
+ }
+
+ ScaleX=(480<<16)/width;
+ ScaleY=(250<<16)/height;
+}
+
+void cDisplay::InitPalette() {
+ cBitmap *bm;
+ if (!osd) return;
+
+ int Area=0;
+ while ((bm=osd->GetBitmap(Area))) {
+ enumTeletextColor c;
+
+ bm->Reset();
+ // reset palette
+
+ for (c=ttcFirst;c<=ttcLast;c++) bm->Index(GetColorRGB(c,Area));
+ // Announce all palette colors in defined order
+
+ int x1,y1,x2,y2;
+ if (!bm->Dirty(x1,y1,x2,y2)) {
+ // force bitmap dirty to update palette
+ bm->SetIndex(bm->X0(),bm->Y0(),*bm->Data(bm->X0(),bm->Y0()));
+ // otherwise palette change wont be displayed on flush
+ }
+
+ Area++;
+ }
+}
+
+bool cDisplay::SetBlink(bool blink) {
+ int x,y;
+ bool Change=false;
+
+ if (blink==Blinked) return false;
+
+ // touch all blinking chars
+ for (y=0;y<25;y++) {
+ for (x=0;x<40;x++) {
+ if (Page[x][y].GetBlink()) {
+ Page[x][y].SetDirty(true);
+ Change=true;
+ }
+ }
+ }
+ Blinked=blink;
+ if (Change) Dirty=true;
+
+ Flush();
+
+ return Change;
+}
+
+bool cDisplay::SetConceal(bool conceal) {
+ int x,y;
+ bool Change=false;
+
+ if (conceal==Concealed) return false;
+
+ // touch all concealed chars
+ for (y=0;y<25;y++) {
+ for (x=0;x<40;x++) {
+ if (Page[x][y].GetConceal()) {
+ Page[x][y].SetDirty(true);
+ Change=true;
+ }
+ }
+ }
+ Concealed=conceal;
+ if (Change) Dirty=true;
+
+ Flush();
+
+ return Change;
+}
+
+void cDisplay::SetZoom(enumZoom zoom) {
+
+ if (!osd) return;
+ if (Zoom==zoom) return;
+ Zoom=zoom;
+
+ // Re-initialize scaler to let zoom take effect
+ InitScaler();
+
+ // Clear screen - mainly clear border
+ CleanDisplay();
+
+ Flush();
+}
+
+void cDisplay::SetBackgroundColor(tColor c) {
+ Background=c;
+ InitPalette();
+ CleanDisplay();
+ Flush();
+}
+
+void cDisplay::CleanDisplay() {
+ cBitmap *bm;
+ enumTeletextColor bgc=(Boxed)?(ttcTransparent):(ttcBlack);
+ int Area=0;
+ while ((bm=osd->GetBitmap(Area))) {
+ // Draw rect in two steps to avoid zapping palette
+ bm->DrawRectangle(bm->X0(), bm->Y0() , bm->X0()+bm->Width()-1, bm->Y0() , bm->Color(GetColorIndex(bgc,Area)));
+ bm->DrawRectangle(bm->X0(), bm->Y0()+1, bm->X0()+bm->Width()-1, bm->Y0()+bm->Height()-1, bm->Color(GetColorIndex(bgc,Area)));
+ // Yes, this *is* stupid.
+ // Otherwise, ttcTransparent would shift into 0 index of palette,
+ // causing palette re-organization and flicker on page change
+ Area++;
+ }
+
+ // repaint all
+ Dirty=true;
+ DirtyAll=true;
+}
+
+
+tColor cDisplay::GetColorRGB(enumTeletextColor ttc, int Area) {
+ switch (ttc) {
+ case ttcBlack: return Background;
+ case ttcRed: return clrRed;
+ case ttcGreen: return clrGreen;
+ case ttcYellow: return clrYellow;
+ case ttcBlue: return clrBlue;
+ case ttcMagenta: return clrMagenta;
+ case ttcCyan: return clrCyan;
+ case ttcWhite: return clrWhite;
+ case ttcTransparent: return clrTransparent;
+ default: return Background;
+ }
+}
+
+tColor cDisplay::GetColorRGBAlternate(enumTeletextColor ttc, int Area) {
+ return GetColorRGB(ttc,Area);
+}
+
+void cDisplay::RenderTeletextCode(unsigned char *PageCode) {
+ // Interprete teletext code referenced by PageCode
+ // and draw the whole page content into OSD.
+ // PageCode must be a 40*24+12 bytes buffer
+
+ #ifdef timingdebug
+ cTime t;
+ t.Start();
+ #endif
+
+ HoldFlush();
+
+ cRenderPage::ReadTeletextHeader(PageCode);
+
+ if (!Boxed && (Flags&0x60)!=0) {
+ Boxed=true;
+ CleanDisplay();
+ } else if (Boxed && (Flags&0x60)==0) {
+ Boxed=false;
+ CleanDisplay();
+ }
+
+ cRenderPage::RenderTeletextCode(PageCode+12);
+
+ #ifdef timingdebug
+ t.Stop("Render Teletext");
+ #endif
+
+ ReleaseFlush();
+}
+
+
+
+void cDisplay::DrawDisplay() {
+ int x,y;
+ int cnt=0;
+
+ if (!IsDirty()) return;
+ // nothing to do
+
+ #ifdef timingdebug
+ cTime t;
+ t.Start();
+ #endif
+
+ for (y=0;y<25;y++) {
+ for (x=0;x<40;x++) {
+ if (IsDirty(x,y)) {
+ // Need to draw char to osd
+ cnt++;
+ cTeletextChar c=Page[x][y];
+ c.SetDirty(false);
+ if ((Blinked && c.GetBlink()) || (Concealed && c.GetConceal())) {
+ c.SetChar(0x20);
+ c.SetCharset(CHARSET_LATIN_G0_DE);
+ }
+ DrawChar(x,y,c);
+ Page[x][y]=c;
+ }
+ }
+ }
+ #ifdef timingdebug
+ t.Stop("Draw Display");
+ #endif
+
+ Dirty=false;
+ DirtyAll=false;
+}
+
+
+inline bool IsPureChar(unsigned int *bitmap) {
+ // Check if character is pure foreground or
+ // pure background color
+ int i;
+ if (bitmap[0]==0x0000) {
+ for (i=1;i<10;i++) {
+ if (bitmap[i]!=0x0000) return false;
+ }
+ } else if (bitmap[0]==0xfff0) {
+ for (i=1;i<10;i++) {
+ if (bitmap[i]!=0xfff0) return false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+
+
+void cDisplay::DrawChar(int x, int y, cTeletextChar c) {
+ unsigned int buffer[10];
+ unsigned int *charmap;
+ cBitmap *bm;
+
+ // Get character face:
+ charmap=GetFontChar(c,buffer);
+ if (!charmap) {
+ // invalid - clear buffer
+ bzero(&buffer,sizeof buffer);
+ charmap=buffer;
+ }
+
+ // Get colors
+ enumTeletextColor ttfg=c.GetFGColor();
+ enumTeletextColor ttbg=c.GetBGColor();
+
+ if (c.GetBoxedOut()) {
+ ttbg=ttcTransparent;
+ ttfg=ttcTransparent;
+ }
+
+ // Virtual box area of the character
+ cBox box;
+ box.SetToCharacter(x,y);
+
+ // OSD top left pixel of char
+ cVirtualCoordinate TopLeft;
+ TopLeft.VirtualToPixel(this,box.XMin,box.YMin);
+ // This pixel overlaps the box, but may be almost outside.
+
+ // Move in OSD pixel units until we are inside the box
+ while (TopLeft.VirtX<box.XMin) TopLeft.IncPixelX(this);
+ while (TopLeft.VirtY<box.YMin) TopLeft.IncPixelY(this);
+
+ // Move through all areas
+ int Area=0;
+ while ((bm=osd->GetBitmap(Area))) {
+ cVirtualCoordinate BMTopLeft=TopLeft;
+
+ // Correct for bitmap offset
+ BMTopLeft.OsdX-=bm->X0();
+ BMTopLeft.OsdY-=bm->Y0();
+
+ // Map color to local
+ int fg=GetColorIndex(ttfg,Area);
+ int bg=GetColorIndex(ttbg,Area);
+ if (ttfg!=ttbg && fg==bg && !IsPureChar(charmap)) {
+ // Color collision
+ bg=GetColorIndexAlternate(ttbg,Area);
+ }
+
+ // Now draw the character. Start at the top left corner, and walk
+ // through all pixels on OSD. To speed up, keep one pointer to OSD pixel
+ // and one to virtual box coordinates, and move them together.
+
+ cVirtualCoordinate p=BMTopLeft;
+ while (p.VirtY<=box.YMax) {
+ // run through OSD lines
+
+ // OSD line in this bitmap?
+ if (0<=p.OsdY && p.OsdY<bm->Height()) {
+ // bits for this line
+ int bitline;
+ bitline=charmap[(p.VirtY-box.YMin)>>16];
+
+ p.OsdX=BMTopLeft.OsdX;
+ p.VirtX=BMTopLeft.VirtX;
+ while (p.VirtX<=box.XMax) {
+ // run through line pixels
+
+ // pixel insied this bitmap?
+ if (0<=p.OsdX && p.OsdX<bm->Width()) {
+ // pixel offset in bitline:
+ int bit=(p.VirtX-box.XMin)>>16;
+
+ if (bitline&(0x8000>>bit)) {
+ bm->SetIndex(p.OsdX,p.OsdY,fg);
+ } else {
+ bm->SetIndex(p.OsdX,p.OsdY,bg);
+ }
+ }
+ p.IncPixelX(this);
+ }
+ }
+ p.IncPixelY(this);
+ }
+ Area++;
+ }
+}
+
+void cDisplay::DrawText(int x, int y, const char *text, int len) {
+ // Copy text to teletext page
+
+ cTeletextChar c;
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(CHARSET_LATIN_G0);
+
+ // Copy chars up to len or null char
+ while (len>0 && *text!=0x00) {
+ c.SetChar(*text);
+ SetChar(x,y,c);
+ text++;
+ x++;
+ len--;
+ }
+
+ // Fill remaining chars with spaces
+ c.SetChar(' ');
+ while (len>0) {
+ SetChar(x,y,c);
+ x++;
+ len--;
+ }
+ // .. and display
+ Flush();
+}
+
+void cDisplay::DrawClock() {
+ char text[9];
+ time_t t=time(0);
+ struct tm loct;
+
+ localtime_r(&t, &loct);
+ sprintf(text, "%02d:%02d:%02d", loct.tm_hour, loct.tm_min, loct.tm_sec);
+
+ DrawText(32,0,text,8);
+}
+
+void cDisplay::DrawMessage(const char *txt) {
+ const int border=5;
+ cBitmap *bm;
+
+ if (!osd) return;
+
+ HoldFlush();
+ // Hold flush until done
+
+ ClearMessage();
+ // Make sure old message is gone
+
+ if (IsDirty()) DrawDisplay();
+ // Make sure all characters are out, so we can draw on top
+
+ int w=MessageFont->Width(txt)+4*border;
+ int h=MessageFont->Height(txt)+4*border;
+ int x=(Width-w)/2;
+ int y=(Height-h)/2;
+
+ int Area=0;
+ while ((bm=osd->GetBitmap(Area))) {
+ // Walk through all OSD areas
+
+ // Get local color mapping
+ tColor fg=bm->Color(GetColorIndex(ttcWhite,Area));
+ tColor bg=bm->Color(GetColorIndex(ttcBlack,Area));
+ if (fg==bg) bg=bm->Color(GetColorIndexAlternate(ttcBlack,Area));
+
+ // Draw framed box
+ osd->DrawRectangle(x ,y ,x+w-1 ,y+border-1 ,fg);
+ osd->DrawRectangle(x ,y+h-border,x+w-1 ,y+h-1 ,fg);
+ osd->DrawRectangle(x ,y ,x+border-1 ,y+h-1 ,fg);
+ osd->DrawRectangle(x+w-border,y ,x+w-1 ,y+h-1 ,fg);
+ osd->DrawRectangle(x+border ,y+border ,x+w-border-1,y+h-border-1,bg);
+
+ // Draw text
+ osd->DrawText(x+2*border,y+2*border,txt, fg, bg, MessageFont);
+
+ Area++;
+ }
+
+ // Remember box
+ MessageW=w;
+ MessageH=h;
+ MessageX=x;
+ MessageY=y;
+
+ // And flush all changes
+ ReleaseFlush();
+}
+
+void cDisplay::ClearMessage() {
+ if (!osd) return;
+ if (MessageW==0 || MessageH==0) return;
+
+ // map OSD pixel to virtual coordinate, use center of pixel
+ int x0=(MessageX-OffsetX)*ScaleX+ScaleX/2;
+ int y0=(MessageY-OffsetY)*ScaleY+ScaleY/2;
+ int x1=(MessageX+MessageW-1-OffsetX)*ScaleX+ScaleX/2;
+ int y1=(MessageY+MessageH-1-OffsetY)*ScaleY+ScaleY/2;
+
+ // map to character
+ x0=x0/(12<<16);
+ y0=y0/(10<<16);
+ x1=(x1+(12<<16)-1)/(12<<16);
+ y1=(y1+(10<<16)-1)/(10<<16);
+
+ for (int x=x0;x<=x1;x++) {
+ for (int y=y0;y<=y1;y++) {
+ MakeDirty(x,y);
+ }
+ }
+
+ MessageW=0;
+ MessageH=0;
+
+ Flush();
+}
+
+
diff --git a/displaybase.h b/displaybase.h
new file mode 100644
index 0000000..708689f
--- /dev/null
+++ b/displaybase.h
@@ -0,0 +1,287 @@
+/***************************************************************************
+ * *
+ * displaybase.h - Base class for rendering a teletext cRenderPage to *
+ * an actual VDR OSD. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#ifndef OSDTELETEXT_DISPLAYBASE_H_
+#define OSDTELETEXT_DISPLAYBASE_H_
+
+#include "txtrender.h"
+#include <vdr/osd.h>
+
+//#define timingdebug
+// Enables some time measure debugging code
+
+#ifdef timingdebug
+ #include <sys/timeb.h>
+
+ class cTime {
+ // Debugging: Simple class to measure time
+ timeb start;
+ public:
+ void Start() {
+ ftime(&start);
+ }
+ void Stop(char *txt) {
+ timeb t;
+ ftime(&t);
+ int s=t.time-start.time;
+ int ms=t.millitm-start.millitm;
+ if (ms<0) {
+ s--;
+ ms+=1000;
+ }
+ printf("%s: %i.%03i\n",txt,s,ms);
+ }
+ };
+#endif
+
+
+class cDisplay : public cRenderPage {
+ // Class that extends the virtual cRenderPage with the capability
+ // to render its contents to an OSD of variable size.
+ // Renders incrementally - just changes
+ // plus adds some more display features like message display.
+
+public:
+ enum enumZoom {
+ // Zoom up upper/lower half of page
+ Zoom_Off,
+ Zoom_Upper,
+ Zoom_Lower
+ } Zoom;
+
+protected:
+ bool Concealed;
+ // Hidden text internal state
+
+ bool Blinked;
+ // Blinking text internal state
+
+ int FlushLock;
+ // Lock counter for bundeling OSD flushes
+
+ bool Boxed;
+ // Page is 'boxed mode' transparent
+
+ int Width;
+ int Height;
+ // OSD pixel dimension
+
+ tColor Background;
+ // Color to be used for black background
+ // - allow transparency
+
+ cOsd *osd;
+ // The osd object. If creation fails, may be NULL
+
+ int ScaleX,ScaleY;
+ int OffsetX,OffsetY;
+ // Virtual coordinate system, see InitScaler
+
+ const cFont *MessageFont;
+ int MessageX,MessageY,MessageW,MessageH;
+ // Message overlay window, position and font
+
+ class cBox {
+ // helper class. Represents a character's box in virtual coordinates
+ public:
+ int XMin,YMin,XMax,YMax;
+ inline void SetToCharacter(int x, int y);
+ };
+ friend class cBox;
+
+ class cVirtualCoordinate {
+ // helper class. Represents a coordinate in virtual display space
+ // and in OSD pixel coordinates.
+ public:
+ int OsdX,OsdY;
+ int VirtX,VirtY;
+ inline void VirtualToPixel(cDisplay *Display, int x, int y);
+ inline void IncPixelX(cDisplay *Display);
+ inline void IncPixelY(cDisplay *Display);
+ };
+ friend class cVirtualCoordinate;
+
+public:
+ cDisplay(int width, int height);
+ virtual ~cDisplay();
+ bool Valid() { return (osd!=NULL); }
+ // After creation, check for Valid(). Destroy, if not valid.
+
+protected:
+ void InitScaler();
+ // Initialize transformation for OSD->Virtual coordinates
+ // Some words about scaling:
+
+ // OSD display is variable width x height, with 3 pixels border
+ // on all sides. There is a virtual coordinate system projected
+ // on this, with (3,3) mapped to (0,0) and (width-3,height-3)
+ // mapped to (480<<16,250<<16).
+ // The idea is, that each font pixel uses a virtual rectangle
+ // of (1<<16,1<<16) size.
+
+ // ScaleX,ScaleY represent the (virtual) width and height of a
+ // physical OSD pixel.
+ // OffsetX,OffsetY default to 3,3 to represent the border offset,
+ // but may be used differently.
+
+public:
+ bool GetBlink() { return Blinked; }
+ bool SetBlink(bool blink);
+ // Switch blink frequently to get blinking chars
+ // Returns true if there are blinking characters.
+
+ bool GetConceal() { return Concealed; }
+ bool SetConceal(bool conceal);
+ // Hidden text. Set to true to see hidden text.
+ // Returns true if there are concealed characters.
+
+ enumZoom GetZoom() { return Zoom; }
+ void SetZoom(enumZoom zoom);
+ // Zoom to upper/lower half of page
+
+ void SetBackgroundColor(tColor c);
+ tColor GetBackgroundColor() { return Background; }
+ // Set the background color for black. Allows transparent black.
+
+ // Color mapping interface.
+ virtual tColor GetColorRGB(enumTeletextColor ttc, int Area);
+ // Map a teletext color to an OSD color in #Area.
+
+ virtual tColor GetColorRGBAlternate(enumTeletextColor ttc, int Area);
+ // For color collision:
+ // Map this teletext color to an OSD color in #Area, but dont
+ // return same as GetColorRGB(). Used to solve conflicts if
+ // foreground and background are mapped to same color.
+ // Defaults to 1:1 identity. Not needed if all colors actually
+ // supported by OSD.
+
+ int GetColorIndex(enumTeletextColor ttc, int Area) {
+ // Map this teletext color to an OSD color index in #Area.
+ if (!osd) return 0;
+ cBitmap *bm=osd->GetBitmap(Area);
+ if (!bm) return 0;
+ return bm->Index(GetColorRGB(ttc,Area));
+ }
+
+ int GetColorIndexAlternate(enumTeletextColor ttc, int Area) {
+ // Map this teletext color to an OSD color index in #Area.
+ if (!osd) return 0;
+ cBitmap *bm=osd->GetBitmap(Area);
+ if (!bm) return 0;
+ return bm->Index(GetColorRGBAlternate(ttc,Area));
+ }
+
+
+
+protected:
+ void InitPalette();
+ // Initialize palette(s) for OSD
+
+ void DrawDisplay();
+ // Draw all dirty characters from cRenderPage buffer to OSD
+
+ void CleanDisplay();
+ // Clean OSD completely
+
+ virtual void DrawChar(int x, int y, cTeletextChar c);
+ // Draw a single character to OSD
+
+
+public:
+ void HoldFlush() { FlushLock++; }
+ // Hold all OSD flush updates to bundle operations.
+
+ void ReleaseFlush() { FlushLock--; Flush(); }
+ // Release hold of flush updates. After last release,
+ // the flush will be done
+
+protected:
+ void Flush() {
+ // Commit all changes from OSD internal bitmaps to device
+ // All draw operations inside cDisplay should call it,
+ // no one outside should need to call it.
+
+ if (FlushLock>0) return;
+ if (!osd) return;
+ if (IsDirty()) DrawDisplay();
+
+ #ifdef timingdebug
+ cTime t;
+ t.Start();
+ #endif
+
+ osd->Flush();
+
+ #ifdef timingdebug
+ t.Stop("osd Flush");
+ #endif
+ }
+
+public:
+ void RenderTeletextCode(unsigned char *PageCode);
+ // Interprete teletext code referenced by PageCode
+ // and draw the whole page content into OSD.
+ // PageCode must be a 40*24+12 bytes buffer
+
+ void DrawText(int x, int y, const char *text, int len);
+ // Draw some characters in teletext page.
+ // Max len chars, fill up with spaces
+
+ void DrawClock();
+ // Draw current time to OSD
+
+ void DrawPageId(const char *text)
+ { DrawText(0,0,text,8); }
+ // Draw Page ID string to OSD
+
+ void DrawMessage(const char *txt);
+ // Draw a framed, centered message box to OSD
+
+ void ClearMessage();
+ // Remove message box and redraw hidden content
+};
+
+
+
+inline void cDisplay::cBox::SetToCharacter(int x, int y) {
+ // Virtual box area of a character
+ XMin=(x*12)<<16;
+ YMin=(y*10)<<16;
+ XMax=XMin+(12<<16)-1;
+ YMax=YMin+(10<<16)-1;
+}
+
+inline void cDisplay::cVirtualCoordinate::VirtualToPixel(cDisplay *Display, int x, int y) {
+ // Map virtual coordinate to OSD pixel
+ OsdX=x/Display->ScaleX+Display->OffsetX;
+ OsdY=y/Display->ScaleY+Display->OffsetY;
+
+ // map OSD pixel back to virtual coordinate, use center of pixel
+ VirtX=(OsdX-Display->OffsetX)*Display->ScaleX+Display->ScaleX/2;
+ VirtY=(OsdY-Display->OffsetY)*Display->ScaleY+Display->ScaleY/2;
+}
+
+inline void cDisplay::cVirtualCoordinate::IncPixelX(cDisplay *Display) {
+ // Move one OSD pixel
+ OsdX++;
+ VirtX+=Display->ScaleX;
+}
+inline void cDisplay::cVirtualCoordinate::IncPixelY(cDisplay *Display) {
+ // Move one OSD pixel
+ OsdY++;
+ VirtY+=Display->ScaleY;
+}
+
+#endif
diff --git a/i18n.c b/i18n.c
new file mode 100644
index 0000000..1d64b59
--- /dev/null
+++ b/i18n.c
@@ -0,0 +1,445 @@
+/*
+ * i18n.c: Internationalization
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.c 1.3 2002/06/23 13:05:59 kls Exp $
+ */
+
+#include "i18n.h"
+
+const tI18nPhrase Phrases[] = {
+ { "Page", //English
+ "Seite", //German
+ "", //Slovenian
+ "Pagina", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Page", //French
+ "", //Norwegian
+ "Sivua", //Finnish
+ "", //Polish
+ "Página", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Pàgina", //Catalan
+ "ÁâàÐÝØæÐ", //Russian
+ },
+ { "not found", //English
+ "nicht gefunden", //German
+ "", //Slovenian
+ "non trovata", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "pas trouvé", //French
+ "", //Norwegian
+ "ei löydy", //Finnish
+ "", //Polish
+ "no encontrada", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "no trobada", //Catalan
+ "ÝÕ ÝÐÙÔÕÝÐ", //Russian
+ },
+ { "Teletext (OSD)", //English
+ "Videotext (OSD)", //German
+ "", //Slovenian
+ "Teletext (OSD)", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Teletext (OSD)", //French
+ "", //Norwegian
+ "Teksti-TV", //Finnish
+ "", //Polish
+ "Teletexto (OSD)",//Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Teletext (OSD)", //Catalan
+ "ÂÕÛÕâÕÚáâ", //Russian
+ },
+ { "Zoom", //English
+ "Vergrößern", //German
+ "", //Slovenian
+ "Zoom", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Zoom", //French
+ "", //Norwegian
+ "Suurenna", //Finnish
+ "", //Polish
+ "Zoom", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Zoom", //Catalan
+ "ãÒÕÛØçØâì", //Russian
+ },
+ { "Half page", //English
+ "Halbe Seite", //German
+ "", //Slovenian
+ "Mezza pagina", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Demi-Page", //French
+ "", //Norwegian
+ "Puolikas sivu", //Finnish
+ "", //Polish
+ "Media página", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Mitja pàgina", //Catalan
+ "ßÞÛ-áâàÐÝØæë", //Russian
+ },
+ { "Change channel", //English
+ "Kanal wechseln", //German
+ "", //Slovenian
+ "Cambio canale", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Changer la chaîne", //French
+ "", //Norwegian
+ "Vaihda kanavaa", //Finnish
+ "", //Polish
+ "Cambio cadena", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Canvi cadena", //Catalan
+ "ßÕàÕÚÛîçØâì ÚÐÝÐÛ", //Russian
+ },
+ { "Jump to...", //English
+ "Springe zu...", //German
+ "", //Slovenian
+ "Salta a...", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Aller à...", //French
+ "", //Norwegian
+ "Siirry sivulle...", //Finnish
+ "", //Polish
+ "Salta a...", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Salta a...", //Catalan
+ "ßÕàÕÙâØ Ú...", //Russian
+ },
+ { "Background transparency", //English
+ "Hintergrund-Transparenz", //German
+ "", //Slovenian
+ "Trasparenza dello sfondo", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Fond transparent", //French
+ "", //Norwegian
+ "Taustan läpinäkyvyys", //Finnish
+ "", //Polish
+ "Transparencia del fondo", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Transparència del fons", //Catalan
+ "ÁâÕßÕÝì ßàÞ×àÐçÝÞáâØ äÞÝÐ", //Russian
+ },
+ { "Red key", //English
+ "Rote Taste", //German
+ "", //Slovenian
+ "Tasto Rosso", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Touche rouge", //French
+ "", //Norwegian
+ "Punainen näppäin", //Finnish
+ "", //Polish
+ "Tecla roja", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Tecla vermella", //Catalan
+ "ºàÐáÝÐï ÚÝÞßÚÐ", //Russian
+ },
+ { " Page number", //English
+ " Seitenzahl", //German
+ "", //Slovenian
+ " Numero di pagina", //Italian
+ "", //Dutch
+ "", //Portuguese
+ " Nombre de pages", //French
+ "", //Norwegian
+ " Sivunumero", //Finnish
+ "", //Polish
+ " Número de página", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ " Nombre de pàgina", //Catalan
+ " ½ÞÜÕà áâàÐÝØæë", //Russian
+ },
+ { "Green key", //English
+ "Grüne Taste", //German
+ "", //Slovenian
+ "Tasto Verde", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Touche verte", //French
+ "", //Norwegian
+ "Vihreä näppäin", //Finnish
+ "", //Polish
+ "Tecla verde", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Tecla verda", //Catalan
+ "·ÕÛñÝÐï ÚÝÞßÚÐ", //Russian
+ },
+ { "Yellow key", //English
+ "Gelbe Taste", //German
+ "", //Slovenian
+ "Tasto Giallo", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Touche jaune", //French
+ "", //Norwegian
+ "Keltainen näppäin", //Finnish
+ "", //Polish
+ "Tecla amarilla", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Tecla groga", //Catalan
+ "¶ñÛâÐï ÚÝÞßÚÐ", //Russian
+ },
+ { "Blue key", //English
+ "Blaue Taste", //German
+ "", //Slovenian
+ "Tasto Blu", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Touche bleue", //French
+ "", //Norwegian
+ "Sininen näppäin", //Finnish
+ "", //Polish
+ "Tecla azul", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Tecla blava", //Catalan
+ "ÁØÝïï ÚÝÞßÚÐ", //Russian
+ },
+ { "Channel (press OK): ", //English
+ "Sender (OK drücken): ", //German
+ "", //Slovenian
+ "Canale (premere OK)", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Chaine (Appuyer sur OK): ", //French
+ "", //Norwegian
+ "Kanava (paina OK):", //Finnish
+ "", //Polish
+ "Canal (pulse OK):", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Canal (premi OK):", //Catalan
+ "ºÐÝÐÛ (½ÐÖÜØâÕ ¾º)", //Russian
+ },
+ { "Show clock", //English
+ "Uhr anzeigen", //German
+ "", //Slovenian
+ "Visualizza la hora", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Afficher l'heure", //French
+ "", //Norwegian
+ "Näytä kello", //Finnish
+ "", //Polish
+ "Visualiza el reloj", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Visualitza l'hora", //Catalan
+ "¿ÞÚÐ×ëÒÐâì çÐáë", //Russian
+ },
+ { "Setup$Suspend receiving", //English
+ "Empfang unterbrechen", //German
+ "", //Slovenian
+ "Sospendi ricezione", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Suspension de la réception", //French
+ "", //Norwegian
+ "Keskeytä vastaanottaminen", //Finnish
+ "", //Polish
+ "Suspende la recepción", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Suspèn la recepció", //Catalan
+ "¿àØÞáâÐÝÞÒØâì ßàØñÜ", //Russian
+ },
+ { "Suspend receiving", //English
+ "Empfang unterbrechen", //German
+ "", //Slovenian
+ "Sospendi ricezione", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Suspension de la réception", //French
+ "", //Norwegian
+ "Keskeytä vastaanottaminen", //Finnish
+ "", //Polish
+ "Suspende la recepción", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Suspèn la recepció", //Catalan
+ "ßàØÞáâÐÝÞÒØâì ßàØñÜ", //Russian
+ },
+ { "Switch background", //English
+ "Hintergrund ändern", //German
+ "", //Slovenian
+ "Cambia sfondo", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Change le fond d'écran", //French
+ "", //Norwegian
+ "Vaihda tausta", //Finnish
+ "", //Polish
+ "Cambia el fondo", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Canvia el fons", //Catalan
+ "ÝÕßàÞ×àÐçÝëÙ äÞÝ", //Russian
+ },
+ { "Auto-update pages", //English
+ "Seiten aktualisieren", //German
+ "", //Slovenian
+ "Aggiornamento pagina automatico", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "Mise a jour des pages", //French
+ "", //Norwegian
+ "Automaattinen sivupäivitys", //Finnish
+ "Actualización páginas automática", //Polish
+ "", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Actualització pàgines automàtica", //Catalan
+ "°ÒâÞÞÑÝÞÒÛÕÝØÕ áâàÐÝØæ", //Russian
+ },
+ { "OSD height", //English
+ "OSD-Höhe", //German
+ "", //Slovenian
+ "Altezza OSD", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "OSD Hauteur", //French
+ "", //Norwegian
+ "Korkeus", //Finnish
+ "", //Polish
+ "Altura OSD", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Altura OSD", //Catalan
+ "²ëáÞâÐ ÜÕÝî", //Russian
+ },
+ { "OSD width", //English
+ "OSD-Breite", //German
+ "", //Slovenian
+ "Larghezza OSD", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "OSD Largeur", //French
+ "", //Norwegian
+ "Leveys", //Finnish
+ "", //Polish
+ "Anchura OSD", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Amplària OSD", //Catalan
+ "ÈØàØÝÐ ÜÕÝî", //Russian
+ },
+ { "OSD horizontal align", //English
+ "OSD horizontale Anordnung", //German
+ "", //Slovenian
+ "", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "", //French
+ "", //Norwegian
+ "Pystykeskitys", //Finnish
+ "", //Polish
+ "", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "", //Catalan
+ "", //Russian
+ },
+ { "OSD vertical align", //English
+ "OSD vertikale Anordnung", //German
+ "", //Slovenian
+ "", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "", //French
+ "", //Norwegian
+ "Vaakakeskitys", //Finnish
+ "", //Polish
+ "", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "", //Catalan
+ "", //Russian
+ },
+ { "Displays teletext on the OSD", //English
+ "Zeigt den Videotext auf dem OSD an", //German
+ "", //Slovenian
+ "", //Italian
+ "", //Dutch
+ "", //Portuguese
+ "", //French
+ "", //Norwegian
+ "Teksti-TV (OSD)", //Finnish
+ "", //Polish
+ "Visualiza el teletexto en el OSD", //Spanish
+ "", //Greek
+ "", //Swedish
+ "", //Romanian
+ "", //Hugarian
+ "Visualitza el teletext en l'OSD", //Catalan
+ "¿ÞÚÐ× âÕÛÕâÕÚáâÐ Ò ÜÕÝî", //Russian
+ },
+ { NULL }
+ };
diff --git a/i18n.h b/i18n.h
new file mode 100644
index 0000000..577628a
--- /dev/null
+++ b/i18n.h
@@ -0,0 +1,16 @@
+/*
+ * i18n.h: Internationalization
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.h 1.2 2002/05/11 14:48:16 kls Exp $
+ */
+
+#ifndef _I18N__H
+#define _I18N__H
+
+#include <vdr/i18n.h>
+
+extern const tI18nPhrase Phrases[];
+
+#endif //_I18N__H
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..cfefff7
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,681 @@
+/***************************************************************************
+ * Copyright (c) 2003,2004 by Marcel Wiesweg *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <map>
+#include <time.h>
+
+#include <vdr/interface.h>
+#include <vdr/i18n.h>
+#include <vdr/config.h>
+
+#include "menu.h"
+#include "display.h"
+#include "setup.h"
+#include "txtrecv.h"
+
+
+#define TXTROOT "/vtx"
+
+#define GET_HUNDREDS(x) ( ( (x) - ((x)%256) ) /256 )
+#define GET_TENS(x) ( (( (x) - ((x)%16) )%256 ) /16 )
+#define GET_ONES(x) ( (x)%16 )
+
+#define GET_HUNDREDS_DECIMAL(x) ( ( (x) - ((x)%100) ) /100 )
+#define GET_TENS_DECIMAL(x) ( (( (x) - ((x)%10) )%100 ) /10 )
+#define GET_ONES_DECIMAL(x) ( (x)%10 )
+
+#define PSEUDO_HEX_TO_DECIMAL(x) ( (GET_HUNDREDS_DECIMAL(x))*256 + (GET_TENS_DECIMAL(x))*16 + (GET_ONES_DECIMAL(x)) )
+
+using namespace std;
+
+int Stretch = true;
+typedef map<int,int> IntMap;
+IntMap channelPageMap;
+
+//static variables
+int TeletextBrowser::currentPage=0x100; //Believe it or not, the teletext numbers are somehow hexadecimal
+int TeletextBrowser::currentSubPage=0;
+tChannelID TeletextBrowser::channel;
+int TeletextBrowser::currentChannelNumber=0;
+TeletextBrowser* TeletextBrowser::self=0;
+
+
+TeletextBrowser::TeletextBrowser(cTxtStatus *txtSt) {
+ cursorPos=0;
+ pageFound=true;
+ selectingChannel=false;
+ needClearMessage=false;
+ selectingChannelNumber=-1;
+ self=this;
+ txtStatus=txtSt;
+ //if (txtStatus)
+ // txtStatus->ForceReceiving(true);
+ suspendedReceiving=false;
+ previousPage=currentPage;
+ previousSubPage=currentSubPage;
+ pageBeforeNumberInput=currentPage;
+ lastActivity=time(NULL);
+ inactivityTimeout=-1;
+}
+
+
+TeletextBrowser::~TeletextBrowser() {
+ Display::Delete();
+
+ self=0;
+ /*if (txtStatus) {
+ if (suspendedReceiving)
+ txtStatus->ForceSuspending(false);
+ txtStatus->ForceReceiving(false);
+ }*/
+}
+
+void TeletextBrowser::Show(void) {
+ Display::SetMode(Display::mode);
+ ShowPage();
+}
+
+bool TeletextBrowser::CheckIsValidChannel(int number) {
+ return (Channels.GetByNumber(number) != 0);
+}
+
+void TeletextBrowser::ChannelSwitched(int ChannelNumber) {
+ cChannel *chan=Channels.GetByNumber(ChannelNumber);
+
+ if (!chan)
+ return;
+
+ tChannelID chid=chan->GetChannelID();
+ if (chid==channel || chid==tChannelID::InvalidID)
+ return;
+
+ channel=chid;
+
+ //store page number of current channel
+ IntMap::iterator it;
+ channelPageMap[currentChannelNumber] = currentPage;
+ currentChannelNumber=ChannelNumber;
+
+ currentPage=0x100;
+ currentSubPage=0;
+
+ //see if last page number on this channel was stored
+ it=channelPageMap.find(ChannelNumber);
+ if (it != channelPageMap.end()) { //found
+ currentPage=(*it).second;
+ }
+
+ //on the one hand this must work in background mode, when the plugin is not active.
+ //on the other hand, if active, the page should be shown.
+ //so this self-Pointer.
+ if (self) {
+ self->ShowPage();
+ }
+}
+
+
+eOSState TeletextBrowser::ProcessKey(eKeys Key) {
+ if (Key != kNone)
+ lastActivity = time(NULL);
+
+ switch (Key) {
+ case k1: SetNumber(1);break;
+ case k2: SetNumber(2);break;
+ case k3: SetNumber(3);break;
+ case k4: SetNumber(4);break;
+ case k5: SetNumber(5);break;
+ case k6: SetNumber(6);break;
+ case k7: SetNumber(7);break;
+ case k8: SetNumber(8);break;
+ case k9: SetNumber(9);break;
+ case k0:
+ //same behavior for 0 as VDR does it with channels
+ if ((cursorPos==0) && (!selectingChannel)) {
+ //swap variables
+ int tempPage=currentPage;
+ int tempSubPage=currentSubPage;
+ currentPage=previousPage;
+ currentSubPage=previousSubPage;
+ previousPage=tempPage;
+ previousSubPage=tempSubPage;
+ ShowPage();
+ } else
+ SetNumber(0);
+ break;
+ case kOk:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ if (selectingChannelNumber>0) {
+ if (CheckIsValidChannel(selectingChannelNumber))
+ ChannelSwitched(selectingChannelNumber);
+ else {
+ needClearMessage=true;
+ //string tranlated in VDR's i18n.c
+ Display::DrawMessage(tr("*** Invalid Channel ***"));
+ }
+ } else {
+ ShowPage();
+ }
+ }
+ break;
+ case kBack: return osEnd;
+ case kNone: //approx. every second
+ //checking if page changed
+ if ( pageFound && ttSetup.autoUpdatePage && cursorPos==0 && !selectingChannel && (PageCheckSum() != checkSum) ) {
+ ShowPage();
+ //check if page was previously not found and is available now
+ } else if (!pageFound && CheckFirstSubPage(0)) {
+ ShowPage();
+ } else {
+ if (needClearMessage) {
+ needClearMessage=false;
+ Display::ClearMessage();
+ }
+ //updating clock
+ UpdateClock();
+ }
+ //check for activity timeout
+ if (ttSetup.inactivityTimeout && (time(NULL) - lastActivity > ttSetup.inactivityTimeout*60))
+ return osEnd;
+ break;
+ case kUp:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+
+ if (cursorPos != 0) {
+ //fully revert cursor
+ SetNumber(-3);
+ }
+ ChangePageRelative(DirectionForward);
+ Display::ShowUpperHalf();
+ ShowPage();
+ break;
+ case kDown:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+ if (cursorPos != 0) {
+ //fully reset
+ SetNumber(-3);
+ }
+ ChangePageRelative(DirectionBackward);
+ Display::ShowUpperHalf();
+ ShowPage();
+ break;
+ case kRight:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+ if (cursorPos != 0) {
+ //fully reset
+ SetNumber(-3);
+ }
+ ChangeSubPageRelative(DirectionForward);
+ Display::ShowUpperHalf();
+ ShowPage();
+ break;
+ case kLeft:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+ if (cursorPos != 0) {
+ //revert cursor
+ SetNumber(-1);
+ break;
+ }
+ ChangeSubPageRelative(DirectionBackward);
+ Display::ShowUpperHalf();
+ ShowPage();
+ break;
+
+
+ case kRed:
+ case kGreen:
+ case kBlue:
+ case kYellow:
+ //case kUser1:case kUser2:case kUser3:case kUser4:case kUser5:
+ //case kUser6:case kUser7:case kUser8:case kUser9:
+ case kPlay:case kPause:case kStop: case kRecord:case kFastFwd:case kFastRew:
+ if (cursorPos != 0) {
+ //fully reset
+ SetNumber(-3);
+ }
+ ExecuteAction(TranslateKey(Key));
+ break;
+ default: break;
+ }
+ return osContinue;
+}
+
+void TeletextBrowser::ExecuteAction(eTeletextAction e) {
+ switch (e) {
+ case Zoom:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+
+ switch (Display::GetZoom()) {
+ case cDisplay::Zoom_Off:
+ Display::SetZoom(cDisplay::Zoom_Upper);
+ break;
+ case cDisplay::Zoom_Upper:
+ Display::SetZoom(cDisplay::Zoom_Lower);
+ break;
+ case cDisplay::Zoom_Lower:
+ Display::SetZoom(cDisplay::Zoom_Off);
+ break;
+ }
+
+ break;
+ case HalfPage:
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+
+ switch (Display::mode) {
+ case Display::HalfUpper:
+ Display::SetMode(Display::HalfLower);
+ break;
+ case Display::HalfLower:
+ Display::SetMode(Display::Full);
+ break;
+ case Display::Full:
+ Display::SetMode(Display::HalfUpper);
+ break;
+ }
+ ShowPage();
+ break;
+ case SwitchChannel:
+ selectingChannelNumber=0;
+ selectingChannel=true;
+ ShowAskForChannel();
+ break;
+ /*case SuspendReceiving:
+ if (!txtStatus)
+ break;
+ //if (suspendedReceiving)
+ // txtStatus->ForceSuspending(false);
+ //else
+ // txtStatus->ForceSuspending(true);
+ //suspendedReceiving=(!suspendedReceiving);
+ break;*/
+ case DarkScreen:
+ if (Display::GetBackgroundColor() == clrBlack)
+ Display::SetBackgroundColor((tColor)ttSetup.configuredClrBackground);
+ else
+ Display::SetBackgroundColor(clrBlack);
+ break;
+ default:
+ //In osdteletext.c, numbers are thought to be decimal, the setup page
+ //entries will display them in this way. It is a lot easier to do the
+ //conversion to hexadecimal here.
+ //This means, we convert the number to what it would be if the string
+ //had been parsed with hexadecimal base.
+ int pageNr=PSEUDO_HEX_TO_DECIMAL((int)e);
+ if (0x100<=pageNr<=0x899) {
+ if (selectingChannel) {
+ selectingChannel=false;
+ Display::ClearMessage();
+ }
+ SetPreviousPage(currentPage, currentSubPage, pageNr);
+ currentPage=pageNr;
+ cursorPos=0;
+ currentSubPage=0;
+
+ Display::ShowUpperHalf();
+ ShowPage();
+ }
+ break;
+ }
+}
+
+eTeletextAction TeletextBrowser::TranslateKey(eKeys Key) {
+ switch(Key) {
+ case kRed: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyRed];
+ case kGreen: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyGreen];
+ case kYellow: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyYellow];
+ case kBlue: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyBlue];
+ case kPlay: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyPlay];
+ //case kPause: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyPause];
+ case kStop: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyStop];
+ //case kRecord: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyRecord];
+ case kFastFwd: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyFastFwd];
+ case kFastRew: return (eTeletextAction)ttSetup.mapKeyToAction[ActionKeyFastRew];
+ default: return (eTeletextAction)100; //just to keep gcc quiet
+ }
+}
+
+
+void TeletextBrowser::SetNumber(int i) {
+ //cursorPos means insertion after, 0<=cursorPos<=2
+ if (selectingChannel) {
+ selectingChannelNumber = selectingChannelNumber*10+i;
+ ShowAskForChannel();
+ return;
+ }
+
+ //i<0 means revert cursor position
+ if (i<0) {
+ for (;i<0;i++) {
+ switch (cursorPos) {
+ case 0:
+ return;
+ case 1:
+ currentPage = currentPage-256*GET_HUNDREDS(currentPage)+256*GET_HUNDREDS(pageBeforeNumberInput);
+ break;
+ case 2:
+ currentPage = currentPage-16*GET_TENS(currentPage)+16*GET_TENS(pageBeforeNumberInput);
+ break;
+ }
+ cursorPos--;
+ }
+ ShowPageNumber();
+ return;
+ }
+
+
+ static int tempPage;
+ switch (cursorPos) {
+ case 0:
+ if (i<1) i=1;
+ //accept no 9 when cursorPos==0
+ if (i>8) i=8;
+ tempPage= currentPage;
+ pageBeforeNumberInput = currentPage;
+ currentPage = currentPage-256*GET_HUNDREDS(currentPage)+256*i;
+ break;
+ case 1:
+ if (i<0) i=0;
+ if (i>9) i=9;
+ currentPage = currentPage-16*GET_TENS(currentPage)+16*i;
+ break;
+ case 2:
+ if (i<0) i=0;
+ if (i>9) i=9;
+ currentPage = currentPage-GET_ONES(currentPage)+i;
+ pageBeforeNumberInput = currentPage;
+ SetPreviousPage(tempPage, currentSubPage, currentPage);
+ break;
+ }
+ pageFound=true; //so that "page ... not found" is not displayed, but e.g. 1**-00
+ if (++cursorPos>2) {
+ cursorPos=0;
+ CheckFirstSubPage(0);
+ Display::ShowUpperHalf();
+ ShowPage();
+ } else {
+ ShowPageNumber();
+ }
+}
+
+//returns whether x, when written in hexadecimal form,
+//will only contain the digits 0...9 and not A...F
+//in the first three digits.
+static inline bool onlyDecimalDigits(int x) {
+ return (( x & 0xE) < 0xA) &&
+ (( (x>>4) & 0xE) < 0xA) &&
+ (( (x>>8) & 0xE) < 0xA);
+}
+
+//after 199 comes 1A0, but if these pages exist, they contain no useful data, so filter them out
+int TeletextBrowser::nextValidPageNumber(int start, Direction direction) {
+ do {
+ switch (direction) {
+ case DirectionForward:
+ start++;
+ break;
+ case DirectionBackward:
+ start--;
+ break;
+ }
+ } while (!onlyDecimalDigits(start));
+ return start;
+}
+
+void TeletextBrowser::ChangePageRelative(Direction direction)
+{
+ int oldpage = currentPage;
+ int oldSubPage = currentSubPage;
+
+ do {
+ /*if (back)
+ currentPage--;
+ else
+ currentPage++;*/
+ currentPage=nextValidPageNumber(currentPage, direction);
+ if (currentPage>0x899) currentPage=0x100;
+ if (currentPage<0x100) currentPage=0x899;
+ // sub page is always 0 if you change the page
+ if (CheckFirstSubPage(0)) {
+ SetPreviousPage(oldpage, oldSubPage, currentPage);
+ return;
+ }
+ } while (currentPage != oldpage);
+
+ return;
+}
+
+void TeletextBrowser::ChangeSubPageRelative(Direction direction)
+{
+ int oldsubpage = currentSubPage;
+
+ do {
+ /*if (back)
+ currentSubPage--;
+ else
+ currentSubPage++;*/
+ currentSubPage=nextValidPageNumber(currentSubPage, direction);
+ if (currentSubPage > 0x99) currentSubPage=0;
+ if (currentSubPage < 0) currentSubPage=0x99;
+
+ if (CheckPage())
+ return;
+ } while (currentSubPage != oldsubpage);
+
+ return;
+}
+
+bool TeletextBrowser::CheckFirstSubPage(int startWith) {
+ int oldsubpage = currentSubPage;
+
+ do {
+ if (CheckPage())
+ return true;
+ //currentSubPage++;
+ currentSubPage=nextValidPageNumber(currentSubPage, DirectionForward);
+
+ if (currentSubPage > 0x99) currentSubPage=0;
+ if (currentSubPage < 0) currentSubPage=0x99;
+
+ } while (currentSubPage != oldsubpage);
+
+ return false;
+}
+
+bool TeletextBrowser::CheckPage()
+{
+ StorageHandle fd;
+
+ Storage *s=Storage::instance();
+ if (!(fd=s->openForReading(PageID(channel, currentPage, currentSubPage), false)) )
+ return false;
+
+ s->close(fd);
+ return true;
+}
+
+//sets the previousPage variables if and only if new page is different from old page
+void TeletextBrowser::SetPreviousPage(int oldPage, int oldSubPage, int newPage) {
+ if (oldPage != newPage) {
+ previousPage=oldPage;
+ previousSubPage=oldSubPage;
+ }
+}
+
+
+
+
+void TeletextBrowser::ShowPage() {
+ if ((pageFound=DecodePage())) {
+ if (ttSetup.autoUpdatePage)
+ checkSum=PageCheckSum();
+ }
+}
+
+void TeletextBrowser::ShowPageNumber() {
+ char str[8];
+ sprintf(str, "%3x-%02x", currentPage, currentSubPage);
+ if (cursorPos>0) {
+ str[2]='*';
+ if (cursorPos==1)
+ str[1]='*';
+ }
+ Display::DrawPageId(str);
+}
+
+void TeletextBrowser::ShowAskForChannel() {
+ if (selectingChannel) {
+ char *str;
+ if (selectingChannelNumber>0)
+ asprintf(&str,"%s%d", tr("Channel (press OK): "), selectingChannelNumber);
+ else
+ asprintf(&str,"%s", tr("Channel (press OK): ") );
+ Display::DrawMessage(str);
+ free(str);
+ }
+}
+
+//this is taken and adapted from the teletext plugin since it uses its data
+bool TeletextBrowser::DecodePage() {
+ // Load the page and decodes it
+ #ifdef timingdebug
+ cTime t;
+ t.Start();
+ #endif
+
+ unsigned char cache[40*24+12];
+ StorageHandle fd;
+ // Take a look if there is a xxx-00 page
+ Storage *s=Storage::instance();
+ if (currentSubPage==0) {
+ if ( !(fd=s->openForReading(PageID(channel, currentPage,currentSubPage), false)) ) {
+ // There is no subpage 0 so look if there is subpage 1
+ currentSubPage++;
+ // Generate file string
+ } else {
+ // yes file exists
+ s->close(fd);
+ }
+ }
+
+ if ( (fd=s->openForReading(PageID(channel, currentPage, currentSubPage), true)) )
+ {
+ s->read(cache,sizeof cache,fd); // Read full page data
+ s->close(fd);
+
+ Display::HoldFlush();
+ Display::ClearMessage();
+ Display::RenderTeletextCode(cache);
+ ShowPageNumber();
+ UpdateClock();
+ Display::ReleaseFlush();
+
+ #ifdef timingdebug
+ t.Stop("Full Page Update");
+ #endif
+ } else {
+ // page doesn't exist
+ currentSubPage--;
+
+ Display::HoldFlush();
+ ShowPageNumber();
+ char str[80];
+ snprintf(str,80, "%s %3x-%02x %s",tr("Page"),currentPage, currentSubPage,tr("not found"));
+ Display::DrawMessage(str);
+ Display::ReleaseFlush();
+
+ return false;
+ }
+ return true;
+}
+
+
+
+int TeletextBrowser::PageCheckSum() {
+ int retSum=0;
+ StorageHandle fd;
+
+ CheckFirstSubPage(currentSubPage);
+
+ Storage *s=Storage::instance();
+ if ((fd=s->openForReading(PageID(channel, currentPage, currentSubPage), false)) ) {
+ uchar cache[960];
+ s->read(cache, 12, fd); //skip
+ s->read(cache, sizeof(cache), fd);
+ s->close(fd);
+ memset(cache+12, 0, 8); //it seems that there the clock is transmitted, ignore changes
+ for (uint i=0;i<sizeof(cache); i++)
+ retSum+=cache[i];
+ }
+ return retSum;
+}
+
+void TeletextBrowser::UpdateClock() {
+ if ( ttSetup.showClock )
+ Display::DrawClock();
+}
+
+
+ChannelStatus::ChannelStatus()
+{
+}
+
+
+void ChannelStatus::ChannelSwitch(const cDevice *Device, int ChannelNumber) {
+ if (Device->IsPrimaryDevice() && ChannelNumber>0)
+ TeletextBrowser::ChannelSwitched(ChannelNumber);
+}
+
+TeletextSetup ttSetup;
+
+TeletextSetup::TeletextSetup() {
+ //Set default values for setup options
+
+ configuredClrBackground=clrGray50;
+
+ //init key bindings
+ for (int i=0;i<10;i++)
+ mapKeyToAction[0]=(eTeletextAction)0;
+ mapKeyToAction[3]=Zoom;
+ mapKeyToAction[2]=HalfPage;
+ mapKeyToAction[0]=SwitchChannel;
+
+ showClock=true;
+ suspendReceiving=false;
+ autoUpdatePage=true;
+ //OSDHeight+width default values given in Start()
+ OSDHAlign=50;
+ OSDVAlign=50;
+
+ //use the value set for VDR's min user inactivity.
+ //Initially this value could be changed via the plugin's setup, but I removed that
+ //because there is no advantage, but a possible problem when VDR's value is change
+ //after the plugin has stored its own value.
+ inactivityTimeout=Setup.MinUserInactivity;
+}
+
diff --git a/menu.h b/menu.h
new file mode 100644
index 0000000..0aaf3d1
--- /dev/null
+++ b/menu.h
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * Copyright (c) 2003,2004 by Marcel Wiesweg *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef OSDTELETEXT_MENU__H
+#define OSDTELETEXT_MENU__H
+
+#include <time.h>
+
+#include <vdr/osd.h>
+#include <vdr/osdbase.h>
+#include <vdr/status.h>
+
+#include "txtrecv.h"
+#include "setup.h"
+
+extern int Stretch;
+
+class ChannelStatus : public cStatus {
+public:
+ ChannelStatus();
+protected:
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+};
+
+
+class TeletextBrowser : public cOsdObject {
+public:
+ TeletextBrowser(cTxtStatus *txtSt);
+ ~TeletextBrowser();
+ void Show(void);
+ static void ChannelSwitched(int ChannelNumber);
+ virtual eOSState ProcessKey(eKeys Key);
+protected:
+ enum Direction { DirectionForward, DirectionBackward };
+ void SetNumber(int i);
+ void ShowPage();
+ void UpdateClock();
+ bool DecodePage();
+ void ChangePageRelative(Direction direction);
+ void ChangeSubPageRelative(Direction direction);
+ bool CheckPage();
+ void ShowAskForChannel();
+ bool CheckFirstSubPage(int startWith);
+ void SetPreviousPage(int oldPage, int oldSubPage, int newPage);
+ bool CheckIsValidChannel(int number);
+ int PageCheckSum();
+ void ShowPageNumber();
+ void ExecuteAction(eTeletextAction e);
+ int nextValidPageNumber(int start, Direction direction);
+ char fileName[PATH_MAX];
+ char page[40][24];
+ int cursorPos;
+ eTeletextAction TranslateKey(eKeys Key);
+ bool pageFound;
+ bool selectingChannel;
+ bool needClearMessage;
+ int selectingChannelNumber;
+ int checkSum;
+ cTxtStatus *txtStatus;
+ bool suspendedReceiving;
+ int previousPage;
+ int previousSubPage;
+ int pageBeforeNumberInput;
+ time_t lastActivity;
+ int inactivityTimeout;
+ static int currentPage;
+ static int currentSubPage;
+ static tChannelID channel;
+ static int currentChannelNumber;
+ static TeletextBrowser* self;
+};
+
+
+#endif
+
diff --git a/osdteletext.c b/osdteletext.c
new file mode 100644
index 0000000..a7dfbcd
--- /dev/null
+++ b/osdteletext.c
@@ -0,0 +1,481 @@
+/***************************************************************************
+ * Copyright (c) 2003,2004 by Marcel Wiesweg *
+ * (autogenerated code (c) Klaus Schmidinger)
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <vdr/plugin.h>
+#include <vdr/i18n.h>
+#include <vdr/keys.h>
+#include <vdr/config.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+#include "menu.h"
+#include "i18n.h"
+#include "txtrecv.h"
+#include "setup.h"
+
+static const char *VERSION = "0.5.1";
+static const char *DESCRIPTION = "Displays teletext on the OSD";
+static const char *MAINMENUENTRY = "Teletext (OSD)";
+
+class cPluginTeletextosd : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+ cTxtStatus *txtStatus;
+ ChannelStatus *channelStatus;
+ bool startReceiver;
+ void initTexts();
+public:
+ cPluginTeletextosd(void);
+ virtual ~cPluginTeletextosd();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return tr(DESCRIPTION); }
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual bool Start(void);
+ virtual void Housekeeping(void);
+ virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); }
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+};
+
+class cTeletextSetupPage;
+class ActionEdit {
+ public:
+ void Init(cTeletextSetupPage*, int, cMenuEditIntItem *, cMenuEditStraItem *);
+ cMenuEditStraItem *action;
+ cMenuEditIntItem *number;
+ bool visible;
+ };
+
+struct ActionKeyName {
+ const char *internalName;
+ const char *userName;
+};
+
+class cTeletextSetupPage : public cMenuSetupPage {
+friend class ActionEdit;
+private:
+ TeletextSetup temp;
+ int tempPageNumber[LastActionKey];
+ int tempConfiguredClrBackground; //must be a signed int
+protected:
+ virtual void Store(void);
+ ActionEdit ActionEdits[LastActionKey];
+ virtual eOSState ProcessKey(eKeys Key);
+public:
+ cTeletextSetupPage(void);
+ static const ActionKeyName *actionKeyNames;
+ static const char **modes;
+ //~cTeletextSetupPage(void);
+ //void SetItemVisible(cOsdItem *Item, bool visible, bool callDisplay=false);
+};
+
+const ActionKeyName *cTeletextSetupPage::actionKeyNames = 0;
+const char **cTeletextSetupPage::modes = 0;
+
+/*class MenuEditActionItem : public cMenuEditStraItem {
+public:
+ MenuEditActionItem(cTeletextSetupPage *parentMenu, cMenuEditIntItem *pageNumberMenuItem,
+ const char *Name, int *Value, int NumStrings, const char * const *Strings);
+protected:
+ virtual eOSState ProcessKey(eKeys Key);
+ cTeletextSetupPage *parent;
+ cMenuEditIntItem *pageNumberItem;
+};*/
+
+
+
+cPluginTeletextosd::cPluginTeletextosd(void)
+{
+ // Initialize any member variables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
+ txtStatus=0;
+ channelStatus=0;
+ startReceiver=true;
+}
+
+cPluginTeletextosd::~cPluginTeletextosd()
+{
+ // Clean up after yourself!
+ if (txtStatus)
+ delete txtStatus;
+ if (channelStatus)
+ delete channelStatus;
+ Storage::instance()->cleanUp();
+}
+
+const char *cPluginTeletextosd::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return " -d --directory=DIR The directory where the temporary\n"
+ " files will be stored.\n"
+ " (default: /vtx, recommended: /tmp/vtx\n"
+ " or /var/cache/vdr/osdteletext.)\n"
+ " Ensure that the directory exists and is writable.\n"
+ " -n --max-cache=NUM Maximum size in megabytes of cache used\n"
+ " to store the pages on the harddisk.\n"
+ " (default: a calculated value below 50 MB)\n"
+ " -s --cache-system=SYS Set the cache system to be used.\n"
+ " Choose \"legacy\" for the traditional\n"
+ " one-file-per-page system.\n"
+ " Default is \"packed\" for the \n"
+ " one-file-for-a-few-pages system.\n"
+ " -R, --no-receive Do not receive and store teletext\n"
+ " (deprecated - plugin will be useless).\n"
+ " -r, --receive (obsolete)\n";
+}
+
+bool cPluginTeletextosd::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ static struct option long_options[] = {
+ { "directory", required_argument, NULL, 'd' },
+ { "max-cache", required_argument, NULL, 'n' },
+ { "cache-system", required_argument, NULL, 's' },
+ { "no-receiver", no_argument, NULL, 'R' },
+ { "receive", no_argument, NULL, 'r' },
+ { NULL }
+ };
+
+ int c;
+ int maxStorage=-1;
+ while ((c = getopt_long(argc, argv, "s:d:n:Rr", long_options, NULL)) != -1) {
+ switch (c) {
+ case 's':
+ if (!optarg)
+ break;
+ if (strcasecmp(optarg, "legacy")==0)
+ Storage::setSystem(Storage::StorageSystemLegacy);
+ else if (strcasecmp(optarg, "packed")==0)
+ Storage::setSystem(Storage::StorageSystemPacked);
+ break;
+ case 'd': Storage::setRootDir(optarg);
+ break;
+ case 'n': if (isnumber(optarg)) {
+ int n = atoi(optarg);
+ maxStorage=n;
+ }
+ break;
+ case 'R': startReceiver=false;
+ break;
+ case 'r': startReceiver=true;
+ break;
+ }
+ }
+ //do this here because the option -s to change the storage system might be given
+ // after -n, and then -s would have no effect
+ if (maxStorage>=0)
+ Storage::instance()->setMaxStorage(maxStorage);
+ return true;
+}
+
+bool cPluginTeletextosd::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+ //Clean any files which might be remaining from the last session,
+ //perhaps due to a crash they have not been deleted.
+ Storage::instance()->init();
+ initTexts();
+ if (startReceiver)
+ txtStatus=new cTxtStatus();
+ channelStatus=new ChannelStatus();
+ if (ttSetup.OSDheight<=100) ttSetup.OSDheight=Setup.OSDHeight;
+ if (ttSetup.OSDwidth<=100) ttSetup.OSDwidth=Setup.OSDWidth;
+
+ return true;
+}
+
+void cPluginTeletextosd::initTexts() {
+ if (cTeletextSetupPage::actionKeyNames)
+ return;
+ RegisterI18n(Phrases);
+ //TODO: rewrite this in the xy[0].cd="fg"; form
+ static const ActionKeyName st_actionKeyNames[] =
+ {
+ { "Action_kRed", tr("Red key") },
+ { "Action_kGreen", tr("Green key") },
+ { "Action_kYellow", tr("Yellow key") },
+ { "Action_kBlue", tr("Blue key") },
+ { "Action_kPlay", tr(cKey::ToString( kPlay)) },
+ //{ "Action_kPause", tr(cKey::ToString( kPause)) },
+ { "Action_kStop", tr(cKey::ToString( kStop)) },
+ //{ "Action_kRecord", tr(cKey::ToString( kRecord)) },
+ { "Action_kFastFwd", tr(cKey::ToString( kFastFwd)) },
+ { "Action_kFastRew", tr(cKey::ToString( kFastRew)) }
+ };
+
+ cTeletextSetupPage::actionKeyNames = st_actionKeyNames;
+
+ static const char *st_modes[] =
+ {
+ tr("Zoom"),
+ tr("Half page"),
+ tr("Change channel"),
+ tr("Switch background"),
+ //tr("Suspend receiving"),
+ tr("Jump to...")
+ };
+
+ cTeletextSetupPage::modes = st_modes;
+}
+
+void cPluginTeletextosd::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+}
+
+cOsdObject *cPluginTeletextosd::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+ return new TeletextBrowser(txtStatus);
+}
+
+cMenuSetupPage *cPluginTeletextosd::SetupMenu(void)
+{
+ // Return a setup menu in case the plugin supports one.
+ return new cTeletextSetupPage;
+}
+
+
+
+bool cPluginTeletextosd::SetupParse(const char *Name, const char *Value)
+{
+ initTexts();
+ // Parse your own setup parameters and store their values.
+ //Stretch=true;
+ if (!strcasecmp(Name, "configuredClrBackground")) ttSetup.configuredClrBackground=( ((unsigned int)atoi(Value)) << 24);
+ /*else if (!strcasecmp(Name, "Action_kRed")) ttSetup.mapKeyToAction[0]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kGreen")) ttSetup.mapKeyToAction[1]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kYellow")) ttSetup.mapKeyToAction[2]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kBlue")) ttSetup.mapKeyToAction[3]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kPlay")) ttSetup.mapKeyToAction[4]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kPause")) ttSetup.mapKeyToAction[5]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kStop")) ttSetup.mapKeyToAction[6]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kRecord")) ttSetup.mapKeyToAction[7]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kFastFwd")) ttSetup.mapKeyToAction[8]=(eTeletextAction)atoi(Value);
+ else if (!strcasecmp(Name, "Action_kFastRew")) ttSetup.mapKeyToAction[9]=(eTeletextAction)atoi(Value);*/
+ else if (!strcasecmp(Name, "showClock")) ttSetup.showClock=atoi(Value);
+ //currently not used
+ else if (!strcasecmp(Name, "suspendReceiving")) ttSetup.suspendReceiving=atoi(Value);
+ else if (!strcasecmp(Name, "autoUpdatePage")) ttSetup.autoUpdatePage=atoi(Value);
+ else if (!strcasecmp(Name, "OSDheight")) ttSetup.OSDheight=atoi(Value);
+ else if (!strcasecmp(Name, "OSDwidth")) ttSetup.OSDwidth=atoi(Value);
+ else if (!strcasecmp(Name, "OSDHAlign")) ttSetup.OSDHAlign=atoi(Value);
+ else if (!strcasecmp(Name, "OSDVAlign")) ttSetup.OSDVAlign=atoi(Value);
+ else if (!strcasecmp(Name, "inactivityTimeout")) /*ttSetup.inactivityTimeout=atoi(Value)*/;
+ else {
+ for (int i=0;i<LastActionKey;i++) {
+ if (!strcasecmp(Name, cTeletextSetupPage::actionKeyNames[i].internalName)) {
+ ttSetup.mapKeyToAction[i]=(eTeletextAction)atoi(Value);
+
+ //for migration to 0.4
+ if (ttSetup.mapKeyToAction[i]<100 && ttSetup.mapKeyToAction[i]>=LastAction)
+ ttSetup.mapKeyToAction[i]=LastAction-1;
+
+ return true;
+ }
+ }
+
+ //for migration to 0.4
+ char act[7];
+ strncpy(act, Name, 7);
+ if (!strcasecmp(act, "Action_"))
+ return true;
+
+ return false;
+ }
+ return true;
+}
+
+void cTeletextSetupPage::Store(void) {
+ //copy table
+ for (int i=0;i<LastActionKey;i++) {
+ if (temp.mapKeyToAction[i] >= LastAction) //jump to page selected
+ ttSetup.mapKeyToAction[i]=(eTeletextAction)tempPageNumber[i];
+ else //one of the other modes selected
+ ttSetup.mapKeyToAction[i]=temp.mapKeyToAction[i];
+ }
+ ttSetup.configuredClrBackground=( ((unsigned int)tempConfiguredClrBackground) << 24);
+ ttSetup.showClock=temp.showClock;
+ ttSetup.suspendReceiving=temp.suspendReceiving;
+ ttSetup.autoUpdatePage=temp.autoUpdatePage;
+ ttSetup.OSDheight=temp.OSDheight;
+ ttSetup.OSDwidth=temp.OSDwidth;
+ ttSetup.OSDHAlign=temp.OSDHAlign;
+ ttSetup.OSDVAlign=temp.OSDVAlign;
+ //ttSetup.inactivityTimeout=temp.inactivityTimeout;
+
+ for (int i=0;i<LastActionKey;i++) {
+ SetupStore(actionKeyNames[i].internalName, ttSetup.mapKeyToAction[i]);
+ }
+ /*SetupStore("Action_kRed", ttSetup.mapKeyToAction[0]);
+ SetupStore("Action_kGreen", ttSetup.mapKeyToAction[1]);
+ SetupStore("Action_kYellow", ttSetup.mapKeyToAction[2]);
+ SetupStore("Action_kBlue", ttSetup.mapKeyToAction[3]);
+ SetupStore("Action_kPlay", ttSetup.mapKeyToAction[4]);
+ SetupStore("Action_kPause", ttSetup.mapKeyToAction[5]);
+ SetupStore("Action_kStop", ttSetup.mapKeyToAction[6]);
+ SetupStore("Action_kRecord", ttSetup.mapKeyToAction[7]);
+ SetupStore("Action_kFastFwd", ttSetup.mapKeyToAction[8]);
+ SetupStore("Action_kFastRew", ttSetup.mapKeyToAction[9]);*/
+ SetupStore("configuredClrBackground", (int)(ttSetup.configuredClrBackground >> 24));
+ SetupStore("showClock", ttSetup.showClock);
+ //currently not used
+ //SetupStore("suspendReceiving", ttSetup.suspendReceiving);
+ SetupStore("autoUpdatePage", ttSetup.autoUpdatePage);
+ SetupStore("OSDheight", ttSetup.OSDheight);
+ SetupStore("OSDwidth", ttSetup.OSDwidth);
+ SetupStore("OSDHAlign", ttSetup.OSDHAlign);
+ SetupStore("OSDVAlign", ttSetup.OSDVAlign);
+ //SetupStore("inactivityTimeout", ttSetup.inactivityTimeout);
+}
+
+
+cTeletextSetupPage::cTeletextSetupPage(void) {
+ //init tables
+ for (int i=0;i<LastActionKey;i++) {
+ if (ttSetup.mapKeyToAction[i] >= LastAction) {//jump to page selected
+ temp.mapKeyToAction[i]=LastAction; //to display the last string
+ tempPageNumber[i]=ttSetup.mapKeyToAction[i];
+ } else { //one of the other modes selected
+ temp.mapKeyToAction[i]=ttSetup.mapKeyToAction[i];
+ tempPageNumber[i]=100;
+ }
+ }
+ tempConfiguredClrBackground=(ttSetup.configuredClrBackground >> 24);
+ temp.showClock=ttSetup.showClock;
+ temp.suspendReceiving=ttSetup.suspendReceiving;
+ temp.autoUpdatePage=ttSetup.autoUpdatePage;
+ temp.OSDheight=ttSetup.OSDheight;
+ temp.OSDwidth=ttSetup.OSDwidth;
+ temp.OSDHAlign=ttSetup.OSDHAlign;
+ temp.OSDVAlign=ttSetup.OSDVAlign;
+ //temp.inactivityTimeout=ttSetup.inactivityTimeout;
+
+ Add(new cMenuEditIntItem(tr("Background transparency"), &tempConfiguredClrBackground, 0, 255));
+
+ Add(new cMenuEditBoolItem(tr("Show clock"), &temp.showClock ));
+
+ //Add(new cMenuEditBoolItem(tr("Setup$Suspend receiving"), &temp.suspendReceiving ));
+
+ Add(new cMenuEditBoolItem(tr("Auto-update pages"), &temp.autoUpdatePage ));
+
+ Add(new cMenuEditIntItem(tr("OSD height"), &temp.OSDheight, 250, MAXOSDHEIGHT));
+ Add(new cMenuEditIntItem(tr("OSD width"), &temp.OSDwidth, 320, MAXOSDWIDTH));
+
+ Add(new cMenuEditIntItem(tr("OSD horizontal align"), &temp.OSDHAlign, 0, 100));
+ Add(new cMenuEditIntItem(tr("OSD vertical align"), &temp.OSDVAlign, 0, 100));
+
+ //Using same string as VDR's setup menu
+ //Add(new cMenuEditIntItem(tr("Setup.Miscellaneous$Min. user inactivity (min)"), &temp.inactivityTimeout));
+
+ for (int i=0;i<LastActionKey;i++) {
+ ActionEdits[i].Init(this, i, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[i], 100, 899),
+ new cMenuEditStraItem(actionKeyNames[i].userName, (int*)&temp.mapKeyToAction[i], LastAction+1, modes) );
+ }
+
+ /*ActionEdits[0].Init(this, 0, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[0], 100, 899),
+ new cMenuEditStraItem(tr("Red key"), (int*)&temp.mapKeyToAction[0], LAST_ACTION+2, modes) );
+ //Add(tempItem);
+
+ ActionEdits[1].Init(this, 1, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[1], 100, 899),
+ new cMenuEditStraItem(tr("Green key"), (int*)&temp.mapKeyToAction[1], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[2].Init(this, 2, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[2], 100, 899),
+ new cMenuEditStraItem(tr("Yellow key"), (int*)&temp.mapKeyToAction[2], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[3].Init(this, 3, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[3], 100, 899),
+ new cMenuEditStraItem(tr("Blue key"), (int*)&temp.mapKeyToAction[3], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[4].Init(this, 4, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[4], 100, 899),
+ new cMenuEditStraItem(tr(cKey::ToString( kPlay)), (int*)&temp.mapKeyToAction[4], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[5].Init(this, 5, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[5], 100, 899),
+ new cMenuEditStraItem(tr(cKey::ToString( kPause)), (int*)&temp.mapKeyToAction[5], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[6].Init(this, 6, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[6], 100, 899),
+ new cMenuEditStraItem(tr(cKey::ToString(kStop)), (int*)&temp.mapKeyToAction[6], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[7].Init(this, 7, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[7], 100, 899),
+ new cMenuEditStraItem(tr(cKey::ToString(kRecord)), (int*)&temp.mapKeyToAction[7], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[8].Init(this, 8, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[8], 100, 899),
+ new cMenuEditStraItem(tr(cKey::ToString(kFastFwd)), (int*)&temp.mapKeyToAction[8], LAST_ACTION+2, modes));
+ //Add(tempItem);
+
+ ActionEdits[9].Init(this, 9, new cMenuEditIntItem(tr(" Page number"), &tempPageNumber[9], 100, 899),
+ new cMenuEditStraItem(tr(cKey::ToString(kFastRew)), (int*)&temp.mapKeyToAction[9], LAST_ACTION+2, modes));
+ //Add(tempItem);*/
+
+}
+
+eOSState cTeletextSetupPage::ProcessKey(eKeys Key) {
+ eOSState state = cMenuSetupPage::ProcessKey(Key);
+ if (Key != kRight && Key!=kLeft)
+ return state;
+ cOsdItem *item = Get(Current());
+ for (int i=0;i<LastActionKey;i++) {
+ if (ActionEdits[i].action==item) { //we have a key left/right and one of our items as current
+ //eOSState state = item->ProcessKey(Key);
+ //if (state != osUnknown) { //really should not return osUnknown I think
+ if (temp.mapKeyToAction[i] == LastAction && !ActionEdits[i].visible) {
+ //need to make it visible
+ if (i+1<LastActionKey)
+ //does not work for i==LastAction-1
+ Ins( ActionEdits[i].number, false, ActionEdits[i+1].action);
+ else
+ Add( ActionEdits[i].number, false );
+
+ ActionEdits[i].visible=true;
+ Display();
+ } else if (temp.mapKeyToAction[i] != LastAction && ActionEdits[i].visible) {
+ //need to hide it
+ cList<cOsdItem>::Del(ActionEdits[i].number, false);
+ ActionEdits[i].visible=false;
+ Display();
+ }
+ break;
+ //return state;
+ //}
+ }
+ }
+
+ return state;
+ //return cMenuSetupPage::ProcessKey(Key);
+}
+
+
+void ActionEdit::Init(cTeletextSetupPage* s, int num, cMenuEditIntItem *p, cMenuEditStraItem * a) {
+ action=a;
+ number=p;
+ s->Add(action);
+ if (s->temp.mapKeyToAction[num] == LastAction) {
+ s->Add(number);
+ visible=true;
+ } else
+ visible=false;
+}
+
+
+
+
+VDRPLUGINCREATOR(cPluginTeletextosd); // Don't touch this!
diff --git a/setup.h b/setup.h
new file mode 100644
index 0000000..f04488f
--- /dev/null
+++ b/setup.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef __SETUP_H
+#define __SETUP_H
+
+
+//There are two places to be kept in sync with these enums:
+//TeletextBrowser::TranslateKey and
+//the constants in cPluginTeletextosd::initTexts
+enum eTeletextAction { Zoom, HalfPage, SwitchChannel,
+ DarkScreen, /*SuspendReceiving,*/ LastAction }; //and 100-899 => jump to page
+
+enum ActionKeys {
+ActionKeyRed,
+ActionKeyGreen,
+ActionKeyYellow,
+ActionKeyBlue,
+ActionKeyPlay,
+//ActionKeyPause,
+ActionKeyStop,
+//ActionKeyRecord,
+ActionKeyFastFwd,
+ActionKeyFastRew,
+
+LastActionKey
+};
+
+/*
+kRed
+kGreen
+kYellow
+kBlue
+kPlay
+kPause
+kStop
+kRecord
+kFastFwd*/
+
+//Default values are set in menu.c, setup menu, parsing and storing can be found in osdteletext.c
+class TeletextSetup {
+public:
+ TeletextSetup();
+ int mapKeyToAction[10]; //4 color keys + kPlay, kPause etc.
+ unsigned int configuredClrBackground;
+ int showClock;
+ int suspendReceiving;
+ int autoUpdatePage;
+ int OSDheight;
+ int OSDwidth;
+ int OSDHAlign;
+ int OSDVAlign;
+ int inactivityTimeout;
+};
+
+extern TeletextSetup ttSetup;
+
+#endif
diff --git a/tables.h b/tables.h
new file mode 100644
index 0000000..08fe344
--- /dev/null
+++ b/tables.h
@@ -0,0 +1,112 @@
+/* This file is copied from Ralph Metzler's vbidecode package. */
+
+/*
+ tables.h - some data conversion tables for vbidecode
+*/
+
+#ifndef _TABLES_H
+#define _TABLES_H
+
+unsigned char invtab[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+};
+
+unsigned char unhamtab[256] = {
+ 0x01, 0xff, 0x81, 0x01, 0xff, 0x00, 0x01, 0xff,
+ 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07,
+ 0xff, 0x00, 0x01, 0xff, 0x00, 0x80, 0xff, 0x00,
+ 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff,
+ 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07,
+ 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x87,
+ 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff,
+ 0x86, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07,
+ 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09,
+ 0x02, 0x82, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff,
+ 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff,
+ 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x83, 0x03,
+ 0x04, 0xff, 0xff, 0x05, 0x84, 0x04, 0x04, 0xff,
+ 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07,
+ 0xff, 0x05, 0x05, 0x85, 0x04, 0xff, 0xff, 0x05,
+ 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff,
+ 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09,
+ 0x0a, 0xff, 0xff, 0x0b, 0x8a, 0x0a, 0x0a, 0xff,
+ 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff,
+ 0xff, 0x0b, 0x0b, 0x8b, 0x0a, 0xff, 0xff, 0x0b,
+ 0x0c, 0x8c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff,
+ 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07,
+ 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x8d, 0x0d,
+ 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff,
+ 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x89,
+ 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09,
+ 0x88, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09,
+ 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff,
+ 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09,
+ 0x0f, 0xff, 0x8f, 0x0f, 0xff, 0x0e, 0x0f, 0xff,
+ 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff,
+ 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x8e, 0xff, 0x0e,
+};
+
+unsigned char cct2vtx_table[] =
+ { 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f,
+
+ 0x30, 0x31, 0x32, 0x33,
+ 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0xef,
+
+ 0x40, 0x41, 0x42, 0x43,
+ 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x4f,
+
+ 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b,
+ 0x5c, 0x5d, 0x5e, 0x5f,
+
+ 0x60, 0x61, 0x62, 0x63,
+ 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b,
+ 0x6c, 0x6d, 0x6e, 0x6f,
+
+ 0x70, 0x71, 0x72, 0x73,
+ 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b,
+ 0x7c, 0x7d, 0x7e, 0x7f
+ };
+
+#endif
diff --git a/txtfont.c b/txtfont.c
new file mode 100644
index 0000000..438ff7d
--- /dev/null
+++ b/txtfont.c
@@ -0,0 +1,3371 @@
+#include "txtfont.h"
+
+unsigned int TXT_Mask[11]= {
+ 0x0000, // ************ ****
+ 0x39C0, // **###**###** ****
+ 0x39C0, // **###**###** ****
+ 0x0000, // ************ ****
+ 0x39C0, // **###**###** ****
+ 0x39C0, // **###**###** ****
+ 0x0000, // ************ ****
+ 0x39C0, // **###**###** ****
+ 0x39C0, // **###**###** ****
+ 0x0000 // ************ ****
+ };
+
+unsigned int TXT_Font[][11]= {
+ { // 0x20 = Leerzeichen
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x21 = !
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x22 = "
+ 0x0000, // ************ ****
+ 0x39C0, // **###**###** ****
+ 0x18C0, // ***##***##** ****
+ 0x3180, // **##***##*** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x23 = # = NC
+ 0x0000, // ************ ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x24 = $ = NC
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x6660, // *##**##**##* ****
+ 0x6600, // *##**##***** ****
+ 0x3FC0, // **########** ****
+ 0x0660, // *****##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ },
+ { // 0x25 = %
+ 0x0000, // ************ ****
+ 0x70C0, // *###****##** ****
+ 0xD980, // ##*##**##*** ****
+ 0x7300, // *###**##**** ****
+ 0x0600, // *****##***** ****
+ 0x0CE0, // ****##**###* ****
+ 0x19B0, // ***##**##*## ****
+ 0x30E0, // **##****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x26 = &
+ 0x0000, // ************ ****
+ 0x1E00, // ***####***** ****
+ 0x3300, // **##**##**** ****
+ 0x3300, // **##**##**** ****
+ 0x1E00, // ***####***** ****
+ 0x3330, // **##**##**## ****
+ 0x61C0, // *##****###** ****
+ 0x3F30, // **######**## ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x27 = '
+ 0x0000, // ************ ****
+ 0x0700, // *****###**** ****
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x28 = (
+ 0x0000, // ************ ****
+ 0x0700, // *****###**** ****
+ 0x0C00, // ****##****** ****
+ 0x1800, // ***##******* ****
+ 0x1800, // ***##******* ****
+ 0x1800, // ***##******* ****
+ 0x0C00, // ****##****** ****
+ 0x0700, // *****###**** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x29 = )
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0300, // ******##**** ****
+ 0x0180, // *******##*** ****
+ 0x0180, // *******##*** ****
+ 0x0180, // *******##*** ****
+ 0x0300, // ******##**** ****
+ 0x0E00, // ****###***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x2A = *
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x6660, // *##**##**##* ****
+ 0x36C0, // **##*##*##** ****
+ 0x0F00, // ****####**** ****
+ 0x36C0, // **##*##*##** ****
+ 0x6660, // *##**##**##* ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x2B = +
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x2C = ,
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3800, // **###******* ****
+ 0x1800, // ***##******* ****
+ 0x3000, // **##******** ****
+ },
+ { // 0x2D = -
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x2E = .
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x1800, // ***##******* ****
+ 0x1800, // ***##******* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x2F = /
+ 0x0000, // ************ ****
+ 0x00C0, // ********##** ****
+ 0x0180, // *******##*** ****
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0C00, // ****##****** ****
+ 0x1800, // ***##******* ****
+ 0x3000, // **##******** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+
+ { // 0x30 = 0
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x38E0, // **###***###* ****
+ 0x38E0, // **###***###* ****
+ 0x38E0, // **###***###* ****
+ 0x38E0, // **###***###* ****
+ 0x38E0, // **###***###* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x31 = 1
+ 0x0000, // ************ ****
+ 0x0700, // *****###**** ****
+ 0x1F00, // ***#####**** ****
+ 0x0700, // *****###**** ****
+ 0x0700, // *****###**** ****
+ 0x0700, // *****###**** ****
+ 0x0700, // *****###**** ****
+ 0x0700, // *****###**** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x32 = 2
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x30E0, // **##****###* ****
+ 0x00E0, // ********###* ****
+ 0x01C0, // *******###** ****
+ 0x0780, // *****####*** ****
+ 0x1E00, // ***####***** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x33 = 3
+ 0x0000, // ************ ****
+ 0x3FE0, // **#########* ****
+ 0x00C0, // ********##** ****
+ 0x0080, // *******##*** ****
+ 0x07E0, // *****######* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x34 = 4
+ 0x0000, // ************ ****
+ 0x00E0, // ********###* ****
+ 0x03C0, // ******####** ****
+ 0x0700, // *****###**** ****
+ 0x1C00, // ***###****** ****
+ 0x38E0, // **###***###* ****
+ 0x3FE0, // **#########* ****
+ 0x00E0, // ********###* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x35 = 5
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3FC0, // **########** ****
+ 0x00E0, // ********###* ****
+ 0x30E0, // **##****###* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x36 = 6
+ 0x0000, // ************ ****
+ 0x0700, // *****###**** ****
+ 0x0E00, // ****###***** ****
+ 0x1C00, // ***###****** ****
+ 0x3FC0, // **########** ****
+ 0x3860, // **###****##* ****
+ 0x3860, // **###****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x37 = 7
+ 0x0000, // ************ ****
+ 0x7FE0, // *##########* ****
+ 0x01C0, // *******###** ****
+ 0x0380, // ******###*** ****
+ 0x0700, // *****###**** ****
+ 0x0E00, // ****###***** ****
+ 0x1C00, // ***###****** ****
+ 0x3800, // **###******* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x38 = 8
+ 0x0000, // ************ ****
+ 0x0F80, // ****#####*** ****
+ 0x38E0, // **###***###* ****
+ 0x38E0, // **###***###* ****
+ 0x0F80, // ****#####*** ****
+ 0x38E0, // **###***###* ****
+ 0x38E0, // **###***###* ****
+ 0x0F80, // ****#####*** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x39 = 9
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x30E0, // **##****###* ****
+ 0x30E0, // **##****###* ****
+ 0x1FC0, // ***#######** ****
+ 0x0380, // ******###*** ****
+ 0x0700, // *****###**** ****
+ 0x0E00, // ****###***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x3A = :
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x0000, // ************ ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x3B = ;
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x1800, // ***##******* ****
+ },
+ { // 0x3C = <
+ 0x0000, // ************ ****
+ 0x00E0, // ********###* ****
+ 0x0380, // ******###*** ****
+ 0x0E00, // ****###***** ****
+ 0x3800, // **###******* ****
+ 0x0E00, // ****###***** ****
+ 0x0380, // ******###*** ****
+ 0x00E0, // ********###* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x3D = =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x3E = >
+ 0x0000, // ************ ****
+ 0x7000, // *###******** ****
+ 0x1C00, // ***###****** ****
+ 0x0700, // *****###**** ****
+ 0x01C0, // *******###** ****
+ 0x0700, // *****###**** ****
+ 0x1C00, // ***###****** ****
+ 0x7000, // *###******** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+ { // 0x3F = ?
+ 0x0000, // ************ ****
+ 0x1F80, // ***######*** ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x0180, // *******##*** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ },
+
+ { // 0x40 = § = NC
+ 0x0000, // ************ ****
+ 0x1F80, // ***######*** ****
+ 0x30C0, // **##****##** ****
+ 0x3000, // **##******** ****
+ 0x1F80, // ***######*** ****
+ 0x30C0, // **##****##** ****
+ 0x1F80, // ***######*** ****
+ 0x00C0, // ********##** ****
+ 0x30C0, // **##****##** ****
+ 0x1F80 // ***######*** ****
+ },
+ { // 0x41 = A
+ 0x0000, // ************ ****
+ 0x0F00, // ****####**** ****
+ 0x1980, // ***##**##*** ****
+ 0x30C0, // **##****##** ****
+ 0x6060, // *##******##* ****
+ 0x7FE0, // *##########* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x42 = B
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FC0, // **########** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x43 = C
+ 0x0000, // ************ ****
+ 0x0FC0, // ****######** ****
+ 0x1860, // ***##****##* ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x1860, // ***##****##* ****
+ 0x0FC0, // ****######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x44 = D
+ 0x0000, // ************ ****
+ 0x3F80, // **#######*** ****
+ 0x30C0, // **##****##** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30C0, // **##****##** ****
+ 0x3F80, // **#######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x45 = E
+ 0x0000, // ************ ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3F80, // **#######*** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x46 = F
+ 0x0000, // ************ ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3F80, // **#######*** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x47 = G
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x33E0, // **##**#####* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x48 = H
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x7FE0, // *##########* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x49 = I
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x4A = J
+ 0x0000, // ************ ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x4B = K
+ 0x0000, // ************ ****
+ 0x30E0, // **##****###* ****
+ 0x3180, // **##***##*** ****
+ 0x3700, // **##*###**** ****
+ 0x3C00, // **####****** ****
+ 0x3700, // **##*###**** ****
+ 0x3180, // **##***##*** ****
+ 0x30E0, // **##****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x4C = L
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x4D = M
+ 0x0000, // ************ ****
+ 0x70E0, // *###****###* ****
+ 0x79E0, // *####**####* ****
+ 0x6F60, // *##*####*##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x4E = N
+ 0x0000, // ************ ****
+ 0x7060, // *###*****##* ****
+ 0x7860, // *####****##* ****
+ 0x6C60, // *##*##***##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6360, // *##***##*##* ****
+ 0x61E0, // *##****####* ****
+ 0x60E0, // *##*****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x4F = O
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0x50 = P
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FC0, // **########** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x51 = Q
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3360, // **##**##*##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0180, // *******##*** ****
+ 0x00E0 // ********###* ****
+ },
+ { // 0x52 = R
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FC0, // **########** ****
+ 0x3300, // **##**##**** ****
+ 0x31C0, // **##***###** ****
+ 0x30E0, // **##****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x53 = S
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x54 = T
+ 0x0000, // ************ ****
+ 0x7FE0, // *##########* ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x55 = U
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x56 = V
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x1980, // ***##**##*** ****
+ 0x0F00, // ****####**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x57 = W
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6F60, // *##*####*##* ****
+ 0x39C0, // **###**###** ****
+ 0x30C0, // **##****##** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x58 = X
+ 0x0000, // ************ ****
+ 0x30C0, // **##****##** ****
+ 0x1980, // ***##**##*** ****
+ 0x0F00, // ****####**** ****
+ 0x0600, // *****##***** ****
+ 0x0F00, // ****####**** ****
+ 0x1980, // ***##**##*** ****
+ 0x30C0, // **##****##** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x59 = Y
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x30C0, // **##****##** ****
+ 0x1980, // ***##**##*** ****
+ 0x0F00, // ****####**** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x5A = Z
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0180, // *******##*** ****
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0C00, // ****##****** ****
+ 0x1800, // ***##******* ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x5B = Ä = NC
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x5C = Ö = NC
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x5D = Ü = NC
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x5E = ^ = NC
+ 0x0600, // *****##***** ****
+ 0x0F00, // ****####**** ****
+ 0x1980, // ***##**##*** ****
+ 0x30C0, // **##****##** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x5F = _ = NC
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x7FE0 // *##########* ****
+ },
+
+ { // 0x60 = ° = NC
+ 0x0000, // ************ ****
+ 0x0000, // *****####*** ****
+ 0x0000, // ****##**##** ****
+ 0x0000, // *****####*** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x61 = a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x62 = b
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x37C0, // **##*#####** ****
+ 0x3860, // **###****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x63 = c
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0FE0, // ****#######* ****
+ 0x1800, // ***##******* ****
+ 0x3000, // **##******** ****
+ 0x1800, // ***##******* ****
+ 0x0FE0, // ****#######* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x64 = d
+ 0x0000, // ************ ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x1F60, // ***#####*##* ****
+ 0x30E0, // **##****###* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FE0, // ***########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x65 = e
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x66 = f
+ 0x0000, // ************ ****
+ 0x07E0, // *****######* ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x3F80, // **#######*** ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x67 = g
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x1F60, // ***#####*##* ****
+ 0x30E0, // **##****###* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0060, // *********##* ****
+ 0x1FC0 // ***#######** ****
+ },
+ { // 0x68 = h
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x37C0, // **##*#####** ****
+ 0x3860, // **###****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x69 = i
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x1F80, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x6A = j
+ 0x0000, // ************ ****
+ 0x00E0, // ********###* ****
+ 0x0000, // ************ ****
+ 0x01E0, // *******####* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x0060, // *********##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0 // ***#######** ****
+ },
+ { // 0x6B = k
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x30E0, // **##****###* ****
+ 0x3180, // **##***##*** ****
+ 0x3E00, // **#####***** ****
+ 0x3180, // **##***##*** ****
+ 0x30E0, // **##****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x6C = l
+ 0x0000, // ************ ****
+ 0x1E00, // ***####***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x6D = m
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x6DC0, // *##*##*###** ****
+ 0x6660, // *##**##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x6E = n
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x37C0, // **##*#####** ****
+ 0x3860, // **###****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x6F = o
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0x70 = p
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x37C0, // **##*#####** ****
+ 0x3860, // **###****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3860, // **###****##* ****
+ 0x37C0, // **##*#####** ****
+ 0x3000, // **##******** ****
+ 0x3000 // **##******** ****
+ },
+ { // 0x71 = q
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x1EC0, // ***####*##** ****
+ 0x31C0, // **##***###** ****
+ 0x30C0, // **##****##** ****
+ 0x31C0, // **##***###** ****
+ 0x1EC0, // ***####*##** ****
+ 0x00C0, // ********##** ****
+ 0x01E0 // *******####* ****
+ },
+ { // 0x72 = r
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x33E0, // **##**#####* ****
+ 0x3C00, // **####****** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x73 = s
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0060, // *********##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x74 = t
+ 0x0000, // ************ ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x3F80, // **#######*** ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x0C00, // ****##****** ****
+ 0x07E0, // *****######* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x75 = u
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x76 = v
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x30C0, // **##****##** ****
+ 0x1980, // ***##**##*** ****
+ 0x0F00, // ****####**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x77 = w
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x36C0, // **##*##*##** ****
+ 0x2980, // ***##**##*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x78 = x
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x70E0, // *###****###* ****
+ 0x1980, // ***##**##*** ****
+ 0x0F00, // ****####**** ****
+ 0x1980, // ***##**##*** ****
+ 0x70E0, // *###****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x79 = y
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x18C0, // ***##***##** ****
+ 0x0D80, // ****##*##*** ****
+ 0x0700, // *****###**** ****
+ 0x0600, // *****##***** ****
+ 0x0C00, // ****##****** ****
+ 0x3800 // **###******* ****
+ },
+ { // 0x7A = z
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3FE0, // **#########* ****
+ 0x0180, // *******##*** ****
+ 0x0700, // *****###**** ****
+ 0x0C00, // ****##****** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x7B = ä = NC
+ 0x0000, // ************ ****
+ 0x3180, // **##***##*** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x7C = ö = NC
+ 0x0000, // ************ ****
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x7D = ü = NC
+ 0x0000, // ************ ****
+ 0x10C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x7E = ß = NC
+ 0x0000, // ************ ****
+ 0x0F80, // ****#####*** ****
+ 0x18C0, // ***##***##** ****
+ 0x30C0, // **##****##** ****
+ 0x3380, // **##**###*** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x33C0, // **##**####** ****
+ 0x3000, // **##******** ****
+ 0x3000 // **##******** ****
+ },
+ { // 0x7F = Block
+ 0x0000, // ************ ****
+ 0x7FE0, // *##########* ****
+ 0x7FE0, // *##########* ****
+ 0x7FE0, // *##########* ****
+ 0x7FE0, // *##########* ****
+ 0x7FE0, // *##########* ****
+ 0x7FE0, // *##########* ****
+ 0x7FE0, // *##########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0x80 =
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x63E0, // *##***#####* ****
+ 0x6660, // *##**##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x63E0, // *##***#####* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x81 =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x82 =
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x7000, // *###******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3180, // **##***##*** ****
+ 0x0300, // ******##**** ****
+ 0x0660, // *****##**##* ****
+ 0x07E0, // *****######* ****
+ 0x0060 // *********##* ****
+ },
+ { // 0x83 =
+ 0x0000, // ************ ****
+ 0x0FC0, // ****######** ****
+ 0x1860, // ***##****##* ****
+ 0x0C00, // ****##****** ****
+ 0x3F00, // **######**** ****
+ 0x0C00, // ****##****** ****
+ 0x3E60, // **#####**##* ****
+ 0x33C0, // **##**####** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x84 =
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x6660, // *##**##**##* ****
+ 0x6600, // *##**##***** ****
+ 0x3FC0, // **########** ****
+ 0x0660, // *****##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x85 =
+ 0x07F0, // *****####### ****
+ 0x0C00, // ****##****** ****
+ 0x19F0, // ***##**##### ****
+ 0x1800, // ***##******* ****
+ 0x19F0, // ***##**##### ****
+ 0x1800, // ***##******* ****
+ 0x19F0, // ***##**##### ****
+ 0x0C00, // ****##****** ****
+ 0x07F0, // *****####### ****
+ 0x0000 // ************ ****
+ },
+ { // 0x86 =
+ 0xFFC0, // ##########** ****
+ 0x1C60, // ***###***##* ****
+ 0x0830, // ****#*****## ****
+ 0x7F30, // *#######**## ****
+ 0x4130, // *#*****#**## ****
+ 0x7F30, // *#######**## ****
+ 0x0830, // ****#*****## ****
+ 0x1C60, // ***###***##* ****
+ 0xFFC0, // ##########** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x87 =
+ 0xFFC0, // ##########** ****
+ 0x0060, // *********##* ****
+ 0x3E30, // **#####***## ****
+ 0x6330, // *##***##**## ****
+ 0x0E30, // ****###***## ****
+ 0x1830, // ***##*****## ****
+ 0x1830, // ***##*****## ****
+ 0x0060, // *********##* ****
+ 0xFFC0, // ##########** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x88 =
+ 0x0000, // ************ ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x3980, // ***##**##*** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x89 =
+ 0x0000, // ************ ****
+ 0x7C00, // *#####****** ****
+ 0x0C00, // ****##****** ****
+ 0x3800, // **###******* ****
+ 0x0C00, // ****##****** ****
+ 0x7980, // *####**##*** ****
+ 0x0300, // ******##**** ****
+ 0x0660, // *****##**##* ****
+ 0x07E0, // *****######* ****
+ 0x0060 // *********##* ****
+ },
+ { // 0x8A =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x8B =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x1C00, // ***###****** ****
+ 0x7FF0, // *########### ****
+ 0x1C00, // ***###****** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x8C =
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x7000, // *###******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x33C0, // **##**####** ****
+ 0x0660, // *****##**##* ****
+ 0x00C0, // ********##** ****
+ 0x0300, // ******##**** ****
+ 0x07E0 // *****######* ****
+ },
+ { // 0x8D =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0380, // ******###*** ****
+ 0xFFE0, // ###########* ****
+ 0x0380, // ******###*** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x8E =
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0F00, // ****####**** ****
+ 0x1F80, // ***######*** ****
+ 0x36C0, // **##*##*##** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600 // *****##***** ****
+ },
+ { // 0x8F =
+ 0x0000, // ************ ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0x90 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x3000, // **##******** ****
+ 0x3F80, // **#######*** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x91 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x92 =
+ 0x0000, // ************ ****
+ 0x3180, // **##***##*** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x93 =
+ 0x0000, // ************ ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x94 =
+ 0x0000, // ************ ****
+ 0x6060, // *##******##* ****
+ 0x30C0, // **##****##** ****
+ 0x1F80, // ***######*** ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x1F80, // ***######*** ****
+ 0x30C0, // **##****##** ****
+ 0x6060, // *##******##* ****
+ 0x0000 // ************ ****
+ },
+ { // 0x95 =
+ 0xFFC0, // ##########** ****
+ 0x0060, // *********##* ****
+ 0xFF30, // ########**## ****
+ 0x0030, // **********## ****
+ 0xFF30, // ########**## ****
+ 0x0030, // **********## ****
+ 0xFF30, // ########**## ****
+ 0x0060, // *********##* ****
+ 0xFFC0, // ##########** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x96 =
+ 0xFFC0, // ##########** ****
+ 0x0060, // *********##* ****
+ 0x3E30, // **#####***## ****
+ 0x4730, // *#***###**## ****
+ 0x4730, // *#***###**## ****
+ 0x7F30, // *#######**## ****
+ 0x3E30, // **#####***## ****
+ 0x0060, // *********##* ****
+ 0xFFC0, // ##########** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x97 =
+ 0xFFC0, // ##########** ****
+ 0x0860, // ****#****##* ****
+ 0x1C30, // ***###****## ****
+ 0x0030, // **********## ****
+ 0x7F30, // *#######**## ****
+ 0x0030, // **********## ****
+ 0x1C30, // ***###****## ****
+ 0x0860, // ****#****##* ****
+ 0xFFC0, // ##########** ****
+ 0x0000 // ************ ****
+ },
+ { // 0x98 =
+ 0x0000, // ************ ****
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x99 =
+ 0x0E00, // ****###***** ****
+ 0x1B00, // ***##*##**** ****
+ 0x0E00, // ****###***** ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x9A =
+ 0x0000, // ************ ****
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x9B =
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x9C =
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x9D =
+ 0x0700, // *****###**** ****
+ 0x0700, // *****###**** ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x9E =
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0x9F = _
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x7FE0 // *##########* ****
+ },
+
+
+ { // 0xA0 = 0x20a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA1 = 0x21a
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA2 = 0x22a
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA3 = 0x23a
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA4 = 0x24a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA5 = 0x25a
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA6 = 0x26a
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA7 = 0x27a
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA8 = 0x28a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xA9 = 0x29a
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xAA = 0x2Aa
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xAB = 0x2Ba
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xAC = 0x2Ca
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xAD = 0x2Da
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xAE = 0x2Ea
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xAF = 0x2Fa
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0xB0 = 0x30a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB1 = 0x31a
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB2 = 0x32a
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB3 = 0x33a
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB4 = 0x34a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB5 = 0x35a
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB6 = 0x36a
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB7 = 0x37a
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB8 = 0x38a
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xB9 = 0x39a
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xBA = 0x3Aa
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xBB = 0x3Ba
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xBC = 0x3Ca
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xBD = 0x3Da
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xBE = 0x3Ea
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+ { // 0xBF = 0x3Fa
+ 0xFFFF, // ############ ****
+ 0xFFFF, // ############ ****
+ 0xFFFF, // ############ ****
+ 0xFFFF, // ############ ****
+ 0xFFFF, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00 // ######****** ****
+ },
+
+ { // 0xC0 =
+ 0x0600, // *****##***** ****
+ 0x0C00, // ****##****** ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x6060, // *##******##* ****
+ 0x7FE0, // *##########* ****
+ 0x6000, // *##********* ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC1 =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC2 =
+ 0x0C00, // ****##****** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC3 =
+ 0x0000, // ************ ****
+ 0x0FC0, // ****######** ****
+ 0x1860, // ***##****##* ****
+ 0x0C00, // ****##****** ****
+ 0x3F00, // **######**** ****
+ 0x0C00, // ****##****** ****
+ 0x3E60, // **#####**##* ****
+ 0x33C0, // **##**####** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC4 =
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x6660, // *##**##**##* ****
+ 0x6600, // *##**##***** ****
+ 0x3FC0, // **########** ****
+ 0x0660, // *****##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x3F60, // **########** ****
+ 0x06C0, // *****##***** ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC5 =
+ 0x3CC0, // **####**##** ****
+ 0x6780, // *##**####*** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC6 =
+ 0x3C60, // **####***##* ****
+ 0x67C0, // *##**#####** ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC7 =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC8 =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xC9 =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xCA =
+ 0x0C00, // ****##****** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x1F80, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xCB =
+ 0x0000, // ************ ****
+ 0x0780, // *****####*** ****
+ 0x0CC0, // ****##**##** ****
+ 0x0780, // *****####*** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xCC =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0FE0, // ****#######* ****
+ 0x1800, // ***##******* ****
+ 0x3000, // **##******** ****
+ 0x1800, // ***##******* ****
+ 0x0FE0, // ****#######* ****
+ 0x0300, // ******##**** ****
+ 0x0E00 // ****###***** ****
+ },
+ { // 0xCD =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0310, // ******###*** ****
+ 0xFFE0, // ###########* ****
+ 0x0310, // ******###*** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xCE =
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0F00, // ****####**** ****
+ 0x1F80, // ***######*** ****
+ 0x36C0, // **##*##*##** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600 // *****##***** ****
+ },
+ { // 0xCF =
+ 0x0000, // ************ ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0xD0 =
+ 0x0C00, // ****##****** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD1 =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD2 =
+ 0x0E00, // ****###***** ****
+ 0x1B00, // ***##*##**** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD3 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD4 =
+ 0x0000, // ************ ****
+ 0x1980, // ***##**##*** ****
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x1F80, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD5 =
+ 0x1E60, // ***####**##* ****
+ 0x33C0, // **##**####** ****
+ 0x1F80, // ***######*** ****
+ 0x30C0, // **##****##** ****
+ 0x6060, // *##******##* ****
+ 0x7FE0, // *##########* ****
+ 0x6060, // *##******##* ****
+ 0x6060, // *##******##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD6 =
+ 0x1E60, // ***####**##* ****
+ 0x33C0, // **##**####** ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD7 =
+ 0x0000, // ************ ****
+ 0x0FC0, // ****######** ****
+ 0x1860, // ***##****##* ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x1860, // ***##****##* ****
+ 0x0FC0, // ****######** ****
+ 0x0300, // ******##**** ****
+ 0x0E00 // ****###***** ****
+ },
+ { // 0xD8 =
+ 0x0700, // *****###**** ****
+ 0x0D80, // ****##*##*** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xD9 =
+ 0x0700, // *****###**** ****
+ 0x0D80, // ****##*##*** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xDA =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0FE0, // ****#######* ****
+ 0x1800, // ***##******* ****
+ 0x3000, // **##******** ****
+ 0x1800, // ***##******* ****
+ 0x0FE0, // ****#######* ****
+ 0x0300, // ******##**** ****
+ 0x0E00 // ****###***** ****
+ },
+ { // 0xDB =
+ 0x0000, // ************ ****
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xDC =
+ 0x0700, // *****###**** ****
+ 0x0D80, // ****##*##*** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xDD =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xDE =
+ 0x0F00, // ****####**** ****
+ 0x1980, // ***##**##*** ****
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x1F80, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xDF =
+ 0x0000, // ************ ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x7FE0, // *##########* ****
+ 0x1980, // ***##**##*** ****
+ 0x1980, // ***##**##*** ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0xE0 =
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE1 =
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0600, // *****##***** ****
+ 0x1800, // ***##******* ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x1F00, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE2 =
+ 0x0000, // ************ ****
+ 0x18C0, // ***##***##** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE3 =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0FE0, // ****#######* ****
+ 0x1800, // ***##******* ****
+ 0x3000, // **##******** ****
+ 0x1800, // ***##******* ****
+ 0x0FE0, // ****#######* ****
+ 0x0300, // ******##**** ****
+ 0x0E00 // ****###***** ****
+ },
+ { // 0xE4 =
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x6660, // *##**##**##* ****
+ 0x6600, // *##**##***** ****
+ 0x3FC0, // **########** ****
+ 0x0660, // *****##**##* ****
+ 0x6660, // *##**##**##* ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE5 =
+ 0x0000, // ************ ****
+ 0x3F80, // **#######*** ****
+ 0x6180, // *##****##*** ****
+ 0x6180, // *##****##*** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x7FE0, // *##########* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE6 =
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE7 =
+ 0x1E60, // ***####**##* ****
+ 0x33C0, // **##**####** ****
+ 0x3860, // **###****##* ****
+ 0x3C60, // **####***##* ****
+ 0x3660, // **##*##**##* ****
+ 0x3360, // **##**##*##* ****
+ 0x31E0, // **##***####* ****
+ 0x30E0, // **##****###* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE8 =
+ 0x1E60, // ***####**##* ****
+ 0x33C0, // **##**####** ****
+ 0x0000, // ************ ****
+ 0x37C0, // **##*#####** ****
+ 0x3860, // **###****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xE9 =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xEA =
+ 0x0C00, // ****##****** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xEB =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x7F80, // *########*** ****
+ 0x00C0, // ********##** ****
+ 0x3FC0, // **########** ****
+ 0x60C0, // *##*****##** ****
+ 0x3FE0, // **#########* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xEC =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3000, // **##******** ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xED =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x0E00, // ****###***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x1F80, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xEE =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xEF =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x0000, // ************ ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x30E0, // **##****###* ****
+ 0x1F60, // ***#####*##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0xF0 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF1 =
+ 0x0C00, // ****##****** ****
+ 0x0600, // *****##***** ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3FE0, // **#########* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF2 =
+ 0x0C00, // ****##****** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x3000, // **##******** ****
+ 0x3F00, // **######**** ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF3 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF4 =
+ 0x19C0, // ***##**##*** ****
+ 0x0000, // ************ ****
+ 0x3FC0, // **########** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x0600, // *****##***** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF5 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF6 =
+ 0x0600, // *****##***** ****
+ 0x0300, // ******##**** ****
+ 0x1FC0, // ***#######** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF7 =
+ 0x0300, // ******##**** ****
+ 0x0600, // *****##***** ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x3060, // **##*****##* ****
+ 0x1FC0, // ***#######** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF8 =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x3DC0, // **####*###** ****
+ 0x0660, // *****##**##* ****
+ 0x3FE0, // **#########* ****
+ 0x6600, // *##**##***** ****
+ 0x3FC0, // **########** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xF9 =
+ 0x0000, // ************ ****
+ 0x0FE0, // ****#######* ****
+ 0x1B00, // ***##*##**** ****
+ 0x3300, // **##**##**** ****
+ 0x7FC0, // *#########** ****
+ 0x6300, // *##***##**** ****
+ 0x6300, // *##***##**** ****
+ 0x63E0, // *##***#####* ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xFA =
+ 0x0000, // ************ ****
+ 0x0300, // ******##**** ****
+ 0x0FC0, // ****######** ****
+ 0x0180, // *******##*** ****
+ 0x1FC0, // ***#######** ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x1F80, // ***######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xFB =
+ 0x0000, // ************ ****
+ 0x3F80, // **#######*** ****
+ 0x30C0, // **##****##** ****
+ 0x3060, // **##*****##* ****
+ 0x7C60, // *#####***##* ****
+ 0x3060, // **##*****##* ****
+ 0x30C0, // **##****##** ****
+ 0x3F80, // **#######*** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+ { // 0xFC =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0180, // *******##*** ****
+ 0x3FC0, // **########** ****
+ 0x6360, // *##***##*##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6C60, // *##*##***##* ****
+ 0x3FC0, // **########** ****
+ 0x1800, // ***##******* ****
+ 0x0000 // ************ ****
+ },
+ { // 0xFD =
+ 0x0060, // *********##* ****
+ 0x3FC0, // **########** ****
+ 0x61E0, // *##****####* ****
+ 0x6360, // *##***##*##* ****
+ 0x6660, // *##**##**##* ****
+ 0x6C60, // *##*##***##* ****
+ 0x7860, // *####****##* ****
+ 0x3FC0, // **########** ****
+ 0x6000, // *##********* ****
+ 0x0000 // ************ ****
+ },
+ { // 0xFE =
+ 0x0000, // ************ ****
+ 0x3000, // **##******** ****
+ 0x3000, // **##******** ****
+ 0x3F80, // **#######*** ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x30C0, // **##****##** ****
+ 0x3F80, // **#######*** ****
+ 0x3000, // **##******** ****
+ 0x3000 // **##******** ****
+ },
+ { // 0xFF =
+ 0x3C00, // **####****** ****
+ 0x1800, // ***##******* ****
+ 0x1F80, // ***######*** ****
+ 0x18C0, // ***##***##** ****
+ 0x18C0, // ***##***##** ****
+ 0x1F80, // ***######*** ****
+ 0x1800, // ***##******* ****
+ 0x3C00, // **####****** ****
+ 0x0000, // ************ ****
+ 0x0000 // ************ ****
+ },
+
+ { // 0x60a =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x61a =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x62a =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x63a =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x64a =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x65a =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x66a =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x67a =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x68a =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x69a =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x6Aa =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x6Ba =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x6Ca =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x6Da =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x6Ea =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+ { // 0x6Fa =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0 // ******###### ****
+ },
+
+ { // 0x70a =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x71a =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x72a =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x73a =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x74a =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x75a =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x76a =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x77a =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x78a =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x79a =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x7Aa =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x7Ba =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x7Ca =
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0x0000, // ************ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x7Da =
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFC00, // ######****** ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x7Ea =
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0x03F0, // ******###### ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0 // ############ ****
+ },
+ { // 0x7Fa =
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ 0xFFF0, // ############ ****
+ }
+};
+
+
+
+int NationalOptionSubsetG0Default[13]=
+ {0x23,0x94,0x80,0 ,0 ,0 ,0x5e,0x5f,0 ,0 ,0 ,0 ,0 };
+
+int NationalOptionSubsetCZ_SK[13]=
+ {0x23,0 ,0 ,0 ,0 ,0 ,0xed,0 ,0xec,0xeb,0 ,0xef,0 };
+int NationalOptionSubsetEN[13]=
+ {0x83,0x24,0x80,0x8b,0x8c,0x8d,0x8e,0x23,0x81,0x82,0x88,0x89,0x8a};
+int NationalOptionSubsetEE[13]=
+ {0x23,0xc6,0 ,0x5b,0x5c,0 ,0x5d,0xd6,0 ,0x7b,0x7c,0 ,0x7d};
+int NationalOptionSubsetFR[13]=
+ {0xd3,0xd4,0xd0,0xdb,0xdc,0xc1,0xde,0x23,0xd1,0xd2,0xd8,0xd9,0xcc};
+int NationalOptionSubsetDE[13]=
+ {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e};
+int NationalOptionSubsetIT[13]=
+ {0x83,0x24,0xd3,0x60,0xcc,0x8d,0x8e,0x23,0xdd,0xc1,0xc8,0xc9,0xca};
+int NationalOptionSubsetLV_LT[13]=
+ {0x23,0x24,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 };
+int NationalOptionSubsetPL[13]=
+ {0x23,0 ,0 ,0 ,0 ,0 ,0 ,0xee,0 ,0 ,0 ,0 ,0 };
+int NationalOptionSubsetPT_ES[13]=
+ {0xcc,0x24,0xe0,0xeb,0xec,0xed,0xee,0xef,0xe1,0x7d,0xe8,0xc9,0xc2};
+int NationalOptionSubsetRO[13]=
+ {0x23,0x94,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0xd2,0 ,0 ,0xde};
+int NationalOptionSubsetSR_HR_SL[13]=
+ {0x23,0 ,0 ,0 ,0 ,0xfb,0 ,0xdb,0 ,0 ,0 ,0 ,0 };
+int NationalOptionSubsetSV_FI[13]=
+ {0x23,0x94,0x90,0x5b,0x5c,0x9d,0x5d,0x5f,0x91,0x7b,0x7c,0x99,0x7d};
+int NationalOptionSubsetTR[13]=
+ {0 ,0 ,0 ,0 ,0x5c,0xd7,0x5d,0 ,0 ,0 ,0x7c,0xcc,0x7d};
+
+
+
+inline int NationalOptionSubset(int chr) {
+ switch (chr) {
+ case 0x23: return 0;
+ case 0x24: return 1;
+ case 0x40: return 2;
+ case 0x5b: return 3;
+ case 0x5c: return 4;
+ case 0x5d: return 5;
+ case 0x5e: return 6;
+ case 0x5f: return 7;
+ case 0x60: return 8;
+ case 0x7b: return 9;
+ case 0x7c: return 10;
+ case 0x7d: return 11;
+ case 0x7e: return 12;
+ }
+ return -1;
+}
+
+inline unsigned int LeftBits(unsigned int bits) {
+ // Scale bit positions 0xfc00 to 0xfff0 positions
+ unsigned int res=0;
+ if (bits&0x8000) res|=0xC000;
+ if (bits&0x4000) res|=0x3000;
+ if (bits&0x2000) res|=0x0C00;
+ if (bits&0x1000) res|=0x0300;
+ if (bits&0x0800) res|=0x00C0;
+ if (bits&0x0400) res|=0x0030;
+ return res;
+}
+inline unsigned int RightBits(unsigned int bits) {
+ // Scale bit positions 0x03f0 to 0xfff0 positions
+ unsigned int res=0;
+ if (bits&0x0200) res|=0xC000;
+ if (bits&0x0100) res|=0x3000;
+ if (bits&0x0080) res|=0x0C00;
+ if (bits&0x0040) res|=0x0300;
+ if (bits&0x0020) res|=0x00C0;
+ if (bits&0x0010) res|=0x0030;
+ return res;
+}
+
+
+
+unsigned int* GetFontChar(cTeletextChar c, unsigned int *buffer) {
+ // Get character bitmap for character/charset
+
+ enumCharsets font=c.GetCharset();
+ int chr=c.GetChar();
+ unsigned int *bitmap=NULL;
+ int i;
+ int NationalOption=NationalOptionSubset(chr);
+
+ switch (font) {
+ case CHARSET_LATIN_G0:
+ if (NationalOption>=0) {
+ if (NationalOptionSubsetG0Default[NationalOption]>0)
+ bitmap=TXT_Font[NationalOptionSubsetG0Default[NationalOption]-0x20];
+ } else {
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ }
+ break;
+ case CHARSET_LATIN_G0_EN:
+ if (NationalOption>=0) {
+ if (NationalOptionSubsetEN[NationalOption]>0)
+ bitmap=TXT_Font[NationalOptionSubsetEN[NationalOption]-0x20];
+ } else {
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ }
+ break;
+ case CHARSET_LATIN_G0_FR:
+ if (NationalOption>=0) {
+ if (NationalOptionSubsetFR[NationalOption]>0)
+ bitmap=TXT_Font[NationalOptionSubsetFR[NationalOption]-0x20];
+ } else {
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ }
+ break;
+ case CHARSET_LATIN_G0_IT:
+ if (NationalOption>=0) {
+ if (NationalOptionSubsetIT[NationalOption]>0)
+ bitmap=TXT_Font[NationalOptionSubsetIT[NationalOption]-0x20];
+ } else {
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ }
+ break;
+ case CHARSET_LATIN_G0_PT_ES:
+ if (NationalOption>=0) {
+ if (NationalOptionSubsetPT_ES[NationalOption]>0)
+ bitmap=TXT_Font[NationalOptionSubsetPT_ES[NationalOption]-0x20];
+ } else {
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ }
+ break;
+ case CHARSET_LATIN_G0_SV_FI:
+ if (NationalOption>=0) {
+ if (NationalOptionSubsetSV_FI[NationalOption]>0)
+ bitmap=TXT_Font[NationalOptionSubsetSV_FI[NationalOption]-0x20];
+ } else {
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ }
+ break;
+ case CHARSET_LATIN_G0_DE:
+ if (chr>=0x20 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ break;
+ case CHARSET_LATIN_G0_CZ_SK:
+ case CHARSET_LATIN_G0_EE:
+ case CHARSET_LATIN_G0_LV_LT:
+ case CHARSET_LATIN_G0_PL:
+ case CHARSET_LATIN_G0_RO:
+ case CHARSET_LATIN_G0_SR_HR_SL:
+ case CHARSET_LATIN_G0_TR:
+ // Partially supported latin charsets
+ if (chr>=0x20 && chr<0x80 && NationalOption<0) {
+ bitmap=TXT_Font[chr-0x20];
+ }
+ break;
+
+ case CHARSET_LATIN_G2:
+ case CHARSET_CYRILLIC_G0_SR_HR:
+ case CHARSET_CYRILLIC_G0_RU_BG:
+ case CHARSET_CYRILLIC_G0_UK:
+ case CHARSET_CYRILLIC_G2:
+ case CHARSET_GREEK_G0:
+ case CHARSET_GREEK_G2:
+ case CHARSET_ARABIC_G0:
+ case CHARSET_ARABIC_G2:
+ case CHARSET_HEBREW_G0:
+ // totally unsupported
+ break;
+
+ case CHARSET_GRAPHICS_G1:
+ if (chr>=0x20 && chr<0x40) {
+ bitmap=TXT_Font[chr-0x20+0x80];
+ } else if (chr>=0x60 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x60+0xE0];
+ }
+ break;
+ case CHARSET_GRAPHICS_G1_SEP:
+ if (chr>=0x20 && chr<0x40) {
+ bitmap=TXT_Font[chr-0x20+0x80];
+ } else if (chr>=0x60 && chr<0x80) {
+ bitmap=TXT_Font[chr-0x60+0xE0];
+ }
+ if (bitmap) {
+ for (i=0;i<10;i++) buffer[i]=bitmap[i]&TXT_Mask[i];
+ bitmap=buffer;
+ }
+ break;
+
+ case CHARSET_GRAPHICS_G3:
+ case CHARSET_INVALID:
+ // Totally unsupported
+ break;
+ }
+
+
+
+ if (!buffer) {
+ printf("Warning: Undefined char: %x %x\n",font,chr);
+ return NULL;
+ }
+
+ switch (c.GetDblHeight()) {
+ case dblh_Top:
+ // Scale top 5 lines to full height
+ buffer[8]=buffer[9]=bitmap[4];
+ buffer[6]=buffer[7]=bitmap[3];
+ buffer[4]=buffer[5]=bitmap[2];
+ buffer[2]=buffer[3]=bitmap[1];
+ buffer[1]=buffer[0]=bitmap[0];
+ bitmap=buffer;
+ break;
+ case dblh_Bottom:
+ // Scale bottom 5 lines to full height
+ buffer[0]=buffer[1]=bitmap[5];
+ buffer[2]=buffer[3]=bitmap[6];
+ buffer[4]=buffer[5]=bitmap[7];
+ buffer[6]=buffer[7]=bitmap[8];
+ buffer[8]=buffer[9]=bitmap[9];
+ bitmap=buffer;
+ default:;
+ }
+
+ switch (c.GetDblWidth()) {
+ case dblw_Left:
+ // Scale 6 left columns to full width
+ buffer[0]=LeftBits(bitmap[0]);
+ buffer[1]=LeftBits(bitmap[1]);
+ buffer[2]=LeftBits(bitmap[2]);
+ buffer[3]=LeftBits(bitmap[3]);
+ buffer[4]=LeftBits(bitmap[4]);
+ buffer[5]=LeftBits(bitmap[5]);
+ buffer[6]=LeftBits(bitmap[6]);
+ buffer[7]=LeftBits(bitmap[7]);
+ buffer[8]=LeftBits(bitmap[8]);
+ buffer[9]=LeftBits(bitmap[9]);
+ bitmap=buffer;
+ break;
+ case dblw_Right:
+ // Scale 6 right columns to full width
+ buffer[0]=RightBits(bitmap[0]);
+ buffer[1]=RightBits(bitmap[1]);
+ buffer[2]=RightBits(bitmap[2]);
+ buffer[3]=RightBits(bitmap[3]);
+ buffer[4]=RightBits(bitmap[4]);
+ buffer[5]=RightBits(bitmap[5]);
+ buffer[6]=RightBits(bitmap[6]);
+ buffer[7]=RightBits(bitmap[7]);
+ buffer[8]=RightBits(bitmap[8]);
+ buffer[9]=RightBits(bitmap[9]);
+ bitmap=buffer;
+ default:;
+ }
+
+ return bitmap;
+}
diff --git a/txtfont.h b/txtfont.h
new file mode 100644
index 0000000..c2b73f4
--- /dev/null
+++ b/txtfont.h
@@ -0,0 +1,14 @@
+#ifndef __TXTFONT_H
+#define __TXTFONT_H
+
+#include "txtrender.h"
+
+unsigned int* GetFontChar(cTeletextChar c, unsigned int *buffer);
+// Get a character bitmap for character/charset
+// Also handle double width/height partial characters
+// buffer must be an unsigned int[10] buffer, that *may* be used
+// to store the character - a different pointer may be returned too.
+// returns NULL if undefined character
+
+
+#endif
diff --git a/txtrecv.c b/txtrecv.c
new file mode 100644
index 0000000..af76a3a
--- /dev/null
+++ b/txtrecv.c
@@ -0,0 +1,884 @@
+/***************************************************************************
+ * Copyright (c) 2003,2004 by Marcel Wiesweg *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <dirent.h>
+
+#include "txtrecv.h"
+#include "tables.h"
+#include "setup.h"
+
+#include <vdr/channels.h>
+#include <vdr/device.h>
+#include <vdr/config.h>
+
+#include <pthread.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+const char *RootDir::root = "/vtx";
+
+void RootDir::setRootDir(const char *newRoot) {
+ root=newRoot;
+}
+
+const char *RootDir::getRootDir() {
+ return root;
+}
+
+int Storage::doCleanUp() {
+ DIR *top=opendir(root);
+ int pagesDeleted=0;
+ if (top) {
+ struct dirent *chandir, path;
+ struct stat chandirstat;
+ char fullPath[PATH_MAX];
+ while ( (!readdir_r(top, &path, &chandir) && chandir != NULL) ) {
+ if (strcmp(chandir->d_name, "..")==0 || strcmp(chandir->d_name, ".")==0)
+ continue;
+ snprintf(fullPath, PATH_MAX, "%s/%s", root, chandir->d_name);
+ if (stat(fullPath, &chandirstat)==0) {
+ if (S_ISDIR(chandirstat.st_mode)) {
+ pagesDeleted+=cleanSubDir(fullPath);
+ }
+ }
+ }
+ closedir(top);
+ } else {
+ esyslog("Error opening teletext storage directory \"%s\": %s", root, strerror(errno));
+ }
+ return pagesDeleted;
+}
+
+int Storage::cleanSubDir(const char *dir) {
+ static bool reportedError=false; //avoid filling up syslog
+ DIR *d=opendir(dir);
+ bool hadError=false;
+ int bytesDeleted=0, filesize;
+ if (d) {
+ struct dirent *txtfile, path;
+ struct stat txtfilestat;
+ char fullPath[PATH_MAX];
+ while ( (!readdir_r(d, &path, &txtfile) && txtfile != NULL) ) {
+ int len=strlen(txtfile->d_name);
+ //check that the file end with .vtx to avoid accidents and disasters
+ if (strcmp(txtfile->d_name+len-4, ".vtx")==0) {
+ snprintf(fullPath, PATH_MAX, "%s/%s", dir, txtfile->d_name);
+ stat(fullPath, &txtfilestat);
+ filesize=actualFileSize(txtfilestat.st_size);
+ int ret=unlink(fullPath);
+ if (ret==0)
+ bytesDeleted+=filesize;
+ else
+ hadError=ret;
+ }
+ }
+ closedir(d);
+ rmdir(dir);
+ } else {
+ if (!reportedError) {
+ esyslog("OSD-Teletext: Error opening teletext storage subdirectory \"%s\": %s", dir, strerror(errno));
+ reportedError=true;
+ }
+ }
+
+ if (hadError && !reportedError) {
+ esyslog("OSD-Teletext: Error removing teletext storage subdirectory \"%s\": %s", dir, strerror(hadError));
+ reportedError=true;
+ }
+ return bytesDeleted;
+}
+
+Storage *Storage::s_self = 0;
+Storage::StorageSystem Storage::system = Storage::StorageSystemPacked;
+
+Storage::Storage() {
+ s_self=this;
+ byteCount=0;
+ currentDir=0;
+ storageOption=-1;
+ failedFreeSpace=false;
+}
+
+Storage::~Storage() {
+}
+
+void Storage::setSystem(StorageSystem s) {
+ system=s;
+}
+
+Storage *Storage::instance() {
+ if (!s_self) {
+ switch (system) {
+ case StorageSystemLegacy:
+ s_self=new LegacyStorage();
+ break;
+ case StorageSystemPacked:
+ default:
+ s_self=new PackedStorage();
+ break;
+ }
+ }
+ return s_self;
+}
+
+void Storage::setMaxStorage(int maxMB) {
+ storageOption=maxMB;
+}
+
+void Storage::init() {
+ cleanUp();
+ initMaxStorage(storageOption);
+}
+
+void Storage::freeSpace() {
+ //there might be a situation where only the current directory is left and
+ //occupies the whole space. We cannot delete anything. Don't waste time scanning.
+ if (failedFreeSpace)
+ return;
+
+ //printf("freeSpace()\n");
+ time_t min=time(0);
+ char minDir[PATH_MAX];
+ char fullPath[PATH_MAX];
+ int haveDir=0;
+ DIR *top=opendir(getRootDir());
+ if (top) {
+ struct dirent *chandir, path;
+ struct stat chandirstat;
+ while ( (!readdir_r(top, &path, &chandir) && chandir != NULL) ) {
+ if (strcmp(chandir->d_name, "..")==0 || strcmp(chandir->d_name, ".")==0)
+ continue;
+ snprintf(fullPath, PATH_MAX, "%s/%s", getRootDir(), chandir->d_name);
+ if (stat(fullPath, &chandirstat)==0) {
+ if (S_ISDIR(chandirstat.st_mode)) {
+ if (chandirstat.st_ctime < min && strcmp(fullPath, currentDir)) {
+ min=chandirstat.st_ctime;
+ strcpy(minDir, fullPath);
+ haveDir++;
+ }
+ }
+ }
+ }
+ closedir(top);
+
+ //if haveDir, only current directory present, which must not be deleted
+ if (haveDir>=2)
+ byteCount-=cleanSubDir(minDir);
+ else
+ failedFreeSpace=true;
+ }
+}
+
+bool Storage::exists(const char* file) {
+ struct stat s;
+ return (stat(file, &s)==0);
+}
+
+void Storage::getFilename(char *buffer, int bufLength, PageID page) {
+ snprintf(buffer, bufLength, "%s/%s/%03x_%02x.vtx", getRootDir(),
+#if VDRVERSNUM >= 10318
+ *page.channel.ToString(),
+#else
+ page.channel.ToString(),
+#endif
+ page.page, page.subPage);
+}
+
+void Storage::prepareDirectory(tChannelID chan) {
+ free(currentDir);
+ asprintf(&currentDir, "%s/%s", root,
+#if VDRVERSNUM >= 10318
+ *chan.ToString()
+#else
+ chan.ToString()
+#endif
+ );
+ MakeDirs(currentDir, 1);
+ failedFreeSpace=false;
+}
+
+#define TELETEXT_PAGESIZE 972
+
+LegacyStorage::LegacyStorage() {
+ maxBytes=0;
+ fsBlockSize=1;
+ pageBytes=TELETEXT_PAGESIZE;
+}
+
+LegacyStorage::~LegacyStorage() {
+}
+
+/*
+static inline int FilesForMegabytes(double MB, int blocksize) {
+ double pageBytes;
+ if (TELETEXT_PAGESIZE<=blocksize)
+ pageBytes=blocksize;
+ else
+ pageBytes=((TELETEXT_PAGESIZE/blocksize)+1)*blocksize;
+ //reserve 10% for directories
+ return (int)( (1024.0 * 1024.0 * (MB-MB*0.1)) / pageBytes );
+}*/
+
+int LegacyStorage::actualFileSize(int netFileSize) {
+ if (netFileSize<=0)
+ return 0;
+ if (netFileSize<=fsBlockSize)
+ return fsBlockSize;
+ else
+ return ((netFileSize/fsBlockSize)+1)*fsBlockSize;
+}
+
+//max==0 means unlimited, max==-1 means a reasonable default value shall be calculated
+void LegacyStorage::initMaxStorage(int maxMB) {
+
+ struct statfs fs;
+ if (statfs(getRootDir(), &fs)!=0) {
+ esyslog("OSD-Teletext: Error statfs'ing root directory \"%s\": %s, cache size uncontrolled", getRootDir(), strerror(errno));
+ return;
+ }
+ fsBlockSize=fs.f_bsize;
+
+ pageBytes=actualFileSize(TELETEXT_PAGESIZE);
+
+ if (maxMB>=0) {
+ if (maxMB<3) {
+ esyslog("OSD-Teletext: Request to use at most %d MB for caching. This is not enough, using 3 MB", maxMB);
+ maxMB=3;
+ }
+ maxBytes=MEGABYTE(maxMB);
+ } else if (maxMB==-1) {
+ //calculate a default value
+ double blocksPerMeg = 1024.0 * 1024.0 / fs.f_bsize;
+ double capacityMB=fs.f_blocks / blocksPerMeg;
+ double freeMB=(fs.f_bavail / blocksPerMeg);
+ if (capacityMB<=50 || freeMB<50) {
+ //small (<=50MB) filesystems as root dir are assumed to be dedicated for use as a teletext cache
+ //for others, the maximum default size is set to 50 MB
+ maxBytes=MEGABYTE((int)freeMB);
+ //maxPages= FilesForMegabytes(freeMB, fs.f_bsize);
+ if (freeMB<3.0) {
+ esyslog("OSD-Teletext: Less than %.1f MB free on filesystem of root directory \"%s\"!", freeMB, getRootDir());
+ maxBytes=MEGABYTE(3);
+ }
+ } else {
+ //the maximum default size is set to 50 MB
+ maxBytes=MEGABYTE(50);
+ }
+ //printf("Set maxBytes to %ld, %.2f %.2f\n", maxBytes, capacityMB, freeMB);
+ }
+}
+
+void LegacyStorage::cleanUp() {
+ byteCount -= Storage::doCleanUp();
+}
+
+void LegacyStorage::registerFile(PageID page) {
+ //pageBytes is already effective size
+ if ( maxBytes && (byteCount+=pageBytes)>maxBytes )
+ freeSpace();
+}
+
+StorageHandle LegacyStorage::openForReading(PageID page, bool countAsAccess) {
+ //the countAsAccess argument was intended for use in a LRU cache, currently unused
+ char filename[PATH_MAX];
+ getFilename(filename, sizeof(filename), page);
+ StorageHandle ret=(StorageHandle)open(filename, O_RDONLY);
+ return ret;
+}
+
+StorageHandle LegacyStorage::openForWriting(PageID page) {
+ static bool wroteError=false;
+ char filename[PATH_MAX];
+ getFilename(filename, sizeof(filename), page);
+ bool existed=exists(filename);
+ //first try
+ StorageHandle fd=(StorageHandle)open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd) {
+ if (!existed)
+ registerFile(page);
+ return fd;
+ }
+ //no space on disk? make some space available
+ if (errno == ENOSPC)
+ freeSpace();
+ //second try
+ fd=(StorageHandle)open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (!fd && !wroteError) {
+ //report error to syslog - once!
+ wroteError=true;
+ esyslog("OSD-Teletext: Error opening teletext file %s: %s", filename, strerror(errno));
+ }
+ //make sure newly created files are counted
+ if (fd && !existed)
+ registerFile(page);
+ return fd;
+}
+
+ssize_t LegacyStorage::write(const void *ptr, size_t size, StorageHandle stream) {
+ ssize_t written;
+ if (!(written=::write((int)stream, ptr, size)) ) {
+ switch (errno) {
+ case ENOSPC:
+ freeSpace();
+ return ::write((int)stream, ptr, size);
+ case EINTR:
+ esyslog("OSD-Teletext: EINTR while writing. Please contact the author and tell him this happened.");
+ break;
+ default:
+ break;
+ }
+ }
+ return written;
+}
+
+
+
+PackedStorage::PackedStorage() {
+}
+#define TOC_SIZE 8
+//The file structure is simple:
+// TOC_SIZE*PageAddress contains the numbers of the following pages
+// TOC_SIZE*TELETEXT_PAGESIZE contains the page data
+//and the same again.
+bool PackedStorage::seekTo(PageID page, int desc, bool create) {
+ lseek(desc, 0, SEEK_SET);
+ PageAddress addr[TOC_SIZE];
+
+ while (::read(desc, addr, sizeof(addr)) == sizeof(addr)) {
+ lseek(desc, 0, SEEK_CUR);
+ for (int index=0; index<TOC_SIZE; index++) {
+ if (addr[index]==page) {
+ lseek(desc, index*TELETEXT_PAGESIZE, SEEK_CUR);
+ return true;
+ } else if (addr[index].page==0) {
+ //0 means: no more pages follow
+ if (create) {
+ //rewind what was read
+ lseek(desc, -(sizeof(addr)), SEEK_CUR);
+ //update index
+ addr[index]=page;
+ if (::write(desc, addr, sizeof(addr)) != sizeof(addr))
+ return false;
+ //seek to data position
+ lseek(desc, TELETEXT_PAGESIZE*index, SEEK_CUR);
+ return true;
+ } else
+ return false;
+ }
+ }
+
+ //seek over data area
+ lseek(desc, TELETEXT_PAGESIZE*TOC_SIZE, SEEK_CUR);
+ }
+
+ int oldSize=actualFileSize(lseek(desc, 0, SEEK_CUR));
+ if (create) {
+ //create a new set of a TOC and a TOC_SIZE*TELETEXT_PAGESIZE data area
+ memset(addr, 0, sizeof(addr));
+ //first entry is our page
+ addr[0]=page;
+ if (::write(desc, addr, sizeof(addr)) != sizeof(addr))
+ return false;
+ //seek beyond end of file
+ lseek(desc, (TELETEXT_PAGESIZE*TOC_SIZE)-1, SEEK_CUR);
+ //write one byte to enlarge the file to the sought position
+ char c=1;
+ if (::write(desc, &c, 1) != 1)
+ return false;
+ //Now, calculate new file size
+ byteCount += ( actualFileSize(lseek(desc, 0, SEEK_CUR)) - oldSize );
+ //seek to beginning of data, which is requested
+ lseek(desc, -(TELETEXT_PAGESIZE*TOC_SIZE), SEEK_CUR);
+ return true;
+ } else
+ return false;
+}
+
+void PackedStorage::getFilename(char *buffer, int bufLength, PageID page) {
+ //This is a different scheme: page 576_07 will have the name 570s.vtx, the same as e.g. 571_01 or 575_00
+ //Think of "the five hundred seventies"
+ snprintf(buffer, bufLength, "%s/%s/%03xs.vtx", getRootDir(),
+#if VDRVERSNUM >= 10318
+ *page.channel.ToString(),
+#else
+ page.channel.ToString(),
+#endif
+ (page.page & 0xFF0));
+}
+
+StorageHandle PackedStorage::openForWriting(PageID page) {
+ static bool wroteError=false;
+ char filename[PATH_MAX];
+ getFilename(filename, sizeof(filename), page);
+ //first try
+ int desc=open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (desc != -1) {
+ if (!seekTo(page, desc, true)) {
+ ::close(desc);
+ return StorageHandle();
+ }
+ if ( maxBytes && byteCount>maxBytes )
+ freeSpace();
+ return (StorageHandle)desc;
+ }
+ //no space on disk? make some space available
+ if (errno == ENOSPC)
+ freeSpace();
+ //second try
+ desc=open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (desc==-1 && !wroteError) {
+ //report error to syslog - once!
+ wroteError=true;
+ esyslog("OSD-Teletext: Error opening teletext file %s: %s", filename, strerror(errno));
+ }
+
+ if (desc==-1)
+ return StorageHandle();
+ else if (!seekTo(page, desc, true)) {
+ ::close(desc);
+ return StorageHandle();
+ }
+
+ if ( maxBytes && byteCount>maxBytes )
+ freeSpace();
+ return (StorageHandle)desc;
+}
+
+StorageHandle PackedStorage::openForReading(PageID page, bool countAsAccess) {
+ int desc;
+ if ( (desc=(int)LegacyStorage::openForReading(page, false))!= -1 ) {
+ if (!seekTo(page, desc, false)) {
+ //this is not an error condition here, may and shall happen!
+ ::close(desc);
+ } else {
+ return (StorageHandle)desc;
+ }
+ }
+ return StorageHandle();
+}
+
+
+
+
+cTelePage::cTelePage(PageID t_page, uchar t_flags, uchar t_lang,int t_mag)
+ : mag(t_mag), flags(t_flags), lang(t_lang), page(t_page)
+{
+ memset(pagebuf,' ',26*40);
+}
+
+cTelePage::~cTelePage() {
+}
+
+void cTelePage::SetLine(int line, uchar *myptr)
+{
+ memcpy(pagebuf+40*line,myptr,40);
+}
+
+void cTelePage::save()
+{
+ Storage *s=Storage::instance();
+ unsigned char buf;
+ StorageHandle fd;
+ if ( (fd=s->openForWriting(page)) ) {
+ s->write("VTXV4",5,fd);
+ buf=0x01; s->write(&buf,1,fd);
+ buf=mag; s->write(&buf,1,fd);
+ buf=page.page; s->write(&buf,1,fd);
+ buf=flags; s->write(&buf,1,fd);
+ buf=lang; s->write(&buf,1,fd);
+ buf=0x00; s->write(&buf,1,fd);
+ buf=0x00; s->write(&buf,1,fd);
+ s->write(pagebuf,24*40,fd);
+ s->close(fd);
+ }
+}
+
+
+cTxtStatus::cTxtStatus(void)
+{
+ receiver = NULL;
+
+ //running=false;
+ TPid=0;
+ /*doNotSuspend=false;
+ doNotReceive=false;*/
+ //suspended=false;
+}
+
+cTxtStatus::~cTxtStatus()
+{
+ /*if (running)
+ Cancel(3);*/
+ if (receiver)
+ delete receiver;
+}
+
+void cTxtStatus::ChannelSwitch(const cDevice *Device, int ChannelNumber)
+{
+ if (Device->IsPrimaryDevice()) {
+
+/*#ifdef OSDTELETEXT_REINSERTION_PATCH
+ if (ttSetup.suspendReceiving) {
+ if (!running)
+ Start();
+ } else if (running) { //setup option changed, apply
+ running=false;
+ Cancel(3);
+ }
+#endif*/
+
+ CheckDeleteReceiver();
+
+ if (ChannelNumber) {
+ cChannel *channel = Channels.GetByNumber(ChannelNumber);
+ if (channel && channel->Tpid()) {
+/*#ifdef OSDTELETEXT_REINSERTION_PATCH
+ cMutexLock MutexLock(&mutex);
+ count=0; //reset 20 second intervall
+ condVar.Broadcast();
+ //other thread is locked on the mutex until the end of this function!
+#endif */
+ TPid=channel->Tpid();
+ chan=channel->GetChannelID();
+ CheckCreateReceiver();
+ }
+ }
+ }
+}
+
+void cTxtStatus::CheckCreateReceiver() {
+ if (!receiver && TPid ) {
+ cChannel *channel = Channels.GetByChannelID(chan);
+ if (!channel)
+ return;
+ //primary device a full-featured card
+ if (cDevice::PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit)) {
+ receiver = new cTxtReceiver(TPid, chan);
+ cDevice::PrimaryDevice()->AttachReceiver(receiver);
+ //dsyslog("OSDTeletext: Created teletext receiver for channel %d, PID %d on primary device", ChNum, TPid);
+ //primary device a DXR3 or similar
+ } else {
+ int devNum = cDevice::NumDevices();
+ bool bFound = false;
+ cDevice* pDevice = 0;
+ for (int i = 0; i < devNum && !bFound; ++i) {
+ pDevice = cDevice::GetDevice(i);
+ if (pDevice && pDevice->ProvidesChannel(channel, Setup.PrimaryLimit) && pDevice->Receiving(true)) {
+ bFound = true;
+ receiver = new cTxtReceiver(TPid, chan);
+ pDevice->AttachReceiver(receiver);
+ //dsyslog("OSDTeletext: Created teletext receiver for channel %d, PID %d on device %d", ChNum, TPid, i);
+ }
+ }
+ if (!bFound) //can this happen?
+ esyslog("OSDTeletext: Did not find appropriate device for teletext receiver for channel %s, PID %d", channel->Name(), TPid);
+ }
+ }
+}
+
+void cTxtStatus::CheckDeleteReceiver() {
+ if (receiver) {
+ //dsyslog("OSDTeletext: Deleted teletext receiver");
+ delete receiver;
+/*#ifdef OSDTELETEXT_REINSERTION_PATCH
+ //the patch only makes sense if primary device is a DVB card, so no handling for DXR3
+ cDevice::PrimaryDevice()->ReinsertTeletextPid(TPid);
+#endif*/
+ receiver = NULL;
+ }
+}
+
+/*
+//only used for suspending the receiver, if selected by user in setup
+void cTxtStatus::Action() {
+#ifdef OSDTELETEXT_REINSERTION_PATCH
+ running=true;
+
+ dsyslog("OSDTeletext waiting thread started with pid %d", getpid());
+
+ count=0;
+
+
+ while (running) {
+ cMutexLock MutexLock(&mutex);
+
+ if (doNotSuspend) {
+ CheckCreateReceiver();
+ count=0;
+ } else if (doNotReceive) {
+ CheckDeleteReceiver();
+ count=0;
+ } else {
+ count++;
+ if (count <= 20)
+ CheckCreateReceiver();
+ else if (count < 20+5*60)
+ CheckDeleteReceiver();
+ else
+ count=0; //if count=20+5*60
+ }
+
+ condVar.TimedWait(mutex, 1000); //one second
+
+ }
+
+ running=false;
+ dsyslog("OSDTeletext waiting thread ended");
+
+#endif
+}
+
+//only has an effect when suspending is enabled:
+//prevents receiving from suspension when argument is true
+//reenables suspension when argument is false,
+// but does not necessarily suspend immediately, that is the task of ForceSuspending,
+// in contrast to which it does not make any sense if suspending is
+// not enabled.
+//In clear words: When the plugin is in use, it calls the function
+//with onOrOff=true so that data is received continously during the
+//TeletextBrowser object's lifetime. When it is destroyed, it releases
+//this constraint by calling onOrOff=false.
+void cTxtStatus::ForceReceiving(bool onOrOff) {
+#ifdef OSDTELETEXT_REINSERTION_PATCH
+ if (!running)
+ return;
+ if (onOrOff && !doNotSuspend) {
+ cMutexLock MutexLock(&mutex);
+ doNotSuspend=true;
+ condVar.Broadcast();
+ } else if (!onOrOff && doNotSuspend) {
+ cMutexLock MutexLock(&mutex);
+ doNotSuspend=false;
+ condVar.Broadcast();
+ }
+#endif
+}
+
+//opposite as above:
+//allows to switch off receiving
+void cTxtStatus::ForceSuspending(bool onOrOff) {
+#ifdef OSDTELETEXT_REINSERTION_PATCH
+ if (!running) { //thread is not running, suspend anyway
+ if (onOrOff) {
+ CheckDeleteReceiver();
+ } else {
+ CheckCreateReceiver();
+ }
+ } else {
+ doNotSuspend=false; //ForceReceive may have been called before
+ if (onOrOff && !doNotReceive) {
+ cMutexLock MutexLock(&mutex);
+ doNotReceive=true;
+ condVar.Broadcast();
+ } else if (!onOrOff && doNotReceive) {
+ cMutexLock MutexLock(&mutex);
+ doNotReceive=false;
+ condVar.Broadcast();
+ }
+ }
+#endif
+}
+*/
+
+cTxtReceiver::cTxtReceiver(int TPid, tChannelID chan)
+#if VDRVERSNUM >= 10319
+ : cReceiver(0, -1, TPid),
+#else
+ : cReceiver(0, -1, 1, TPid),
+#endif
+ chan(chan), TxtPage(0), buffer((188+60)*75), running(false)
+{
+ Storage::instance()->prepareDirectory(chan);
+ // 10 ms timeout on getting TS frames
+ buffer.SetTimeouts(0, 10);
+}
+
+
+cTxtReceiver::~cTxtReceiver()
+{
+ Detach();
+ if (running) {
+ running=false;
+ buffer.Signal();
+ Cancel(2);
+ }
+ buffer.Clear();
+ delete TxtPage;
+}
+
+void cTxtReceiver::Activate(bool On)
+{
+ if (On) {
+ if (!running) {
+ running=true;
+ Start();
+ }
+ }
+ else if (running) {
+ running = false;
+ buffer.Signal();
+ Cancel(2);
+ }
+}
+
+void cTxtReceiver::Receive(uchar *Data, int Length)
+{
+ int len = Length+60;
+
+ if (!buffer.Check(len)) {
+ // Buffer overrun
+ buffer.Signal();
+ return;
+ }
+ cFrame *frame=new cFrame(Data, len);
+ if (frame && !buffer.Put(frame)) {
+ // Buffer overrun
+ delete frame;
+ buffer.Signal();
+ }
+}
+
+void cTxtReceiver::Action() {
+
+ while (running) {
+ cFrame *frame=buffer.Get();
+ if (frame) {
+ uchar *Datai=frame->Data();
+
+ for (int i=0; i < 4; i++) {
+ if (Datai[4+i*46]==2 || Datai[4+i*46]==3) {
+ for (int j=(8+i*46);j<(50+i*46);j++)
+ Datai[j]=invtab[Datai[j]];
+ DecodeTXT(&Datai[i*46]);
+ }
+ }
+
+ buffer.Drop(frame);
+ } else
+ buffer.Wait();
+ }
+
+ buffer.Clear();
+ running=false;
+}
+
+uchar cTxtReceiver::unham16 (uchar *p)
+{
+ unsigned short c1,c2;
+ c1=unhamtab[p[0]];
+ c2=unhamtab[p[1]];
+ return (c1 & 0x0F) | (c2 & 0x0F) *16;
+}
+
+void cTxtReceiver::DecodeTXT(uchar* TXT_buf)
+{
+ // Format of buffer:
+ // 0x00-0x04 ?
+ // 0x05-0x06 Clock Run-In?
+ // 0x07 Framing Code?
+ // 0x08 Magazine number (100-digit of page number)
+ // 0x09 Line number
+ // 0x0A..0x31 Line data
+ // Line 0 only:
+ // 0x0A 10-digit of page number
+ // 0x0B 1-digit of page number
+ // 0x0C Sub-Code bits 0..3
+ // 0x0D Sub-Code bits 4..6 + C4 flag
+ // 0x0E Sub-Code bits 8..11
+ // 0x0F Sub-Code bits 12..13 + C5,C6 flag
+ // 0x10 C7-C10 flags
+ // 0x11 C11-C14 flags
+ //
+ // Flags:
+ // C4 - Erase last page, new page transmitted
+ // C5 - News flash, boxed display
+ // C6 - Subtitle, boxed display
+ // C7 - Suppress Header, dont show line 0
+ // C8 - Update, page has changed
+ // C9 - Interrupt Sequence, page number is out of order
+ // C10 - Inhibit Display
+ // C11 - Magazine Serial mode
+ // C12-C14 - Language selection, lower 3 bits
+
+
+ int hdr,mag,mag8,line;
+ uchar *ptr;
+ uchar flags,lang;
+
+ hdr = unham16 (&TXT_buf[0x8]);
+ mag = hdr & 0x07;
+ mag8 = mag ?: 8;
+ line = (hdr>>3) & 0x1f;
+ ptr = &TXT_buf[10];
+
+ switch (line) {
+ case 0:
+ {
+ unsigned char b1, b2, b3, b4;
+ int pgno, subno;
+ b1 = unham16 (ptr);
+ // Page no, 10- and 1-digit
+
+ if (b1 == 0xff) break;
+ if (TxtPage) {
+ TxtPage->save();
+ delete TxtPage;
+ TxtPage=NULL;
+ }
+
+ b2 = unham16 (ptr+2); // Sub-code 0..6 + C4
+ b3 = unham16 (ptr+4); // Sub-code 8..13 + C5,C6
+ b4 = unham16 (ptr+6); // C7..C14
+
+ // flags:
+ // 0x80 C4 - Erase page
+ // 0x40 C5 - News flash
+ // 0x20 C6 - Subtitle
+ // 0x10 C7 - Suppress Header
+ // 0x08 C8 - Update
+ // 0x04 C9 - Interrupt Sequence
+ // 0x02 C9 (Bug?)
+ // 0x01 C11 - Magazine Serial mode
+ flags=b2 & 0x80;
+ flags|=(b3&0x40)|((b3>>2)&0x20); //??????
+ flags|=((b4<<4)&0x10)|((b4<<2)&0x08)|(b4&0x04)|((b4>>1)&0x02)|((b4>>4)&0x01);
+ lang=((b4>>5) & 0x07);
+
+ pgno = mag8 * 256 + b1;
+ subno = (b2 + b3 * 256) & 0x3f7f; // Sub Page Number
+
+ TxtPage = new cTelePage(PageID(chan, pgno, subno), flags, lang, mag);
+ TxtPage->SetLine((int)line,(uchar *)ptr);
+ break;
+ }
+ case 1 ... 25:
+ {
+ if (TxtPage) TxtPage->SetLine((int)line,(uchar *)ptr);
+ break;
+ }
+ /*case 23:
+ {
+ if (TxtPage) {
+ TxtPage->save();
+ delete TxtPage;
+ TxtPage=NULL;
+ }
+ break;
+ }*/
+ default:
+ break;
+ }
+}
+
+
diff --git a/txtrecv.h b/txtrecv.h
new file mode 100644
index 0000000..cafb1dd
--- /dev/null
+++ b/txtrecv.h
@@ -0,0 +1,204 @@
+/***************************************************************************
+ * Copyright (c) 2003,2004 by Marcel Wiesweg *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __TXTRECV_H
+#define __TXTRECV_H
+
+#include <vdr/status.h>
+#include <vdr/receiver.h>
+#include <vdr/thread.h>
+#include <vdr/ringbuffer.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct PageID {
+ PageID() { page=subPage=0; }
+ PageID(tChannelID id, int p, int s) { set(id, p, s); }
+ void set(tChannelID id, int p, int s)
+ { channel=id; page=p; subPage=s; }
+ tChannelID channel;
+ int page;
+ int subPage;
+};
+
+struct StorageHandle {
+public:
+ StorageHandle() { handle=-1; }
+ StorageHandle(const StorageHandle &s) { handle=s.handle; }
+ StorageHandle(int h) { handle=h; }
+ StorageHandle &operator=(int h) { handle=h; return *this; }
+ StorageHandle &operator=(const StorageHandle &s) { handle=s.handle; return *this; }
+ operator bool() const { return handle!=-1; }
+ operator int() const { return handle; }
+private:
+ int handle;
+};
+
+class RootDir {
+public:
+ static void setRootDir(const char *);
+ static const char *getRootDir();
+protected:
+ static const char *root;
+};
+
+class Storage : public RootDir {
+public:
+ virtual ~Storage();
+ enum StorageSystem { StorageSystemLegacy, StorageSystemPacked };
+ //must be called before the first call to instance()
+ static void setSystem(StorageSystem system);
+ void setMaxStorage(int maxMB=-1);
+
+ static Storage *instance();
+
+ //must be called before operation starts. Set all options (RootDir, maxStorage) before.
+ void init();
+ virtual void cleanUp() = 0;
+
+ virtual void getFilename(char *buffer, int bufLength, PageID page);
+ void prepareDirectory(tChannelID chan);
+
+ virtual StorageHandle openForWriting(PageID page) = 0;
+ virtual StorageHandle openForReading(PageID page, bool countAsAccess) = 0;
+ virtual ssize_t write(const void *ptr, size_t size, StorageHandle stream) = 0;
+ virtual ssize_t read(void *ptr, size_t size, StorageHandle stream) = 0;
+ virtual void close(StorageHandle stream) = 0;
+protected:
+ virtual void initMaxStorage(int maxMB=-1) = 0;
+
+ Storage();
+ int cleanSubDir(const char *dir);
+ int doCleanUp();
+ virtual int actualFileSize(int netFileSize) { return netFileSize; }
+ static Storage *s_self;
+ void freeSpace();
+ bool exists(const char* file);
+
+ long byteCount;
+ char *currentDir;
+private:
+ static StorageSystem system;
+ int storageOption;
+ bool failedFreeSpace;
+};
+
+class LegacyStorage : public Storage {
+public:
+ LegacyStorage();
+ virtual ~LegacyStorage();
+ virtual void cleanUp();
+
+ virtual StorageHandle openForWriting(PageID page);
+ virtual StorageHandle openForReading(PageID page, bool countAsAccess);
+ virtual ssize_t write(const void *ptr, size_t size, StorageHandle stream);
+ virtual ssize_t read(void *ptr, size_t size, StorageHandle stream)
+ { return ::read((int)stream, ptr, size); }
+ virtual void close(StorageHandle stream)
+ { ::close((int)stream); }
+protected:
+ virtual void initMaxStorage(int maxMB=-1);
+ void registerFile(PageID page);
+ virtual int actualFileSize(int netFileSize);
+ //int maxPages;
+ long maxBytes;
+ int fsBlockSize;
+ int pageBytes;
+};
+
+class PackedStorage : public LegacyStorage {
+public:
+ PackedStorage();
+ //virtual void setMaxStorage(int maxMB=-1);
+ //virtual void cleanUp();
+
+ virtual void getFilename(char *buffer, int bufLength, PageID page);
+ virtual StorageHandle openForWriting(PageID page);
+ virtual StorageHandle openForReading(PageID page, bool countAsAccess);
+protected:
+ struct PageAddress {
+ bool operator==(const PageID &id) const
+ { return page==id.page && subPage==id.subPage; }
+ void operator=(const PageID &id)
+ { page=id.page; subPage=id.subPage; }
+ int page;
+ int subPage;
+ };
+ bool seekTo(PageID page, int fd, bool create);
+ void registerFile(PageID page);
+};
+
+class cTelePage {
+ private:
+ int mag;
+ unsigned char flags;
+ unsigned char lang;
+ PageID page;
+ unsigned char pagebuf[27*40];
+ char Directory [255];
+ public:
+ cTelePage(PageID page, uchar flags, uchar lang, int mag);
+ ~cTelePage();
+ void SetLine(int, uchar*);
+ void save();
+ };
+
+class cRingTxtFrames : public cRingBufferFrame {
+ public:
+ cRingTxtFrames(int Size) : cRingBufferFrame(Size, true) {};
+ ~cRingTxtFrames() { Clear(); };
+ void Wait(void) { WaitForGet(); };
+ void Signal(void) { EnableGet(); };
+ bool Check(int Size) { return (Free() >= Size); };
+};
+
+class cTxtReceiver : public cReceiver, public cThread {
+private:
+ void DecodeTXT(uchar*);
+ uchar unham16 (uchar*);
+ tChannelID chan;
+ cTelePage *TxtPage;
+protected:
+ virtual void Activate(bool On);
+ virtual void Receive(uchar *Data, int Length);
+ void Action();
+ cRingTxtFrames buffer;
+ bool running;
+public:
+ cTxtReceiver(int TPid, tChannelID chan);
+ virtual ~cTxtReceiver();
+};
+
+class cTxtStatus : public cStatus/*, public cThread*/ {
+private:
+ cTxtReceiver *receiver;
+ //bool running;
+ //cCondVar condVar;
+ //cMutex mutex;
+ //int count;
+protected:
+ int TPid;
+ tChannelID chan;
+ //bool doNotSuspend;
+ //bool doNotReceive;
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+ //virtual void Action();
+ void CheckCreateReceiver();
+ void CheckDeleteReceiver();
+public:
+ cTxtStatus(void);
+ ~cTxtStatus();
+ //void ForceReceiving(bool onOrOff);
+ //void ForceSuspending(bool onOrOff);
+};
+
+
+#endif
diff --git a/txtrender.c b/txtrender.c
new file mode 100644
index 0000000..f4b27e6
--- /dev/null
+++ b/txtrender.c
@@ -0,0 +1,543 @@
+/***************************************************************************
+ * *
+ * txtrender.c - Teletext display abstraction and teletext code *
+ * renderer *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#include <strings.h>
+#include "txtrender.h"
+
+
+// Font tables
+
+// teletext uses 7-bit numbers to identify a font set.
+// There are three font sets involved:
+// Primary G0, Secondary G0, and G2 font set.
+
+// Font tables are organized in blocks of 8 fonts:
+
+enumCharsets FontBlockG0_0000[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0_PT_ES,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_LATIN_G0
+};
+
+enumCharsets FontBlockG2Latin[8]={
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2
+};
+
+enumCharsets FontBlockG0_0001[8] = {
+ CHARSET_LATIN_G0_PL,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_LATIN_G0
+};
+
+enumCharsets FontBlockG0_0010[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_SV_FI,
+ CHARSET_LATIN_G0_IT,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_LATIN_G0_PT_ES,
+ CHARSET_LATIN_G0_TR,
+ CHARSET_LATIN_G0
+};
+
+
+enumCharsets FontBlockG0_0011[8] = {
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_SR_HR_SL,
+ CHARSET_LATIN_G0,
+ CHARSET_LATIN_G0_RO
+};
+
+enumCharsets FontBlockG0_0100[8] = {
+ CHARSET_CYRILLIC_G0_SR_HR,
+ CHARSET_LATIN_G0_DE,
+ CHARSET_LATIN_G0_EE,
+ CHARSET_LATIN_G0_LV_LT,
+ CHARSET_CYRILLIC_G0_RU_BG,
+ CHARSET_CYRILLIC_G0_UK,
+ CHARSET_LATIN_G0_CZ_SK,
+ CHARSET_INVALID
+};
+
+enumCharsets FontBlockG2_0100[8] = {
+ CHARSET_CYRILLIC_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_CYRILLIC_G2,
+ CHARSET_CYRILLIC_G2,
+ CHARSET_LATIN_G2,
+ CHARSET_INVALID
+};
+
+enumCharsets FontBlockG0_0110[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G0_TR,
+ CHARSET_GREEK_G0
+};
+
+enumCharsets FontBlockG2_0110[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G2,
+ CHARSET_GREEK_G2
+};
+
+enumCharsets FontBlockG0_1000[8] = {
+ CHARSET_LATIN_G0_EN,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_LATIN_G0_FR,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G0
+};
+
+enumCharsets FontBlockG2_1000[8] = {
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2
+};
+
+enumCharsets FontBlockG0_1010[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_HEBREW_G0,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G0,
+};
+
+enumCharsets FontBlockG2_1010[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+ CHARSET_INVALID,
+ CHARSET_ARABIC_G2,
+};
+
+enumCharsets FontBlockInvalid[8] = {
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID,
+ CHARSET_INVALID
+};
+
+
+
+// The actual font table definition:
+// Split the 7-bit number into upper 4 and lower 3 bits,
+// use upper 4 bits for outer array,
+// use lower 3 bits for inner array
+
+struct structFontBlock {
+ enumCharsets *G0Block;
+ enumCharsets *G2Block;
+};
+
+structFontBlock FontTable[16] = {
+ { FontBlockG0_0000, FontBlockG2Latin }, // 0000 block
+ { FontBlockG0_0001, FontBlockG2Latin }, // 0001 block
+ { FontBlockG0_0010, FontBlockG2Latin }, // 0010 block
+ { FontBlockG0_0011, FontBlockG2Latin }, // 0011 block
+ { FontBlockG0_0100, FontBlockG2_0100 }, // 0100 block
+ { FontBlockInvalid, FontBlockInvalid }, // 0101 block
+ { FontBlockG0_0110, FontBlockG2_0110 }, // 0110 block
+ { FontBlockInvalid, FontBlockInvalid }, // 0111 block
+ { FontBlockG0_1000, FontBlockG2_1000 }, // 1000 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1001 block
+ { FontBlockG0_1010, FontBlockG2_1010 }, // 1010 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1011 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1100 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1101 block
+ { FontBlockInvalid, FontBlockInvalid }, // 1110 block
+ { FontBlockInvalid, FontBlockInvalid } // 1111 block
+};
+
+inline enumCharsets GetG0Charset(int codepage) {
+ return FontTable[codepage>>3].G0Block[codepage&7];
+}
+inline enumCharsets GetG2Charset(int codepage) {
+ return FontTable[codepage>>3].G2Block[codepage&7];
+}
+
+
+cRenderPage::cRenderPage() {
+ Dirty=false;
+ DirtyAll=false;
+
+ // Todo: make this configurable
+ FirstG0CodePage=0;
+ SecondG0CodePage=0;
+}
+
+enum enumSizeMode {
+ // Possible size modifications of characters
+ sizeNormal,
+ sizeDoubleWidth,
+ sizeDoubleHeight,
+ sizeDoubleSize
+};
+
+/*
+// Debug only: List of teletext spacing code short names
+const char *(names[0x20])={
+ "AlBk","AlRd","AlGr","AlYl","AlBl","AlMg","AlCy","AlWh",
+ "Flsh","Stdy","EnBx","StBx","SzNo","SzDh","SzDw","SzDs",
+ "MoBk","MoRd","MoGr","MoYl","MoBl","MoMg","MoCy","MoWh",
+ "Conc","GrCn","GrSp","ESC", "BkBl","StBk","HoMo","ReMo"};
+*/
+
+void cRenderPage::ReadTeletextHeader(unsigned char *Header) {
+ // Format of buffer:
+ // 0 String "VTXV4"
+ // 5 always 0x01
+ // 6 magazine number
+ // 7 page number
+ // 8 flags
+ // 9 lang
+ // 10 always 0x00
+ // 11 always 0x00
+ // 12 teletext data, 40x24 bytes
+ // Format of flags:
+ // 0x80 C4 - Erase page
+ // 0x40 C5 - News flash
+ // 0x20 C6 - Subtitle
+ // 0x10 C7 - Suppress Header
+ // 0x08 C8 - Update
+ // 0x04 C9 - Interrupt Sequence
+ // 0x02 C9 (Bug?)
+ // 0x01 C11 - Magazine Serial mode
+
+ Flags=Header[8];
+ Lang=Header[9];
+}
+
+
+void cRenderPage::RenderTeletextCode(unsigned char *PageCode) {
+ int x,y;
+ bool EmptyNextLine=false;
+ // Skip one line, in case double height chars were/will be used
+
+ // Get code pages:
+ int LocalG0CodePage=(FirstG0CodePage & 0x78)
+ | ((Lang & 0x04)>>2) | (Lang & 0x02) | ((Lang & 0x01)<<2);
+
+ enumCharsets FirstG0=GetG0Charset(LocalG0CodePage);
+ enumCharsets SecondG0=GetG0Charset(SecondG0CodePage);
+ // Reserved for later use:
+ // enumCharsets FirstG2=GetG2Charset(LocalG0CodePage);
+
+ for (y=0;y<24;(EmptyNextLine?y+=2:y++)) {
+ // Start of line: Set start of line defaults
+
+ // Hold Mosaics mode: Remember last mosaic char/charset
+ // for next spacing code
+ bool HoldMosaics=false;
+ unsigned char HoldMosaicChar=' ';
+ enumCharsets HoldMosaicCharset=FirstG0;
+
+ enumSizeMode Size=sizeNormal;
+ // Font size modification
+ bool SecondCharset=false;
+ // Use primary or secondary G0 charset
+ bool GraphicCharset=false;
+ // Graphics charset used?
+ bool SeparateGraphics=false;
+ // Use separated vs. contiguous graphics charset
+ bool NoNextChar=false;
+ // Skip display of next char, for double-width
+ EmptyNextLine=false;
+ // Skip next line, for double-height
+
+ cTeletextChar c;
+ // auto.initialized to everything off
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(FirstG0);
+
+ if (y==0 && (Flags&0x10)) {
+ c.SetBoxedOut(true);
+ }
+ if (Flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+
+ // Pre-scan for double-height and double-size codes
+ for (x=0;x<40;x++) {
+ if (y==0 && x<8) x=8;
+ if ((PageCode[x+40*y] & 0x7f)==0x0D || (PageCode[x+40*y] & 0x7f)==0x0F)
+ EmptyNextLine=true;
+ }
+
+ // Move through line
+ for (x=0;x<40;x++) {
+ unsigned char ttc=PageCode[x+40*y] & 0x7f;
+ // skip parity check
+
+ if (y==0 && x<8) continue;
+ // no displayable data here...
+
+/* // Debug only: Output line data and spacing codes
+ if (y==6) {
+ if (ttc<0x20)
+ printf("%s ",names[ttc]);
+ else
+ printf("%02x ",ttc);
+ if (x==39) printf("\n");
+ }
+*/
+
+ // Handle all 'Set-At' spacing codes
+ switch (ttc) {
+ case 0x09: // Steady
+ c.SetBlink(false);
+ break;
+ case 0x0C: // Normal Size
+ if (Size!=sizeNormal) {
+ Size=sizeNormal;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x18: // Conceal
+ c.SetConceal(true);
+ break;
+ case 0x19: // Contiguous Mosaic Graphics
+ SeparateGraphics=false;
+ if (GraphicCharset)
+ c.SetCharset(CHARSET_GRAPHICS_G1);
+ break;
+ case 0x1A: // Separated Mosaic Graphics
+ SeparateGraphics=true;
+ if (GraphicCharset)
+ c.SetCharset(CHARSET_GRAPHICS_G1_SEP);
+ break;
+ case 0x1C: // Black Background
+ c.SetBGColor(ttcBlack);
+ break;
+ case 0x1D: // New Background
+ c.SetBGColor(c.GetFGColor());
+ break;
+ case 0x1E: // Hold Mosaic
+ HoldMosaics=true;
+ break;
+ }
+
+ // temporary copy of character data:
+ cTeletextChar c2=c;
+ // c2 will be text character or space character or hold mosaic
+ // c2 may also have temporary flags or charsets
+
+ if (ttc<0x20) {
+ // Spacing code, display space or hold mosaic
+ if (HoldMosaics) {
+ c2.SetChar(HoldMosaicChar);
+ c2.SetCharset(HoldMosaicCharset);
+ } else {
+ c2.SetChar(' ');
+ }
+ } else {
+ // Character code
+ c2.SetChar(ttc);
+ if (GraphicCharset) {
+ if (ttc&0x20) {
+ // real graphics code, remember for HoldMosaics
+ HoldMosaicChar=ttc;
+ HoldMosaicCharset=c.GetCharset();
+ } else {
+ // invalid code, pass-through to G0
+ c2.SetCharset(SecondCharset?SecondG0:FirstG0);
+ }
+ }
+ }
+
+ // Handle double-height and double-width extremes
+ if (y>=23) {
+ if (Size==sizeDoubleHeight) Size=sizeNormal;
+ if (Size==sizeDoubleSize) Size=sizeDoubleWidth;
+ }
+ if (x>=38) {
+ if (Size==sizeDoubleWidth) Size=sizeNormal;
+ if (Size==sizeDoubleSize) Size=sizeDoubleHeight;
+ }
+
+ // Now set character code
+
+ if (NoNextChar) {
+ // Suppress this char due to double width last char
+ NoNextChar=false;
+ } else {
+ switch (Size) {
+ case sizeNormal:
+ // Normal sized
+ SetChar(x,y,c2);
+ if (EmptyNextLine && y<23) {
+ // Clean up next line
+ SetChar(x,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ }
+ break;
+ case sizeDoubleWidth:
+ // Double width
+ SetChar(x,y,c2.ToDblWidth(dblw_Left));
+ SetChar(x+1,y,c2.ToDblWidth(dblw_Right));
+ if (EmptyNextLine && y<23) {
+ // Clean up next line
+ SetChar(x ,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ SetChar(x+1,y+1,c2.ToChar(' ').ToCharset(FirstG0));
+ }
+ NoNextChar=true;
+ break;
+ case sizeDoubleHeight:
+ // Double height
+ SetChar(x,y,c2.ToDblHeight(dblh_Top));
+ SetChar(x,y+1,c2.ToDblHeight(dblh_Bottom));
+ break;
+ case sizeDoubleSize:
+ // Double Size
+ SetChar(x , y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Left ));
+ SetChar(x+1, y,c2.ToDblHeight(dblh_Top ).ToDblWidth(dblw_Right));
+ SetChar(x ,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Left ));
+ SetChar(x+1,y+1,c2.ToDblHeight(dblh_Bottom).ToDblWidth(dblw_Right));
+ NoNextChar=true;
+ break;
+ }
+ }
+
+ // Handle all 'Set-After' spacing codes
+ switch (ttc) {
+ case 0x00 ... 0x07: // Set FG color
+ if (GraphicCharset) {
+ // Actual switch from graphics charset
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ c.SetFGColor((enumTeletextColor)ttc);
+ c.SetCharset(SecondCharset?SecondG0:FirstG0);
+ GraphicCharset=false;
+ c.SetConceal(false);
+ break;
+ case 0x08: // Flash
+ c.SetBlink(true);
+ break;
+ case 0x0A: // End Box
+ c.SetBoxedOut(true);
+ break;
+ case 0x0B: // Start Box
+ c.SetBoxedOut(false);
+ break;
+ case 0x0D: // Double Height
+ if (Size!=sizeDoubleHeight) {
+ Size=sizeDoubleHeight;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x0E: // Double Width
+ if (Size!=sizeDoubleWidth) {
+ Size=sizeDoubleWidth;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x0F: // Double Size
+ if (Size!=sizeDoubleSize) {
+ Size=sizeDoubleSize;
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ break;
+ case 0x10 ... 0x17: // Mosaic FG Color
+ if (!GraphicCharset) {
+ // Actual switch to graphics charset
+ HoldMosaicChar=' ';
+ HoldMosaicCharset=FirstG0;
+ }
+ c.SetFGColor((enumTeletextColor)(ttc-0x10));
+ c.SetCharset(SeparateGraphics?CHARSET_GRAPHICS_G1_SEP:CHARSET_GRAPHICS_G1);
+ GraphicCharset=true;
+ c.SetConceal(false);
+ break;
+ case 0x1B: // ESC Switch
+ SecondCharset=!SecondCharset;
+ if (!GraphicCharset) c.SetCharset(SecondCharset?SecondG0:FirstG0);
+ break;
+ case 0x1F: // Release Mosaic
+ HoldMosaics=false;
+ break;
+ }
+ } // end for x
+ } // end for y
+
+ for (x=0;x<40;x++) {
+ // Clean out last line
+ cTeletextChar c;
+ c.SetFGColor(ttcWhite);
+ c.SetBGColor(ttcBlack);
+ c.SetCharset(FirstG0);
+ c.SetChar(' ');
+ if (Flags&0x60) {
+ c.SetBoxedOut(true);
+ }
+ SetChar(x,24,c);
+ }
+}
+
+
diff --git a/txtrender.h b/txtrender.h
new file mode 100644
index 0000000..e7da20d
--- /dev/null
+++ b/txtrender.h
@@ -0,0 +1,311 @@
+/***************************************************************************
+ * *
+ * txtrender.h - Teletext display abstraction and teletext code *
+ * renderer *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * Changelog: *
+ * 2005-03 initial version (c) Udo Richter *
+ * *
+ ***************************************************************************/
+
+#ifndef OSDTELETEXT_TXTRENDER_H_
+#define OSDTELETEXT_TXTRENDER_H_
+
+#include <stdio.h>
+
+
+// Teletext character sets
+enum enumCharsets {
+ CHARSET_LATIN_G0 = 0x0000, // native latin (partially todo)
+ CHARSET_LATIN_G0_CZ_SK = 0x0100, // Czech/Slovak (todo)
+ CHARSET_LATIN_G0_EN = 0x0200, // English
+ CHARSET_LATIN_G0_EE = 0x0300, // Estonian (todo)
+ CHARSET_LATIN_G0_FR = 0x0400, // French
+ CHARSET_LATIN_G0_DE = 0x0500, // German
+ CHARSET_LATIN_G0_IT = 0x0600, // Italian
+ CHARSET_LATIN_G0_LV_LT = 0x0700, // Lettish/Lithuanian (todo)
+ CHARSET_LATIN_G0_PL = 0x0800, // Polish (todo)
+ CHARSET_LATIN_G0_PT_ES = 0x0900, // Portugese/Spanish
+ CHARSET_LATIN_G0_RO = 0x0A00, // Romanian (todo)
+ CHARSET_LATIN_G0_SR_HR_SL = 0x0B00, // Serbian/Croatian/Slovenian (todo)
+ CHARSET_LATIN_G0_SV_FI = 0x0C00, // Swedish/Finnish
+ CHARSET_LATIN_G0_TR = 0x0D00, // Turkish (todo)
+ CHARSET_LATIN_G2 = 0x0E00, // Latin G2 supplementary set (todo)
+ CHARSET_CYRILLIC_G0_SR_HR = 0x0F00, // Serbian/Croatian (todo)
+ CHARSET_CYRILLIC_G0_RU_BG = 0x1000, // Russian/Bulgarian (todo)
+ CHARSET_CYRILLIC_G0_UK = 0x1100, // Ukrainian (todo)
+ CHARSET_CYRILLIC_G2 = 0x1200, // Cyrillic G2 Supplementary (todo)
+ CHARSET_GREEK_G0 = 0x1300, // Greek G0 (todo)
+ CHARSET_GREEK_G2 = 0x1400, // Greeek G2 (todo)
+ CHARSET_ARABIC_G0 = 0x1500, // Arabic G0 (todo)
+ CHARSET_ARABIC_G2 = 0x1600, // Arabic G2 (todo)
+ CHARSET_HEBREW_G0 = 0x1700, // Hebrew G0 (todo)
+ CHARSET_GRAPHICS_G1 = 0x1800, // G1 graphics set
+ CHARSET_GRAPHICS_G1_SEP = 0x1900, // G1 graphics set, separated
+ CHARSET_GRAPHICS_G3 = 0x1A00, // G3 graphics set (todo)
+ CHARSET_INVALID = 0x1F00 // no charset defined
+};
+
+// Macro to get the lowest non-0 bit position from a bit mask
+// Should evaluate to const on a const mask
+#define LowestSet2Bit(mask) ((mask)&0x0001?0:1)
+#define LowestSet4Bit(mask) ((mask)&0x0003?LowestSet2Bit(mask):LowestSet2Bit((mask)>>2)+2)
+#define LowestSet8Bit(mask) ((mask)&0x000f?LowestSet4Bit(mask):LowestSet4Bit((mask)>>4)+4)
+#define LowestSet16Bit(mask) ((mask)&0x00ff?LowestSet8Bit(mask):LowestSet8Bit((mask)>>8)+8)
+#define LowestSet32Bit(mask) ((mask)&0xffff?LowestSet16Bit(mask):LowestSet16Bit((mask)>>16)+16)
+
+
+// Character modifcation double height:
+enum enumDblHeight {
+ dblh_Normal=0x00000000, // normal height
+ dblh_Top =0x04000000, // upper half character
+ dblh_Bottom=0x08000000 // lower half character
+};
+// Character modifcation double width:
+enum enumDblWidth {
+ dblw_Normal=0x00000000, // normal width
+ dblw_Left =0x10000000, // left half character
+ dblw_Right =0x20000000 // right half character
+};
+
+// Teletext colors
+enum enumTeletextColor {
+ // level 1:
+ ttcBlack=0,
+ ttcRed=1,
+ ttcGreen=2,
+ ttcYellow=3,
+ ttcBlue=4,
+ ttcMagenta=5,
+ ttcCyan=6,
+ ttcWhite=7,
+ // level 2.5:
+ ttcTransparent=8,
+ ttcHalfRed=9,
+ ttcHalfGreen=10,
+ ttcHalfYellow=11,
+ ttcHalfBlue=12,
+ ttcHalfMagenta=13,
+ ttcHalfCyan=14,
+ ttcGrey=15,
+ // unnamed, level 2.5:
+ ttcColor16=16, ttcColor17=17, ttcColor18=18, ttcColor19=19,
+ ttcColor20=20, ttcColor21=21, ttcColor22=22, ttcColor23=23,
+ ttcColor24=24, ttcColor25=25, ttcColor26=26, ttcColor27=27,
+ ttcColor28=28, ttcColor29=29, ttcColor30=30, ttcColor31=31,
+
+ ttcFirst=0, ttcLast=31
+};
+inline enumTeletextColor& operator++(enumTeletextColor& c) { return c=enumTeletextColor(int(c)+1); }
+inline enumTeletextColor operator++(enumTeletextColor& c, int) { enumTeletextColor tmp(c); ++c; return tmp; }
+
+class cTeletextChar {
+ // Wrapper class that represents a teletext character,
+ // including colors and effects. Should optimize back
+ // to 4 byte unsigned int on compile.
+
+protected:
+ unsigned int c;
+
+ static const unsigned int CHAR = 0x000000FF;
+ // character code
+ static const unsigned int CHARSET = 0x00001F00;
+ // character set code, see below
+ static const unsigned int BOXOUT = 0x00004000;
+ // 'boxed' mode hidden area
+ static const unsigned int DIRTY = 0x00008000;
+ // 'dirty' bit - internal marker only
+ static const unsigned int FGCOLOR = 0x001F0000;
+ // 5-bit foreground color code, 3 bit used for now
+ static const unsigned int BGCOLOR = 0x03E00000;
+ // 5-bit background color code, 3 bit used for now
+ static const unsigned int DBLHEIGHT = 0x0C000000;
+ // show double height
+ static const unsigned int DBLWIDTH = 0x30000000;
+ // show double width (todo)
+ static const unsigned int CONCEAL = 0x40000000;
+ // character concealed
+ static const unsigned int BLINK = 0x80000000;
+ // blinking character
+
+ cTeletextChar(unsigned int cc) { c=cc; }
+
+public:
+ cTeletextChar() { c=0; }
+
+ // inline helper functions:
+ // For each parameter encoded into the 32-bit int, there is
+ // a Get...() to read, a Set...() to write, and a To...() to
+ // return a modified copy
+
+ inline unsigned char GetChar()
+ { return c&CHAR; }
+ inline void SetChar(unsigned char chr)
+ { c=(c&~CHAR)|chr; }
+ inline cTeletextChar ToChar(unsigned char chr)
+ { return cTeletextChar((c&~CHAR)|chr); }
+
+ inline enumCharsets GetCharset()
+ { return (enumCharsets)(c&CHARSET); }
+ inline void SetCharset(enumCharsets charset)
+ { c=(c&~CHARSET)|charset; }
+ inline cTeletextChar ToCharset(enumCharsets charset)
+ { return cTeletextChar((c&~CHARSET)|charset); }
+
+ inline enumTeletextColor GetFGColor()
+ { return (enumTeletextColor)((c&FGCOLOR) >> LowestSet32Bit(FGCOLOR)); }
+ inline void SetFGColor(enumTeletextColor fgc)
+ { c=(c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR)); }
+ inline cTeletextChar ToFGColor(enumTeletextColor fgc)
+ { return cTeletextChar((c&~FGCOLOR) | (fgc << LowestSet32Bit(FGCOLOR))); }
+
+ inline enumTeletextColor GetBGColor()
+ { return (enumTeletextColor)((c&BGCOLOR) >> LowestSet32Bit(BGCOLOR)); }
+ inline void SetBGColor(enumTeletextColor bgc)
+ { c=(c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR)); }
+ inline cTeletextChar ToBGColor(enumTeletextColor bgc)
+ { return cTeletextChar((c&~BGCOLOR) | (bgc << LowestSet32Bit(BGCOLOR))); }
+
+ inline bool GetBoxedOut()
+ { return c&BOXOUT; }
+ inline void SetBoxedOut(bool BoxedOut)
+ { c=(BoxedOut)?(c|BOXOUT):(c&~BOXOUT); }
+ inline cTeletextChar ToBoxedOut(bool BoxedOut)
+ { return cTeletextChar((BoxedOut)?(c|BOXOUT):(c&~BOXOUT)); }
+
+ inline bool GetDirty()
+ { return c&DIRTY; }
+ inline void SetDirty(bool Dirty)
+ { c=(Dirty)?(c|DIRTY):(c&~DIRTY); }
+ inline cTeletextChar ToDirty(bool Dirty)
+ { return cTeletextChar((Dirty)?(c|DIRTY):(c&~DIRTY)); }
+
+ inline enumDblHeight GetDblHeight()
+ { return (enumDblHeight)(c&DBLHEIGHT); }
+ inline void SetDblHeight(enumDblHeight dh)
+ { c=(c&~(DBLHEIGHT)) | dh; }
+ inline cTeletextChar ToDblHeight(enumDblHeight dh)
+ { return cTeletextChar((c&~(DBLHEIGHT)) | dh); }
+
+ inline enumDblWidth GetDblWidth()
+ { return (enumDblWidth)(c&DBLWIDTH); }
+ inline void SetDblWidth(enumDblWidth dw)
+ { c=(c&~(DBLWIDTH)) | dw; }
+ inline cTeletextChar ToDblWidth(enumDblWidth dw)
+ { return cTeletextChar((c&~(DBLWIDTH)) | dw); }
+
+ inline bool GetConceal()
+ { return c&CONCEAL; }
+ inline void SetConceal(bool Conceal)
+ { c=(Conceal)?(c|CONCEAL):(c&~CONCEAL); }
+ inline cTeletextChar ToConceal(bool Conceal)
+ { return cTeletextChar((Conceal)?(c|CONCEAL):(c&~CONCEAL)); }
+
+ inline bool GetBlink()
+ { return c&BLINK; }
+ inline void SetBlink(bool Blink)
+ { c=(Blink)?(c|BLINK):(c&~BLINK); }
+ inline cTeletextChar ToBlink(bool Blink)
+ { return cTeletextChar((Blink)?(c|BLINK):(c&~BLINK)); }
+
+ bool operator==(cTeletextChar &chr) { return c==chr.c; }
+ bool operator!=(cTeletextChar &chr) { return c!=chr.c; }
+};
+
+
+class cRenderPage {
+ // Abstraction of a 40x25 teletext character page
+ // with all special attributes and colors
+ // Additionally tracks changes by maintaining a
+ // 'dirty' flag on each character
+
+protected:
+ cTeletextChar Page[40][25];
+
+ int Flags;
+ // 0x80 C4 - Erase page
+ // 0x40 C5 - News flash
+ // 0x20 C6 - Subtitle
+ // 0x10 C7 - Suppress Header
+ // 0x08 C8 - Update
+ // 0x04 C9 - Interrupt Sequence
+ // 0x02 C10 - Inhibit Display
+ // 0x01 C11 - Magazine Serial mode
+
+ int Lang;
+ // 3-bit language number from header
+
+ bool Dirty; // At least one character is dirty
+ bool DirtyAll; // Consider all characters dirty, regardless of flag
+
+ // Font Code pages
+ int FirstG0CodePage; // 7-bit number, lower 3 bits ignored
+ int SecondG0CodePage; // 7-bit number
+
+public:
+ cRenderPage();
+
+ cTeletextChar GetChar(int x, int y) {
+ // Read character content from page
+ if (x<0 || x>=40 || y<0 || y>=25) {
+ printf("Warning: out of bounds read access to teletext page\n");
+ return cTeletextChar();
+ }
+ return Page[x][y].ToDirty(false);
+ }
+
+ bool IsDirty() {
+ // global dirty status
+ return Dirty;
+ }
+
+ bool IsDirty(int x, int y) {
+ // local dirty status
+ if (x<0 || x>=40 || y<0 || y>=25) {
+ printf("Warning: out of bounds read access to teletext page\n");
+ return false;
+ }
+ return Page[x][y].GetDirty() | DirtyAll;
+ }
+
+ void MakeDirty(int x, int y) {
+ // force one character dirty
+ if (x<0 || x>=40 || y<0 || y>=25) {
+ printf("Warning: out of bounds write access to teletext page\n");
+ return;
+ }
+ Page[x][y].SetDirty(true);
+ Dirty=true;
+ }
+
+ void SetChar(int x, int y, cTeletextChar c) {
+ // Set character at given location
+
+ if (x<0 || x>=40 || y<0 || y>=25) {
+ printf("Warning: out of bounds write access to teletext page\n");
+ return;
+ }
+ if (GetChar(x,y) != c) {
+ Page[x][y]=c.ToDirty(true);
+ Dirty=true;
+ }
+ }
+
+ void ReadTeletextHeader(unsigned char *Header);
+ // Read header from teletext page
+ // Header must be a 12 bytes buffer
+
+ void RenderTeletextCode(unsigned char *PageCode);
+ // Interprete teletext code referenced by PageCode
+ // and draw the whole page content into this object
+ // PageCode must be a 40*24 bytes buffer
+};
+
+
+
+#endif