diff options
author | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-02 21:00:33 +0100 |
---|---|---|
committer | Tobias Grimm <tobias@e-tobi.loc> | 2008-12-02 21:00:33 +0100 |
commit | b451fdb5a36c0f749d63d53165cdf4e84a8f476a (patch) | |
tree | aa3b6548ea52ef133028098c8fbaebbe47ed8a5d | |
download | vdr-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-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 207 | ||||
-rw-r--r-- | Makefile | 86 | ||||
-rw-r--r-- | README | 98 | ||||
-rw-r--r-- | README.DE | 86 | ||||
-rw-r--r-- | display.c | 240 | ||||
-rw-r--r-- | display.h | 131 | ||||
-rw-r--r-- | displaybase.c | 507 | ||||
-rw-r--r-- | displaybase.h | 287 | ||||
-rw-r--r-- | i18n.c | 445 | ||||
-rw-r--r-- | i18n.h | 16 | ||||
-rw-r--r-- | menu.c | 681 | ||||
-rw-r--r-- | menu.h | 82 | ||||
-rw-r--r-- | osdteletext.c | 481 | ||||
-rw-r--r-- | setup.h | 65 | ||||
-rw-r--r-- | tables.h | 112 | ||||
-rw-r--r-- | txtfont.c | 3371 | ||||
-rw-r--r-- | txtfont.h | 14 | ||||
-rw-r--r-- | txtrecv.c | 884 | ||||
-rw-r--r-- | txtrecv.h | 204 | ||||
-rw-r--r-- | txtrender.c | 543 | ||||
-rw-r--r-- | txtrender.h | 311 |
22 files changed, 9191 insertions, 0 deletions
@@ -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. @@ -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* *~ @@ -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 @@ -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 } + }; @@ -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 @@ -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; +} + @@ -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! @@ -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(¤tDir, "%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 |