summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Eckhardt <vdr@uli-eckhardt.de>2017-04-23 16:10:16 +0200
committerUlrich Eckhardt <vdr@uli-eckhardt.de>2017-04-23 16:10:16 +0200
commit1dbb7611337dc4b61817cad734a47b1a0404b77c (patch)
treee9b41e387c25c05678d84ce388f9e1977ff18f84
downloadvdr-plugin-radio-1dbb7611337dc4b61817cad734a47b1a0404b77c.tar.gz
vdr-plugin-radio-1dbb7611337dc4b61817cad734a47b1a0404b77c.tar.bz2
Import of original Radio Plugin 1.0.01.0.0
-rw-r--r--COPYING340
-rw-r--r--HISTORY267
-rw-r--r--LIESMICH.bitte82
-rw-r--r--Makefile122
-rw-r--r--README64
-rw-r--r--config/mpegstill/radio-OnAir1080.mpgbin0 -> 135384 bytes
-rw-r--r--config/mpegstill/radio-Red1080.mpgbin0 -> 109074 bytes
-rw-r--r--config/mpegstill/radio-Tubes1080.mpgbin0 -> 138345 bytes
l---------config/mpegstill/radio.mpg1
l---------config/mpegstill/replay.mpg1
-rw-r--r--config/mpegstill/rtextOben-kleo2-live.mpgbin0 -> 56466 bytes
-rw-r--r--config/mpegstill/rtextOben-kleo2-replay.mpgbin0 -> 56663 bytes
-rw-r--r--config/mpegstill/rtextOben-kleo2.mpgbin0 -> 55885 bytes
-rw-r--r--config/mpegstill/rtextUnten-kleo2-live.mpgbin0 -> 49244 bytes
-rw-r--r--config/mpegstill/rtextUnten-kleo2-replay.mpgbin0 -> 49526 bytes
-rw-r--r--config/mpegstill/rtextUnten-kleo2.mpgbin0 -> 48714 bytes
-rw-r--r--config/scripts/LIESMICH.Scripts62
-rwxr-xr-xconfig/scripts/radioinfo-1093-54127
-rwxr-xr-xconfig/scripts/radioinfo-1093-55131
-rwxr-xr-xconfig/scripts/radioinfo-1093-551.utf830
-rwxr-xr-xconfig/scripts/radioinfo-1093-84125
-rwxr-xr-xconfig/scripts/radioinfo-1093-85126
-rwxr-xr-xconfig/scripts/radioinfo-1113-102426
-rwxr-xr-xconfig/scripts/radioinfo-1113-1024.utf825
-rwxr-xr-xconfig/scripts/radioinfo-1113-103024
-rwxr-xr-xconfig/scripts/radioinfo-1113-103625
-rwxr-xr-xconfig/scripts/radioinfo-1113-1036.utf824
-rwxr-xr-xconfig/scripts/radioinfo-1113-35327
-rwxr-xr-xconfig/scripts/radioinfo-1113-35429
-rwxr-xr-xconfig/scripts/radioinfo-1113-354.utf827
-rwxr-xr-xconfig/scripts/radioinfo-1115-43327
-rwxr-xr-xconfig/scripts/radioinfo-15027-512027
-rwxr-xr-xconfig/scripts/radioinfo-7-30427
-rwxr-xr-xconfig/scripts/radioinfo-7-304.utf826
-rwxr-xr-xconfig/scripts/radioinfo-7-33627
-rwxr-xr-xconfig/scripts/radioinfo-7-35224
-rwxr-xr-xconfig/scripts/radioinfo-8500-21424
-rw-r--r--inforx.c162
-rw-r--r--inforx.h24
-rw-r--r--po/de_DE.po350
-rw-r--r--po/fi_FI.po351
-rw-r--r--po/fr_FR.po350
-rw-r--r--po/hu_HU.po350
-rw-r--r--po/it_IT.po350
-rw-r--r--radio.c731
-rw-r--r--radioaudio.c2806
-rw-r--r--radioaudio.h241
-rw-r--r--radioepg.c370
-rw-r--r--radioepg.h61
-rw-r--r--radioskin.c345
-rw-r--r--radioskin.h69
-rw-r--r--radiotools.c1882
-rw-r--r--radiotools.h29
-rw-r--r--symbols/RTplus_80x80.pngbin0 -> 689 bytes
-rw-r--r--symbols/arec.xpm26
-rw-r--r--symbols/bok.xpm25
-rw-r--r--symbols/index.xpm25
-rw-r--r--symbols/marker.xpm25
-rw-r--r--symbols/no0.xpm25
-rw-r--r--symbols/no1.xpm25
-rw-r--r--symbols/no2.xpm25
-rw-r--r--symbols/no3.xpm25
-rw-r--r--symbols/no4.xpm25
-rw-r--r--symbols/no5.xpm25
-rw-r--r--symbols/no6.xpm25
-rw-r--r--symbols/no7.xpm25
-rw-r--r--symbols/no8.xpm25
-rw-r--r--symbols/no9.xpm25
-rw-r--r--symbols/page1.xpm25
-rw-r--r--symbols/pageE.xpm25
-rw-r--r--symbols/pages2.xpm25
-rw-r--r--symbols/pages3.xpm25
-rw-r--r--symbols/pages4.xpm25
-rw-r--r--symbols/radio.xpm23
-rw-r--r--symbols/rass.xpm25
-rw-r--r--symbols/rds.xpm25
-rw-r--r--symbols/rds_20x80.xpm25
-rw-r--r--symbols/rds_24x95.xpm29
78 files changed, 10541 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..f6aaa5e
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,267 @@
+VDR Plugin 'radio' Revision History
+-----------------------------------
+2013-05-31: Version 1.0.0
+ U.Hanke <egal@gmx.info>
+- Security-patch formatstrings, thanks to Tobias Grimm
+- Update EPG for MusicChoice, thanks to p_body@vdr-portal
+- Add Source-charset
+- some UTF-8 script cleanups
+
+2013-02-10: Version 0.9.1
+ U.Hanke <egal@gmx.info>
+- Makefile,cleanup for vdr >= 1.7.37
+- RT,RT+ osd/list: convert ISO-8859-1 to utf8/locale
+
+2012-04-07: Version 0.9.0
+ U.Hanke <egal@gmx.info>
+- Makefilefix for i18n
+- change/round OSD corners
+- add themes for skin EgalT2
+- seperate thread for mpeg image showing
+- add some themes for Skin Elchi
+- fix fonthandling @ Osd
+- add RDS scanning @ TS-Frames for vdr >= 1.7.x
+- cleanup source, vdr >= 1.6.0 needed
+- fix radioepg.c for glibc-2.10, thanks to zzam@vdr-portal
+- api changes for vdr >= 1.7.26
+
+2009-08-20: Version 0.2.5
+ U.Hanke <egal@gmx.info>
+- fix Rass-Decoding bug: rfu-bytes (old offsetb)
+- add some themes for Skin EnigmaNG
+- quoting filenames for rass-imagesave/ffmpeg
+- change Premiere-/Sky-RadioTransponderID to 17
+- add cAudio::PlayTs() to compile with vdr-1.7.x (TS-scanning to be done)
+- checking only vdr-recordings (existing /recordingpath/001.vdr)
+- add italien-translation text, thanks to Diego Pierotto
+
+2007-10-09: Version 0.2.4
+ U.Hanke <egal@gmx.info>
+- new transponder (TID) for premiere radio-channels (+ epg fixed)
+- create/checks temp. data-dir /tmp/vdr-radio.xxxxxx if not specified,
+ thanks to Tobias Grimm & Thomas Günther
+- cleanup for gcc-4.2.1 (some const char*)
+- debug print cleanups -> dsyslog
+- update for RT+Specification 2.1, RT+Classes changed
+- some scripts added
+- add french-translation text, thanks to Patrice Staudt
+
+2007-09-14: Version 0.2.3
+ U.Hanke <egal@gmx.info>
+- additional entity- & xhtml-unicode-dezimal conversion
+- OSD-Info for Radiochannels on Unity Media Kabel: Song, Artist+Album,
+ thanks to gmewes@vdr-portal for testing & screenshots
+- add french-translation text, thanks to pat@vdr-portal
+- Additional songinfos now about external scripts/programs (like www-requests),
+ see ./config/scripts/LIESMICH.Scripts for details
+- changes for vdr >= 1.5.8 (locales)
+- Fix Makefile for all shells (== :unexpected operator), thanks to Matthias Schwarzott
+
+2007-08-14: Version 0.2.2
+ U.Hanke <egal@gmx.info>
+- changes for vdr >= 1.5.7 (locales: ../po, make i18n, aso)
+- Transfermode for encrypted radio channels over command-option -e 1/--encrypted=1,
+ without Transfermode no background-image + no birate-item
+- Auto-OSD called now @ background-thread, no more transfermode need for OSD
+- OSD-Info for Radiochannels on Kabel Deutschland: Song, Artist, Album, Comp.,
+ thanks to CafeDelMar@vdr-portal for testing & screenshots
+- Workaround osdbugfixing 1.Textrow @ setup wihout titlerow
+- StatusEvents for epg-info added
+- Timefixing on epg-events (premiere)
+
+2007-08-03: Version 0.2.1
+ U.Hanke <egal@gmx.info>
+- OSD-Info for Premiere-Radio from EPG-PresentEvent:
+ Interpret, Titel/Werk, Album/Komponist, Jahr
+- UseStillPicture-Device about Setup (disable for softdevice/dxr3)
+- OSD-Info for RockAntenne about InetRequest (Setup-Option),
+ code 'rockantenne.h/rockantenne.c' taken from
+ rockantenne-plugin, thanks to Author Frank Bergmann
+- align OSD-Title/Artist, freetype-fonts in vdr >= 1.5.3
+- first implementation of tmc-parser Alert-C coding
+ (start with --verbose=32 or greater and watch console-output)
+- some changes like RDS-ODA IDs for RT+ & TMC_Alert-C
+- add hungarian-translation text, thanks to Füley István
+- add Skin-Themes: Soppalusikka-Blackberry/Citron,
+ Enigma-WineRed/AppleGreen/WomansLike/YellowSun,
+ Elchi_Plugin, EgalsTry~default/~blue
+- <radio top40> sends RDS @ audio-stream, seperate PID cancled
+- add RaSS-Gallery over OK button,
+ add RaSS-Image saving as jpeg with installed ffmpeg,
+ add RaSS-OSD keys for gallery, navigation, images
+- add audio-bitrate to osd, taken from mpegheader
+- changes for vdr >= 1.5.0
+- fix valgrind suggestion, thanks to Hulk@vdr-portal for providing the patch
+- add french-translation text, thanks to pat@vdr-portal
+- add finnisch-translation text, thanks to Rolf Ahrenberg
+
+2006-12-31: Version 0.2.0
+ U.Hanke <egal@gmx.info>
+- Add RaSS-Implementation 'RadioScreenShow' (workingname QDAr),
+ slideshow with mpeg-stills as backgroundimage & save datafiles,
+ archiv with OSD & Navigation
+- Bugfix: now stopping correct rds-receiver on multiple tunerdevices,
+ thanks to Reinhard Nißl
+
+2006-08-14: Version 0.1.4
+ U.Hanke <egal@gmx.info>
+- add seperate RDS-Receiver for Data-PIDs,
+ on channels like Radio-FFH & co.
+- RDS PS added, text in osd, if no RTplus available
+- RDS PTYN added, shown if no PTY received
+
+2006-07-19: Version 0.1.3
+ U.Hanke <egal@gmx.info>
+- add Service/OSD-Symbol from audiorecorder for title-recording
+- exchange localtime() with thread-safe localtime_r()
+- add french-translation text, thanks to Michaël Nival
+
+2006-04-27: Version 0.1.2
+ U.Hanke <egal@gmx.info>
+- Bugfix in fopen for DataDir-files, thanks to Thomas Günther
+- New command-options --live/--replay = mpegfile for default-mpegs @ live-/replaymode,
+ (mpegfile as absolute incl. Path), suggested by Tobias Grimm
+- Add -fPIC to compiler-flags, thanks to Tobias Grimm
+
+- OSD-Timeout reactivated
+- cPlugin::Active/cPlugin::MainThreadHook only if vdr >= 1.3.47 for better compatibility with patched vdr
+- New svdrp-command 'RTTCLOSE' for temporarily closing OSD (2*Osd-Messagetimeout)
+
+2006-04-19: Version 0.1.0
+ U.Hanke <egal@gmx.info>
+- Changes for vdr >= 1.3.47
+- RDS-logo in osd added, ../symbols/rds.xpm can also be used in skin-menus
+- StatusMsg for lcdproc&co independent from osd
+- New command-option --data=dir for temp. datafiles
+- Reorg plugin-call for automatic-osd
+- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg
+- Changes for vdr >= 1.3.45
+- Add skincolors for Radiotext-OSD, see setup-option 'Skincolor used'
+- Add crc16 check (CCITT) for rds + qdar-files
+- Makefile-Defines for vdr-patches
+- RTplus-Memory with seperate OSDs added
+- detecting radio in file @ replaymode,
+ thanks to Reinhard Nißl for providing the patch
+- cleanup code, vdr < 1.3.43 no longer supported
+- no more own tansferthread -> changing to audiothread,
+ radiotext @ replaymode now possible,
+ better handling of transfer-start,
+ thanks to Reinhard Nißl for providing all the patches
+
+2006-01-09: Version 0.0.9
+ U.Hanke <egal@gmx.info>
+- RDS-PTY OSD changed & no radio-action on Data/Service-channels,
+ thanks to Walter Koch for providing the patch
+- Bugfix: Title-Starttime @ radiotext-service & StatusMsg (lcdproc&co.)
+- Update/Changing to RTplus Version 2.0 (now we have titleend with item-runningbit ;)
+
+2005-11-02: Version 0.0.8e
+ U.Hanke <egal@gmx.info>
+- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg
+- RText: PlusTag ends, if 2x taglen=0, new seen @ 'Eins Live/Bremen Vier/SWR3',
+ PlusTag changing also without togglebit (seen on 'Bremen Vier'),
+ PlusTag change entitystr to corresponding char ("&apos;" -> "'" a.s.o)
+
+2005-10-12: Version 0.0.8d
+ U.Hanke <egal@gmx.info>
+- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg
+- Fix for displaying the bg-image, thanks to Joachim Wilke for providing the patch
+- RText: cStatus::MsgOsdProgramme/ItemText added (incl. setup) for lcdproc and other
+ display-plugins, thanks to Joachim Wilke for providing the initial-patch,
+- RText: length-checking not strict '==', station NDR* sends false MEL
+- RText: PlusTag-startmarker now beginning with '0' (only WDR sends it correct now)
+
+2005-09-12: Version 0.0.8c
+ U.Hanke <egal@gmx.info>
+- Bugfix: closing own plugin-OSD on channelswitch by CHAN+/- or svdrp
+- Background-checking, if radio-channels get video-Pid (new/temp.), suggested by Rolf Ahrenberg
+- Changes for vdr >= 1.3.32, no more UserMacroKey needed for AutoOsd
+- New extern svdrp-commands > plug radio 'RTINFO' and 'RTCLOSE' (vdr >= 1.3.31):
+ > RTINFO
+ > Print the radiotext information.
+ > RTCLOSE
+ > Close the radiotext-osd.
+ > Reopen can only be done over menu or channelswitch.
+
+2005-09-10: Version 0.0.8a/b
+ U.Hanke <egal@gmx.info>
+- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg
+- Bugfix: close RText-OSD at channelswitch (svdrp), if no radio-channel
+- AutoOSD: no UserKey after player-end with <Back-Key>,
+ no more closing other plugin-osds
+
+2005-09-09: Version 0.0.8
+ U.Hanke <egal@gmx.info>
+- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg
+- Delayed OSD-redisplay after menus
+- New OSD-timeout, timerval about setup (0=No, 1-1440 min.)
+- Check textrepeatings in all OSD-Rows
+
+2005-08-31: Version 0.0.7f
+ U.Hanke <egal@gmx.info>
+- RDS-PTY added, thanks to Walter Koch for providing the patch
+- RDSText-Check @ pes audio-frames instead of ts-frames on vdr >= 1.3.31
+- Update ID "RadioTextService-1.0" service-call for other plugins:
+ struct RadioTextService_v1_0 {
+ int rds_info; // 0= No / 1= Text / 2= Text + RTplus-Tags (Item,Artist)
+ int rds_pty; // 0-31, Source http://www.ebu.ch/trev_255-beale.pdf for values
+ char *rds_text;
+ char *rds_title; // "---" if none @ moment
+ char *rds_artist; // "---" if none @ moment
+ struct tm *title_start;
+ };
+- Some modifications on RTplus-tags errors
+
+2005-08-27: Version 0.0.7e
+ U.Hanke <egal@gmx.info>
+- Bugfix: prevent keys Channel+/- to switch twice @ AutoOsd
+- Add char-translation 'additional display characters' for radiotext (see RBDS-Standard for more info)
+
+2005-08-24: Version 0.0.7d
+ U.Hanke <egal@gmx.info>
+- Update finnisch-translation text, thanks to Rolf Ahrenberg
+- RDS-Text: ignore textline-doublettes for OSD,
+- Add ID "RadioTextService-1.0" service-call for other plugins:
+ struct RadioTextService_v1_0 {
+ int rds_info; // 0= No / 1= Text / 2= Text + RTplus-Tags (Item,Artist)
+ char *rds_text;
+ char *rds_title;
+ char *rds_artist;
+ struct tm *title_start;
+ };
+ See vdr-1.3.30 for more info about 'cPluginName::Service' or
+ demo-plugin 'rtextdemo' on console-output, how it works
+
+2005-08-21: Version 0.0.7c
+ U.Hanke <egal@gmx.info>
+- Additional finnisch-translation text, thanks to Rolf Ahrenberg
+- RDS-Text: new osd-options 'OSD-Titlerow, OSD-Scrollmode, OSD-Taginfo',
+ itemtag-end about (no)repeating & min-timer,
+ rdstextcheck-revision since ARD-Radiotransponder sends (20050819)
+- Update transfermode (cThread::Running()), see vdr-1.3.29 for details
+
+2005-08-05: Version 0.0.7b
+ U.Hanke <egal@gmx.info>
+- Finnisch-translation text, thanks to Rolf Ahrenberg
+- Commandline-option verboselevel for testing
+- RTplus tags (Title/Artist) added, OSD-Option for RTplus tags
+- Radiotextcheck optimized (TS-Header, bytestuffing + co.)
+
+2005-07-31: Version 0.0.7a
+ U.Hanke <egal@gmx.info>
+- cleanup code, vdr<1.3.22 no longer supported
+- RDS-Radiotext added, show about Mainmenuentry or Automatic
+- Div. Setup-Options for radio/RDS-Radiotext
+- Internationalization added,
+- All AudioTracks now possible
+
+2005-03-19: Version 0.0.6
+- F.PECOURT:
+ modified functions calls for new Audio IDs and
+ radiotransfer for vdr 1.3.22. First dirty hacks
+ still one problem: blank image when switching
+ from one radio to an other. Clear missing!
+
+2004-11-10: Version 0.0.1
+
+- Initial revision.
diff --git a/LIESMICH.bitte b/LIESMICH.bitte
new file mode 100644
index 0000000..150f3ce
--- /dev/null
+++ b/LIESMICH.bitte
@@ -0,0 +1,82 @@
+Plugin radio for vdr >= 1.7.37
+
+MPEG-Standbilder als Beispiele beigefügt (siehe SubDir ../config/mpgestill),
+(überarbeitete Vorlage von kleo @ vdrportal);
+zur Benutzung kopiere/installiere nach $VDRCONFIG/plugins/radio (-f <DIR>).
+
+Externe Scriptabfragen für Titel/Interpret-Infos unter ../config/scripts),
+(für Funktion/Aufbau siehe ../config/scripts/LIESMICH.Scripts);
+zur Benutzung kopiere/installiere nach $VDRCONFIG/plugins/radio (-f <DIR>).
+
+
+----------------------------
+Grundsätzlich zur Bedienung:
+----------------------------
+Wenn im OSD entweder der Radiotext/Info oder der RaSS-Archivhinweis aktiv ist,
+kann mit der Taste 'Zurück' das OSD getoggelt werden, soll heißen:
+RaSS-Hinweis/Radiotext -> kein OSD -> RaSS-Hinweis/Radiotext usw.
+
+-----------------------------
+Bedienung/Tasten RTplus-Menu:
+-----------------------------
+Wenn im OSD der Radiotext/Info zu sehen ist, kann mit der Taste '0'
+das zusätzliche RTplus-Menu + evtl. weitere aufgerufen werden.
+Die Übersicht wird automatisch alle 60 Sekunden aktualisiert;
+evtl. Untermenus ca. alle 20s, wenn aktiviert.
+
+Tasten in den Menus:
+ 0 = Aktualisieren
+ OK/Zurück = Schließen
+ 8 = RTplus-Infos speichern (nur im 1.Menu)
+
+-----------------------------
+Bedienung/Tasten RaSS-Archiv:
+-----------------------------
+Wenn im OSD der Hinweis 'Archiv verfügbar' zu sehen ist, kann mit der Taste '0'
+das zusätzliche RaSS-Archiv aufgerufen werden.
+
+Auf der linken Seite erscheint das Archiv-Menu mit den Bedienungstasten 0-9/OK,
+dabei bedeuten folgende Symbole:
+
+ |=| = Seiten vorhanden (0-9)
+ | | xx = Gallery, xx Anzahl Bilder (OK)
+ > = Standort
+
+Folgende zusätzliche Tasten stehen zur Verfügung:
+
+ Auf/Ab = Scrollen innerhalb Archivmenu (0-9/OK)
+ Links/Rechts = Scrollen innerhalb der Subseiten/Gallery
+ Rot = Speichert angezeigte Seite als JPEG-Bild (1024x576)
+ Grün = Speichert alle Subseiten/Gallery als JPEG-Bilder (1024x576),
+ - Seitenname = RaSS_Sendername-Seitennr_MonatTagStundeMinute.jpg
+ - Gallerynamen = RaSS_Sendername-GallerySeitennr_MonatTag.jpg
+ Gelb = todo, was ?
+ Blau/Exit = Archiv verlassen
+
+Alle anderen Tasten schließen das RaSS-Archiv ebenso.
+
+Hinweis: Die JPEG-Speicherung/Wandlung erfolgt nur, wenn auf dem System
+ das Programm 'ffmpeg' installiert ist.
+
+
+--------------
+SVDRP-Befehle:
+--------------
+ RTINFO = Ausgabe der Radiotext Information
+ RTCLOSE = Radiotext-OSD schließen. Erneutes Öffnen nur über Menü oder Kanalwechsel
+ RTTCLOSE = Radiotext-OSD zeitweise schließen. Wiederöffnen automatisch nach OSD-Timeout
+
+----------------
+Ausrufparameter:
+----------------
+ -f <DIR> --files=<DIR> Bilderverzeichnis (Standard: $VDRCONFIG/plugins/radio)
+ -d <DIR> --data=<DIR> Datenverzeichnis temporär (Standard: /tmp/vdr-radio.XXXXXX)
+ -l <DATEI> --live=<DATEI> benutze <DATEI> im Livemodus (Standard: $VDRCONFIG/plugins/radio/radio.mpg)
+ -r <DATEI> --replay=<DATE> benutze <DATEI> im Wiedergabemodus (Standard: $VDRCONFIG/plugins/radio/replay.mpg)
+ -e 1 --encrypted=1 benutze Transfermode auch bei verschlüsselten Sendern
+ -v <LEVEL> --verbose=<LEVEL> Console-Printouts: 0 keine Meldungen, 1 RDS-Text+Tags (Voreinstellung), 2 +RDS-Telegram/Debug,
+ 3 +RawData 0xfd, |=16 Rass-Info, |=32 TMC-Info
+
+
+Viel Spaß...
+Uwe <egal at egal-vdr dot de>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5a14a28
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,122 @@
+#
+# 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 = radio
+
+### 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 directory environment:
+
+# Use package data if installed...otherwise assume we're under the VDR source directory:
+PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
+LIBDIR = $(call PKGCFG,libdir)
+LOCDIR = $(call PKGCFG,locdir)
+PLGCFG = $(call PKGCFG,plgcfg)
+#
+TMPDIR ?= /tmp
+
+### The compiler options:
+
+export CFLAGS = $(call PKGCFG,cflags)
+export CXXFLAGS = $(call PKGCFG,cxxflags)
+
+### The version number of VDR's plugin API:
+
+APIVERSION = $(call PKGCFG,apiversion)
+
+### Allow user defined options to overwrite defaults:
+
+-include $(PLGCFG)
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### The name of the shared object file:
+
+SOFILE = libvdr-$(PLUGIN).so
+
+### Includes and Defines (add further entries here):
+
+INCLUDES +=
+
+DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o radioaudio.o radioskin.o radiotools.o radioepg.o inforx.o
+
+### The main target:
+
+all: $(SOFILE) i18n
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Internationalization (I18N):
+
+PODIR = po
+I18Npo = $(wildcard $(PODIR)/*.po)
+I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file))))
+I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file))))))
+I18Npot = $(PODIR)/$(PLUGIN).pot
+
+%.mo: %.po
+ msgfmt -c -o $@ $<
+
+$(I18Npot): $(wildcard *.c)
+ xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+
+%.po: $(I18Npot)
+ msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @touch $@
+
+$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+ install -D -m644 $< $@
+
+.PHONY: i18n
+i18n: $(I18Nmo) $(I18Npot)
+
+install-i18n: $(I18Nmsgs)
+
+### Targets:
+
+$(SOFILE): $(OBJS)
+ $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+
+install-lib: $(SOFILE)
+ install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
+
+install: install-lib install-i18n
+
+dist: $(I18Npo) 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 $(PODIR)/*.mo $(PODIR)/*.pot
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
diff --git a/README b/README
new file mode 100644
index 0000000..22a4af1
--- /dev/null
+++ b/README
@@ -0,0 +1,64 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Lars Tegeler <email@host.dom>,
+ Uwe Hanke <egal@egal-vdr.de>
+
+Project's homepage: www.math.uni-paderborn.de/~tegeler/vdr
+ www.egal-vdr.de/plugins
+
+Latest version available at: www.egal-vdr.de/plugins
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+The complete text of the GNU General Public License can be found
+in /usr/share/common-licenses/GPL on most Debian systems.
+
+
+Description:
+
+This plugin display an background image while the vdr is switcht to radio channels.
+Additionally it decode & show RDS (RadioDataSystem) information in the audiostream
+(RDS UECP) like Radiotext(Plus) and Rass (RadioScreenShow).
+Finally it receive & show external infos (scripts/programs) about title/interpret,
+f.e. parsing websites of radiostations.
+
+
+Install:
+
+1. Extract and copy the plugin:
+ cd /yourpath/VDR/PLUGINS/src
+ tar -xzf /yourpath/vdr-radio-x.y.z.tgz
+
+2. Make a link in /here is your vdr/PLUGINS/src:
+ ln -s radio-x.y.z radio
+
+3. cd /yourpath/VDR
+ make
+ make plugins
+
+4. Copy your background images to /yourpath/vdr/CONFIG/plugins/radio
+ (Default radio.mpg will be used or if exist <channelname>.mpg )
+ Yeah, must be .mpg!
+
+4.1 If you dont wont to use the default directory you can use the -f option
+ to set an other one.
+
+5. Start your VDR with the option:
+ -P radio
+
+6. Have Fun!
+
+
+For additional info/description see LIESMICH.bitte
diff --git a/config/mpegstill/radio-OnAir1080.mpg b/config/mpegstill/radio-OnAir1080.mpg
new file mode 100644
index 0000000..8fa6112
--- /dev/null
+++ b/config/mpegstill/radio-OnAir1080.mpg
Binary files differ
diff --git a/config/mpegstill/radio-Red1080.mpg b/config/mpegstill/radio-Red1080.mpg
new file mode 100644
index 0000000..03f0162
--- /dev/null
+++ b/config/mpegstill/radio-Red1080.mpg
Binary files differ
diff --git a/config/mpegstill/radio-Tubes1080.mpg b/config/mpegstill/radio-Tubes1080.mpg
new file mode 100644
index 0000000..e65cf16
--- /dev/null
+++ b/config/mpegstill/radio-Tubes1080.mpg
Binary files differ
diff --git a/config/mpegstill/radio.mpg b/config/mpegstill/radio.mpg
new file mode 120000
index 0000000..a9a53d4
--- /dev/null
+++ b/config/mpegstill/radio.mpg
@@ -0,0 +1 @@
+radio-Tubes1080.mpg \ No newline at end of file
diff --git a/config/mpegstill/replay.mpg b/config/mpegstill/replay.mpg
new file mode 120000
index 0000000..b16393c
--- /dev/null
+++ b/config/mpegstill/replay.mpg
@@ -0,0 +1 @@
+rtextUnten-kleo2-replay.mpg \ No newline at end of file
diff --git a/config/mpegstill/rtextOben-kleo2-live.mpg b/config/mpegstill/rtextOben-kleo2-live.mpg
new file mode 100644
index 0000000..d60782c
--- /dev/null
+++ b/config/mpegstill/rtextOben-kleo2-live.mpg
Binary files differ
diff --git a/config/mpegstill/rtextOben-kleo2-replay.mpg b/config/mpegstill/rtextOben-kleo2-replay.mpg
new file mode 100644
index 0000000..976483c
--- /dev/null
+++ b/config/mpegstill/rtextOben-kleo2-replay.mpg
Binary files differ
diff --git a/config/mpegstill/rtextOben-kleo2.mpg b/config/mpegstill/rtextOben-kleo2.mpg
new file mode 100644
index 0000000..f310bc4
--- /dev/null
+++ b/config/mpegstill/rtextOben-kleo2.mpg
Binary files differ
diff --git a/config/mpegstill/rtextUnten-kleo2-live.mpg b/config/mpegstill/rtextUnten-kleo2-live.mpg
new file mode 100644
index 0000000..c63f214
--- /dev/null
+++ b/config/mpegstill/rtextUnten-kleo2-live.mpg
Binary files differ
diff --git a/config/mpegstill/rtextUnten-kleo2-replay.mpg b/config/mpegstill/rtextUnten-kleo2-replay.mpg
new file mode 100644
index 0000000..5ff4b40
--- /dev/null
+++ b/config/mpegstill/rtextUnten-kleo2-replay.mpg
Binary files differ
diff --git a/config/mpegstill/rtextUnten-kleo2.mpg b/config/mpegstill/rtextUnten-kleo2.mpg
new file mode 100644
index 0000000..5a62613
--- /dev/null
+++ b/config/mpegstill/rtextUnten-kleo2.mpg
Binary files differ
diff --git a/config/scripts/LIESMICH.Scripts b/config/scripts/LIESMICH.Scripts
new file mode 100644
index 0000000..8038518
--- /dev/null
+++ b/config/scripts/LIESMICH.Scripts
@@ -0,0 +1,62 @@
+vdr-radio plugin: externe script-files
+--------------------------------------
+
+Externe Script- oder Programm-Files haben die Funktion, falls im plugin-Setup
+aktiviert (Externe Info-Abfrage = ja), fehlende Songinfos über externe Quellen
+wie Internetabfragen zu holen.
+
+Das Script/Programm muß hierfür im Plugin-Config-Verzeichnis existieren
+($VDRCONFIG/plugins/radio, beachte auch plugin-Startparameter '-f <DIR>'),
+für den vdr ausführbar sein und die folgende Namenssyntax aufweisen:
+
+ radioinfo-TID-APID
+ (wobei TID = channel-TID, APID = 1.AudioPid entspr. der vdr channels.conf)
+
+Das Script/Programm wird dann mit 1 Parameter = Dateiname Ausgabedatei im
+Datenverzeichnis ($VDRCONFIG/plugins/radio, beachte auch plugin-Parameter -d <DIR>)
+aufgerufen; die Ausgabedatei soll dann Textzeilen im folgendem Format enthalten:
+
+ 1.Zeile = Senderkennung
+ 2.Zeile = Interpret
+ 3.Zeile = Titel
+
+Wenn die Sender zeitweise keine Songinfos anzeigen (z.B. Fritz) sollte
+Interpret und/oder Titel solange mit z.B. "---" gesetzt werden, da sonst
+bei leeren Informationen ein "Error, no Songinfo" im OSD angezeigt wird.
+
+
+Folgende Script-Beispiele (www-Abfragen) werden mitgeliefert
+(die Programme bash/wget/grep sowie teilw. tail/tac/iconv werden benötigt):
+
+ [Astra 19.2]
+ - Rockantenne = radioinfo-7-304
+ - sunshine live = radioinfo-7-336
+ - Antenne Bayern = radioinfo-7-352
+ - radio top40 = radioinfo-1113-353
+ - ffn digital = radioinfo-1113-354
+ - Hit Radio FFH = radioinfo-1113-1024
+ - planet radio = radioinfo-1113-1030
+ - harmony.fm = radioinfo-1113-1036
+ - oe3 orf = radioinfo-1115-433
+ - Truckradio = radioinfo-1115-442
+ - MDR Jump = radioinfo-1093-541
+ - SPUTNIK = radioinfo-1093-551
+ - radioeins = radioinfo-1093-841
+ - Fritz = radioinfo-1093-851
+ [Hotbird 13.0]
+ - SRG-DRS 1 = radioinfo-8500-211
+ - SRG-DRS 2 = radioinfo-8500-212
+ - SRG-DRS 3 = radioinfo-8500-213
+ - SRG-DRS Virus = radioinfo-8500-214
+ - Radio Swiss Classic = radioinfo-8500-224
+ - Radio Swiss Pop = radioinfo-8500-225
+ - Radio Swiss Jazz = radioinfo-8500-226
+ [Astra 23.5]
+ - Truckradio = radioinfo-15027-5120
+
+
+Weitere erfolgreich getestete Scripte werden gerne übernommen :-)
+
+
+Viel Spaß...
+Uwe <egal at egal-vdr dot de>
diff --git a/config/scripts/radioinfo-1093-541 b/config/scripts/radioinfo-1093-541
new file mode 100755
index 0000000..bbac81c
--- /dev/null
+++ b/config/scripts/radioinfo-1093-541
@@ -0,0 +1,27 @@
+#!/bin/bash
+# MDR Jump-Playlist
+# $1 = outfile
+
+### Variabel
+Name="MDR Jump [www.jumpradio.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.jumpradio.de/scripts/musik/wsx_vote_recher.cfm?&titelsuche=zeit"
+
+# Artist/Title
+artist=`grep -B30 '<h2>Suche nach Datum und Uhrzeit' /tmp/playlist | tac`
+artist=${artist/*$'">'/}; artist=${artist/$'<'\/'h2>'*/}
+title=`grep -B29 '<h2>Suche nach Datum und Uhrzeit' /tmp/playlist | tac`
+title=${title/*$'">"'/}; title=${title/$'"<'\/'p>'*/}
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1093-551 b/config/scripts/radioinfo-1093-551
new file mode 100755
index 0000000..5fbbde2
--- /dev/null
+++ b/config/scripts/radioinfo-1093-551
@@ -0,0 +1,31 @@
+#!/bin/bash
+# SPUTNIK-Playlist
+# $1 = outfile
+
+### Variabel
+Name="SPUTNIK [www.sputnik.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.sputnik.de"
+iconv -s -c -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist
+
+# Artist/Title
+present=`grep -A7 'class="current_song"' /tmp/playlist | grep -c 'nicht zu ermitteln'`
+if [ $present = 0 ]; then
+ artist=`grep -A7 'class="current_song"*' /tmp/playlist`
+ artist=${artist/*$'"name">'/}; artist=${artist/$'<'\/'p>'*/}
+ title=`grep -A8 'class="current_song"*' /tmp/playlist`
+ title=${title/*$'"title">'/}; title=${title/$'<'\/'p>'*/}
+fi
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1093-551.utf8 b/config/scripts/radioinfo-1093-551.utf8
new file mode 100755
index 0000000..420685b
--- /dev/null
+++ b/config/scripts/radioinfo-1093-551.utf8
@@ -0,0 +1,30 @@
+#!/bin/bash
+# SPUTNIK-Playlist
+# $1 = outfile
+
+### Variabel
+Name="SPUTNIK [www.sputnik.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.sputnik.de"
+
+# Artist/Title
+present=`grep -A7 'class="current_song"' /tmp/playlist | grep -c 'nicht zu ermitteln'`
+if [ $present = 0 ]; then
+ artist=`grep -A7 'class="current_song"*' /tmp/playlist`
+ artist=${artist/*$'"name">'/}; artist=${artist/$'<'\/'p>'*/}
+ title=`grep -A8 'class="current_song"*' /tmp/playlist`
+ title=${title/*$'"title">'/}; title=${title/$'<'\/'p>'*/}
+fi
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1093-841 b/config/scripts/radioinfo-1093-841
new file mode 100755
index 0000000..6f0b9a0
--- /dev/null
+++ b/config/scripts/radioinfo-1093-841
@@ -0,0 +1,25 @@
+#!/bin/bash
+# radioeins-Playlist
+# $1 = outfile
+
+### Variabel
+Name="radioeins [radioeins.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://radioeins.funtip.de/playList.do"
+
+# Artist/Title
+artist=`grep -A17 'summary="Liste der radioeins Musiktitel"*' /tmp/playlist`
+artist=${artist/*$'<td>'/}; artist=${artist/$'<'\/'td>'*/}
+title=`grep -A18 'summary="Liste der radioeins Musiktitel"*' /tmp/playlist`
+title=${title/*$'<td>'/}; title=${title/$'<'\/'td>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1093-851 b/config/scripts/radioinfo-1093-851
new file mode 100755
index 0000000..0b74297
--- /dev/null
+++ b/config/scripts/radioinfo-1093-851
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Fritz-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Fritz [www.fritz.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.fritz.de/ds/ds.html"
+
+# Artist/Title
+all=`grep -A0 'on air Titel:' /tmp/playlist`
+artist=${all/*$'<span class='\"'titelanzeige'\"'>'/}; artist=${artist/$' - '*/}
+title=${all//*$' - '/}; title=${title/$'<'\/'span>'*/}
+# temp. no Info
+artist=${artist:='...'}; titel=${title:='...'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-1024 b/config/scripts/radioinfo-1113-1024
new file mode 100755
index 0000000..52e4b0f
--- /dev/null
+++ b/config/scripts/radioinfo-1113-1024
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Hit Radio FFH-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Hit Radio FFH [www.ffh.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.ffh.de/webradio/hitfinder_index.php"
+iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist
+
+# Artist/Title
+artist=`grep -A15 '>Datum/Zeit<*' /tmp/playlist`
+artist=${artist//*$'<td>'/}; artist=${artist//$'<'\/'td>'*/}
+title=`grep -A14 '>Datum/Zeit<*' /tmp/playlist`
+title=${title//*$'<td>'/}; title=${title//$'<'\/'td>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-1024.utf8 b/config/scripts/radioinfo-1113-1024.utf8
new file mode 100755
index 0000000..6a7c2b6
--- /dev/null
+++ b/config/scripts/radioinfo-1113-1024.utf8
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Hit Radio FFH-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Hit Radio FFH [www.ffh.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.ffh.de/webradio/hitfinder_index.php"
+
+# Artist/Title
+artist=`grep -A15 '>Datum/Zeit<*' /tmp/playlist`
+artist=${artist//*$'<td>'/}; artist=${artist//$'<'\/'td>'*/}
+title=`grep -A14 '>Datum/Zeit<*' /tmp/playlist`
+title=${title//*$'<td>'/}; title=${title//$'<'\/'td>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-1030 b/config/scripts/radioinfo-1113-1030
new file mode 100755
index 0000000..25e5de5
--- /dev/null
+++ b/config/scripts/radioinfo-1113-1030
@@ -0,0 +1,24 @@
+#!/bin/bash
+# PlanetRadio-Playlist
+# $1 = outfile
+
+### Variabel
+Name="planet radio [www.planetradio.de]"
+###
+
+# get...
+wget -q --tries=1 --timeout=10 -O /tmp/playlist "http://www.planetradio.de/p_mt.php"
+
+# Artist/Title
+all=`grep -A1 'die letzten 3 tracks' /tmp/playlist`
+title=${all/*$'<table><tr><td>'????????????????????/}; title=${title/$'<'\/'td>'*/}
+artist=${all//*$'td><td>'/}; artist=${artist/$'<'\/'td>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-1036 b/config/scripts/radioinfo-1113-1036
new file mode 100755
index 0000000..d58eccd
--- /dev/null
+++ b/config/scripts/radioinfo-1113-1036
@@ -0,0 +1,25 @@
+#!/bin/bash
+# harmony.fm-Playlist
+# $1 = outfile
+
+### Variabel
+Name="harmony.fm [www.harmonyfm.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.harmonyfm.de/index.php"
+iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist
+
+# Artist/Title
+all=`grep -A6 'id="channelOnAir"' /tmp/playlist`
+artist=${all//*$'<p>'/}; artist=${artist/$' mit '*/}
+title=${all//*$' mit '/}; title=${title/$'<'\/'p>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-1036.utf8 b/config/scripts/radioinfo-1113-1036.utf8
new file mode 100755
index 0000000..20a81ac
--- /dev/null
+++ b/config/scripts/radioinfo-1113-1036.utf8
@@ -0,0 +1,24 @@
+#!/bin/bash
+# harmony.fm-Playlist
+# $1 = outfile
+
+### Variabel
+Name="harmony.fm [www.harmonyfm.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.harmonyfm.de/index.php"
+
+# Artist/Title
+all=`grep -A6 'id="channelOnAir"' /tmp/playlist`
+artist=${all//*$'<p>'/}; artist=${artist/$' mit '*/}
+title=${all//*$' mit '/}; title=${title/$'<'\/'p>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-353 b/config/scripts/radioinfo-1113-353
new file mode 100755
index 0000000..7957b1e
--- /dev/null
+++ b/config/scripts/radioinfo-1113-353
@@ -0,0 +1,27 @@
+#!/bin/bash
+# radio top40-Playlist
+# $1 = outfile
+
+### Variabel
+Name="radio top40 [www.radiotop40.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.radiotop40.de/titel.php"
+
+# Artist/Title
+artist=`grep -A6 '<body' /tmp/playlist`
+artist=${artist/*$'">'/}; artist=${artist/$' - '*/}
+title=`grep -A6 '<body' /tmp/playlist`
+title=${title/*$' - '/}; title=${title/$'<'\/'td>'*/}
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-354 b/config/scripts/radioinfo-1113-354
new file mode 100755
index 0000000..068aeeb
--- /dev/null
+++ b/config/scripts/radioinfo-1113-354
@@ -0,0 +1,29 @@
+#!/bin/bash
+# ffn digital-Playlist
+# $1 = outfile
+
+### Variabel
+Name="ffn digital [www.ffn.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.ffn.de/musik/playlist.html"
+iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist
+
+# grep actual song
+all=`grep -A6 'wird gerade gespielt' /tmp/playlist`
+
+# Artist/Title
+artist=${all//*$'"artist">'/}; artist=${artist//$'</h3>'*/}
+title=${all//*$'"title">'/}; title=${title//$'</h3>'*/}
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1113-354.utf8 b/config/scripts/radioinfo-1113-354.utf8
new file mode 100755
index 0000000..00a214b
--- /dev/null
+++ b/config/scripts/radioinfo-1113-354.utf8
@@ -0,0 +1,27 @@
+#!/bin/bash
+# ffn digital-Playlist
+# $1 = outfile
+
+### Variabel
+Name="ffn digital [www.ffn.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.ffn.de/musik/playlist.html"
+# grep actual song
+all=`grep -A6 'wird gerade gespielt' /tmp/playlist`
+
+# Artist/Title
+artist=${all//*$'"artist">'/}; artist=${artist//$'</h3>'*/}
+title=${all//*$'"title">'/}; title=${title//$'</h3>'*/}
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-1115-433 b/config/scripts/radioinfo-1115-433
new file mode 100755
index 0000000..952cd51
--- /dev/null
+++ b/config/scripts/radioinfo-1115-433
@@ -0,0 +1,27 @@
+#!/bin/bash
+# OE3-Playlist
+# $1 = outfile
+
+### Variabel
+Name="OE3 [oe3.ORF.at]"
+###
+
+# get...
+wget -q --tries=1 --timeout=10 -O /tmp/playlist "http://solutions.orf.at/orf/hitservice/index.cgi?view=tracklist"
+
+# Artist/Title
+title=`grep -A2 'class="playlisttop"' /tmp/playlist`
+title=${title/*$'<b>'/}; title=${title/$'<'\/'b>'*/}
+artist=`grep -A4 'class="playlisttop"' /tmp/playlist`
+artist=${artist/*$' '/}
+# temp. no Info
+artist=${artist:='...'}; titel=${title:='...'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-15027-5120 b/config/scripts/radioinfo-15027-5120
new file mode 100755
index 0000000..bac3bb2
--- /dev/null
+++ b/config/scripts/radioinfo-15027-5120
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Truckradio-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Truckradio [truckradio.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://truckradio.de/truckradio.php"
+
+# Artist/Title
+artist=`grep -A1 '>Was l&auml;uft gerade:' /tmp/playlist`
+artist=${artist/*$'<strong>'/}; artist=${artist/$'<BR>'*/}
+title=`grep -A1 '>Was l&auml;uft gerade:' /tmp/playlist`
+title=${title/*$'<BR>'/}; title=${title/$'<'\/'strong>'*/}
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-7-304 b/config/scripts/radioinfo-7-304
new file mode 100755
index 0000000..db123ae
--- /dev/null
+++ b/config/scripts/radioinfo-7-304
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Rockantenne-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Rockantenne [www.rockantenne.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.rockantenne.de/webplayer/#playlist"
+iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist
+
+# last Artist/Title
+all=`grep -m1 -A4 'Rock Nonstop' /tmp/playlist`
+all=${all//*$'class="artist">'/}; artist=${all/$'</span>'*/}
+title=${all/*$'class="title">'/}; title=${title/$'</span>'*/}
+# temp. no Info
+artist=${artist:='---'}; title=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-7-304.utf8 b/config/scripts/radioinfo-7-304.utf8
new file mode 100755
index 0000000..a92422e
--- /dev/null
+++ b/config/scripts/radioinfo-7-304.utf8
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Rockantenne-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Rockantenne [www.rockantenne.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.rockantenne.de/webplayer/#playlist"
+
+# last Artist/Title
+all=`grep -m1 -A4 'Rock Nonstop' /tmp/playlist`
+all=${all//*$'class="artist">'/}; artist=${all/$'</span>'*/}
+title=${all/*$'class="title">'/}; title=${title/$'</span>'*/}
+# temp. no Info
+artist=${artist:='---'}; title=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-7-336 b/config/scripts/radioinfo-7-336
new file mode 100755
index 0000000..3128161
--- /dev/null
+++ b/config/scripts/radioinfo-7-336
@@ -0,0 +1,27 @@
+#!/bin/bash
+# sunshione live Playlist
+# $1 = outfile
+
+### Variabel
+Name="sunshine live [www.sunshine-live.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.sunshine-live.de/index.php?id=15"
+
+# Artist/Title
+artist=`grep -A19 'sunshine live - playlist' /tmp/playlist`
+artist=${artist/*$'class="artist">'/}; artist=${artist/$'<'\/'td>'*/}
+title=`grep -A18 'sunshine live - playlist' /tmp/playlist`
+title=${title/*$'class="title">'/}; title=${title/$'<'\/'td>'*/}
+# temp. no Info
+artist=${artist:='---'}; titel=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-7-352 b/config/scripts/radioinfo-7-352
new file mode 100755
index 0000000..7b8eeaa
--- /dev/null
+++ b/config/scripts/radioinfo-7-352
@@ -0,0 +1,24 @@
+#!/bin/bash
+# AntenneBayern-Playlist
+# $1 = outfile
+
+### Variabel
+Name="Antenne Bayern [www.antenne.de]"
+###
+
+# get...
+wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.antenne.de/antenne/mediathek/c_titelinfos/aby-big.php"
+
+# Artist/Title
+all=`tail -n 6 /tmp/playlist | tac`
+artist=${all/*$';">'/}; artist=${artist/$'<br>'*/}
+title=${all/*$'<br>'/}; title=${title/$'<'\/'div>'*/}
+
+# write...
+if [ $1 ]; then
+ echo $Name > $1
+ echo $artist >> $1
+ echo $title >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/config/scripts/radioinfo-8500-214 b/config/scripts/radioinfo-8500-214
new file mode 100755
index 0000000..87a11c8
--- /dev/null
+++ b/config/scripts/radioinfo-8500-214
@@ -0,0 +1,24 @@
+#!/bin/bash
+# SRG-DRS Virus-Playlist
+# $1 = outfile
+
+### Variabel
+Name="SRG-DRS Virus [virus.ch]"
+###
+
+# get.., schnapp dir den neusten Eintrag aus der Liste; schneide ihn zu auf "titel von artist"
+all="`wget --quiet --tries=2 --timeout=5 -O - http://virus.ch/virus/ticker | grep -m1 date | cut -d '>' -f5 | cut -d '<' -f1`"
+
+# Titel, Artist
+title=${all/$' von '*/}
+artist=${all/*$' von '/}
+# temp. no Info
+artist=${artist:='---'}; title=${title:='---'}
+
+# write...
+if [ $1 ]; then
+ echo "$Name" > $1
+ echo "$Song" >> $1
+else
+ echo "$Name: Interpret/Titel = $artist / $title"
+fi
diff --git a/inforx.c b/inforx.c
new file mode 100644
index 0000000..ea0f492
--- /dev/null
+++ b/inforx.c
@@ -0,0 +1,162 @@
+/*
+ * inetrx.c - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include <fstream>
+#include "inforx.h"
+
+
+void fill_rtpbuffer(char *text1, char *text2) {
+
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", text1);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", text2);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+
+ if (++rtp_content.item_Index >= MAX_RTPC)
+ rtp_content.item_Index = 0;
+ if (rtp_content.item_Index >= 0) {
+ rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime;
+ asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist);
+ asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title);
+ }
+
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("radio-inforx: %s / %s\n", RTP_Artist, RTP_Title);
+}
+
+int info_request(int chantid, int chanapid) {
+
+ char ident[80];
+ char artist[RT_MEL], titel[RT_MEL];
+ struct tm tm_store;
+ static int repeat = 0;
+ char temp[2][2*RT_MEL];
+
+ char *command, *tempfile;
+ asprintf(&command, "%s/radioinfo-%d-%d", ConfigDir, chantid, chanapid);
+ asprintf(&tempfile, "%s/%s", DataDir, RadioInfofile);
+ dsyslog("radio: inforxcall '%s'\n", command);
+
+ DoInfoReq = false;
+ if (file_exists(command)) {
+ if (file_exists(tempfile)) { // delete tempfile
+ char *delcmd;
+ asprintf(&delcmd, "rm -f \"%s\"", tempfile);
+ system(delcmd);
+ free(delcmd);
+ }
+ asprintf(&command, "%s \"%s\"", command, tempfile);
+ if (!system(command)) { // execute script && read tempfile
+ if (file_exists(tempfile)) {
+ std::ifstream infile(tempfile);
+ if (infile.is_open()) {
+ infile.getline(ident, 80);
+ infile.getline(artist, RT_MEL);
+ infile.getline(titel, RT_MEL);
+ }
+ infile.close();
+ DoInfoReq = true;
+ }
+ else
+ esyslog("radio: ERROR inforx tempfile = %s\n", command);
+ }
+ else
+ esyslog("radio: ERROR inforx command = %s\n", command);
+ }
+ free(command);
+ free(tempfile);
+
+ if (!DoInfoReq) {
+ dsyslog("radio: inforxcall cancled !\n");
+ return -1;
+ }
+
+ // Info empty?
+ if (strcmp(artist, "") == 0 && strcmp(titel, "") == 0) {
+ if (repeat < 700) { // ~ 6x switch off
+ repeat += 120;
+ sprintf(RTP_Artist, "---");
+ sprintf(RTP_Title, "---");
+ RTP_Starttime = time(NULL);
+ sprintf(temp[0], "%s Error :-(", ident);
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ sprintf(temp[1], "%02d:%02d no Songinfo received !", ts->tm_hour, ts->tm_min);
+ fill_rtpbuffer(temp[0], temp[1]);
+ RT_MsgShow = true;
+ RT_PlusShow = false;
+ (RT_Info > 0) ? : RT_Info = 1;
+ radioStatusMsg();
+ return 120;
+ }
+ else {
+ RTP_Starttime = time(NULL);
+ sprintf(temp[0], "%s Error :-(", ident);
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ sprintf(temp[1], "%02d:%02d no Songinfo received, switching off !", ts->tm_hour, ts->tm_min);
+ asprintf(&rtp_content.info_Url, "%02d:%02d no Songinfo, switched off!", ts->tm_hour, ts->tm_min);
+ fill_rtpbuffer(temp[0], temp[1]);
+ RT_MsgShow = true;
+ RT_PlusShow = false;
+ (RT_Info > 0) ? : RT_Info = 1;
+ radioStatusMsg();
+ DoInfoReq = false;
+ return 60;
+ }
+ }
+
+ // Info
+ xhtml2text(artist);
+ xhtml2text(titel);
+ if (strcmp(RTP_Artist, artist) != 0 || strcmp(RTP_Title, titel) != 0) {
+ snprintf(RTP_Artist, RT_MEL, "%s", artist);
+ snprintf(RTP_Title, RT_MEL, "%s", titel);
+ RTP_Starttime = time(NULL);
+ sprintf(temp[0], "%s ok :-)", ident);
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ snprintf(temp[1], 2*RT_MEL, "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title);
+ fill_rtpbuffer(temp[0], temp[1]);
+ RT_MsgShow = RT_PlusShow = true;
+ (RT_Info > 0) ? : RT_Info = 2;
+ radioStatusMsg();
+ repeat = 0;
+ return 90;
+ }
+ else {
+ if (repeat < 1200) { // ~20 Min. timeout
+ repeat += 10;
+ return 10;
+ }
+ else {
+ sprintf(RTP_Artist, "---");
+ sprintf(RTP_Title, "---");
+ RTP_Starttime = time(NULL);
+ sprintf(temp[0], "%s Error :-(", ident);
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ sprintf(temp[1], "%02d:%02d no more different Songinfo received, switching off !", ts->tm_hour, ts->tm_min);
+ asprintf(&rtp_content.info_Url, "%02d:%02d no more Songinfo, switched off!", ts->tm_hour, ts->tm_min);
+ fill_rtpbuffer(temp[0], temp[1]);
+ RT_MsgShow = true;
+ RT_PlusShow = false;
+ (RT_Info > 0) ? : RT_Info = 1;
+ radioStatusMsg();
+ DoInfoReq = false;
+ return 60;
+ }
+ }
+
+ return 10;
+}
+
+
+// end
diff --git a/inforx.h b/inforx.h
new file mode 100644
index 0000000..4fb457e
--- /dev/null
+++ b/inforx.h
@@ -0,0 +1,24 @@
+/*
+ * inforx.h - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef _INFORX__H
+#define _INFORX__H
+
+#include "radioaudio.h"
+#include "radiotools.h"
+
+
+extern bool RT_MsgShow, RT_PlusShow;
+extern rtp_classes rtp_content;
+extern bool DoInfoReq;
+
+#define RadioInfofile "radioinfo.dat"
+
+int info_request(int chantid, int chanpid);
+
+
+#endif
diff --git a/po/de_DE.po b/po/de_DE.po
new file mode 100644
index 0000000..5ad188f
--- /dev/null
+++ b/po/de_DE.po
@@ -0,0 +1,350 @@
+# VDR plugin language source file.
+# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de>
+# This file is distributed under the same license as the VDR package.
+# Klaus Schmidinger <kls@cadsoft.de>, 2000
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VDR 1.5.7\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2013-05-31 20:15+0200\n"
+"PO-Revision-Date: 2007-09-20 15:30+0200\n"
+"Last-Translator: Uwe Hanke <egal@egal-vdr.de>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "unknown program type"
+msgstr "Unbekannte Programmart"
+
+msgid "News"
+msgstr "Nachrichten"
+
+msgid "Current affairs"
+msgstr "Aktuelles"
+
+msgid "Information"
+msgstr "Info"
+
+msgid "Sport"
+msgstr "Sport"
+
+msgid "Education"
+msgstr "Bildung"
+
+msgid "Drama"
+msgstr "Hörspiel"
+
+msgid "Culture"
+msgstr "Kultur"
+
+msgid "Science"
+msgstr "Wissenschaft"
+
+msgid "Varied"
+msgstr "Diverses"
+
+msgid "Pop music"
+msgstr "Popmusik"
+
+msgid "Rock music"
+msgstr "Rockmusik"
+
+msgid "M.O.R. music"
+msgstr "Easy Listening u.ä."
+
+msgid "Light classical"
+msgstr "Leichte Klassik"
+
+msgid "Serious classical"
+msgstr "Ernste Klassik"
+
+msgid "Other music"
+msgstr "Sonstige Musik"
+
+msgid "Alarm"
+msgstr "Alarm (!)"
+
+msgid "ext. Info"
+msgstr "zus. Info"
+
+msgid "RTplus"
+msgstr "RTplus"
+
+msgid "Radiotext"
+msgstr "Radiotext"
+
+msgid " [waiting ...]"
+msgstr " [warte ...]"
+
+msgid "Title :"
+msgstr "Titel :"
+
+msgid "Artist :"
+msgstr "Interpret :"
+
+msgid "Records"
+msgstr "Archiv"
+
+msgid "Rass-Image(s) saved from Archiv "
+msgstr "Rass-Bild(er)speicherung von Archiv "
+
+msgid "Rass-Image(s) saved from Gallery"
+msgstr "Rass-Bild(er) der Gallery gespeichert"
+
+msgid "Rass-Image saved"
+msgstr "Rass-Bildspeich."
+
+msgid "Rass-Image failed"
+msgstr "Rass-Bildspeicherfehler"
+
+msgid "Playlist"
+msgstr "Titelliste"
+
+msgid "Sports"
+msgstr "Sport"
+
+msgid "Lottery"
+msgstr "Lotterie"
+
+msgid "Weather"
+msgstr "Wetter"
+
+msgid "Stockmarket"
+msgstr "Bösenkurse"
+
+msgid "Other"
+msgstr "Sonstiges"
+
+msgid "extra Info since"
+msgstr "zusätzl. Info seit"
+
+msgid "RTplus Memory since"
+msgstr "RTplus Speicher seit"
+
+msgid "Programme"
+msgstr "Pogramminfo"
+
+msgid "Stat.Short"
+msgstr "Sender kurz"
+
+msgid "Station"
+msgstr "Sendername"
+
+msgid "Now"
+msgstr "Jetzt"
+
+msgid "...Part"
+msgstr "...Detail"
+
+msgid "Next"
+msgstr "Demnächst"
+
+msgid "Host"
+msgstr "Moderator"
+
+msgid "Edit.Staff"
+msgstr "Person(en)"
+
+msgid "Homepage"
+msgstr "Homepage"
+
+msgid "Interactivity"
+msgstr "Interaktiv (tu' was :)"
+
+msgid "Phone-Hotline"
+msgstr "Tel.-Hotline"
+
+msgid "Phone-Studio"
+msgstr "Tel.-Studio"
+
+msgid "SMS-Studio"
+msgstr "SMS-Studio"
+
+msgid "Email-Hotline"
+msgstr "EMail-Hotline"
+
+msgid "Email-Studio"
+msgstr "EMail-Studio"
+
+msgid "Info"
+msgstr "weitere Information"
+
+msgid "NewsLocal"
+msgstr "Nachricht.Lokal"
+
+msgid "DateTime"
+msgstr "Datum-Zeit"
+
+msgid "Traffic"
+msgstr "Verkehr"
+
+msgid "Advertising"
+msgstr "Hinweis/Reklame"
+
+msgid "Url"
+msgstr "Url/Webseite"
+
+msgid "Exit"
+msgstr "Beenden"
+
+msgid "Info-File saved"
+msgstr "Info-Datei gespeichert"
+
+msgid "RTplus-File saved"
+msgstr "RTplus-Datei gespeichert"
+
+msgid "last seen Radiotext"
+msgstr "die letzten Radiotexte"
+
+msgid "Time"
+msgstr "Zeit"
+
+msgid "Title"
+msgstr "Titel"
+
+msgid "Artist"
+msgstr "Interpret"
+
+msgid "Refresh Off"
+msgstr "Aktualis. Aus"
+
+msgid "Refresh On"
+msgstr "Aktualis. Ein"
+
+msgid "Back"
+msgstr "Zurück"
+
+msgid "Radio Background-Image/RDS-Text"
+msgstr "Hintergr.Bilder/RDS-Text für Radiosender"
+
+msgid "Show RDS-Radiotext"
+msgstr "Zeige RDS-Radiotext"
+
+msgid "Off"
+msgstr "Aus"
+
+msgid "only Text"
+msgstr "nur Text"
+
+msgid "Text+TagInfo"
+msgstr "Text+TagInfos"
+
+msgid "only, if some"
+msgstr "nur, wenn vorhanden"
+
+msgid "always"
+msgstr "immer"
+
+msgid "Top"
+msgstr "Oben"
+
+msgid "Bottom"
+msgstr "Unten"
+
+msgid "latest at Top"
+msgstr "aktuelle Oben"
+
+msgid "latest at Bottom"
+msgstr "aktuelle Unten"
+
+msgid "Black"
+msgstr "Schwarz"
+
+msgid "White"
+msgstr "Weiss"
+
+msgid "Red"
+msgstr "Rot"
+
+msgid "Green"
+msgstr "Grün"
+
+msgid "Yellow"
+msgstr "Gelb"
+
+msgid "Magenta"
+msgstr "Magenta"
+
+msgid "Blue"
+msgstr "Blau"
+
+msgid "Cyan"
+msgstr "Cyan"
+
+msgid "Transparent"
+msgstr "Transparent"
+
+msgid "about MainMenu"
+msgstr "über Hauptmenü"
+
+msgid "Automatic"
+msgstr "Automatisch"
+
+msgid "only Taginfo"
+msgstr "nur TagInfos"
+
+msgid "Rass only"
+msgstr "Rass alleine"
+
+msgid "Rass+Text mixed"
+msgstr "Text über Rass"
+
+msgid "Activate"
+msgstr "Aktivieren"
+
+msgid "Use StillPicture-Function"
+msgstr "Standbild-Funktion aktiv"
+
+msgid "Hide MainMenuEntry"
+msgstr "Verstecke Hauptmenu-Eintrag"
+
+msgid "RDSText Function"
+msgstr "RDSText Funktion"
+
+msgid "RDSText OSD-Position"
+msgstr "RDSText OSD-Position"
+
+msgid "RDSText OSD-Titlerow"
+msgstr "RDSText OSD-Titelzeile"
+
+msgid "RDSText OSD-Rows (1-5)"
+msgstr "RDSText OSD-Zeilen (1-5)"
+
+msgid "RDSText OSD-Scrollmode"
+msgstr "RDSText OSD-Scrollmodus"
+
+msgid "RDSText OSD-Taginfo"
+msgstr "RDSText OSD-Taginformation"
+
+msgid "RDSText OSD-Skincolors used"
+msgstr "RDSText OSD-Skinfarben benutzen"
+
+msgid "RDSText OSD-Backgr.Color"
+msgstr "RDSText OSD-Hintergrundfarbe"
+
+msgid "RDSText OSD-Backgr.Transp."
+msgstr "RDSText OSD-Hintergr.Transparenz"
+
+msgid "RDSText OSD-Foregr.Color"
+msgstr "RDSText OSD-Textfarbe"
+
+msgid "RDSText OSD-Timeout (0-1440 min)"
+msgstr "RDSText OSD-Timeout (0-1440 min)"
+
+msgid "RDSText OSD-Display"
+msgstr "RDSText OSD-Anzeige"
+
+msgid "RDSText StatusMsg (lcdproc & co)"
+msgstr "RDSText StatusMeld. (lcdproc & co)"
+
+msgid "RDSText Rass-Function"
+msgstr "RDSText Rass-Funktion"
+
+msgid "External Info-Request"
+msgstr "Externe Info-Abfrage"
+
+#~ msgid "with <0>"
+#~ msgstr "mit <0>"
diff --git a/po/fi_FI.po b/po/fi_FI.po
new file mode 100644
index 0000000..7c84cde
--- /dev/null
+++ b/po/fi_FI.po
@@ -0,0 +1,351 @@
+# VDR plugin language source file.
+# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de>
+# This file is distributed under the same license as the VDR package.
+# Rolf Ahrenberg <rahrenbe@cc.hut.fi>, 2003
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VDR 1.5.7\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2013-05-31 20:15+0200\n"
+"PO-Revision-Date: 2007-08-13 19:21+0200\n"
+"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "unknown program type"
+msgstr "tuntematon ohjelmatyyppi"
+
+msgid "News"
+msgstr "Uutiset"
+
+msgid "Current affairs"
+msgstr "ajankohtaista"
+
+msgid "Information"
+msgstr "tiedote"
+
+msgid "Sport"
+msgstr "urheilua"
+
+msgid "Education"
+msgstr "opetusohjelmaa"
+
+msgid "Drama"
+msgstr "draamaa"
+
+msgid "Culture"
+msgstr "kulttuuria"
+
+msgid "Science"
+msgstr "tiedeohjelma"
+
+msgid "Varied"
+msgstr "sekalaista"
+
+msgid "Pop music"
+msgstr "pop-musiikkia"
+
+msgid "Rock music"
+msgstr "rock-musiikkia"
+
+msgid "M.O.R. music"
+msgstr "taukomusiikkia"
+
+msgid "Light classical"
+msgstr "kevyttä klassista"
+
+msgid "Serious classical"
+msgstr "klassista"
+
+msgid "Other music"
+msgstr "musiikkia"
+
+msgid "Alarm"
+msgstr "Hälytys"
+
+msgid "ext. Info"
+msgstr ""
+
+msgid "RTplus"
+msgstr "RTplus"
+
+msgid "Radiotext"
+msgstr "Radioteksti"
+
+msgid " [waiting ...]"
+msgstr " [odota ...]"
+
+msgid "Title :"
+msgstr "Kappale :"
+
+msgid "Artist :"
+msgstr "Esittäjä :"
+
+msgid "Records"
+msgstr "Rass-tallenteet"
+
+msgid "Rass-Image(s) saved from Archiv "
+msgstr ""
+
+msgid "Rass-Image(s) saved from Gallery"
+msgstr ""
+
+msgid "Rass-Image saved"
+msgstr ""
+
+msgid "Rass-Image failed"
+msgstr ""
+
+msgid "Playlist"
+msgstr "Soittolista"
+
+msgid "Sports"
+msgstr "Urheilu"
+
+msgid "Lottery"
+msgstr "Arvonta"
+
+msgid "Weather"
+msgstr "Sää"
+
+msgid "Stockmarket"
+msgstr "Pörssikurssit"
+
+msgid "Other"
+msgstr "Sekalaiset"
+
+msgid "extra Info since"
+msgstr ""
+
+msgid "RTplus Memory since"
+msgstr "RTplus-muisti alkaen"
+
+msgid "Programme"
+msgstr "Ohjelma"
+
+msgid "Stat.Short"
+msgstr ""
+
+msgid "Station"
+msgstr "Asema"
+
+msgid "Now"
+msgstr "Nyt"
+
+msgid "...Part"
+msgstr "...osa"
+
+msgid "Next"
+msgstr "Seuraavaksi"
+
+msgid "Host"
+msgstr "Juontaja"
+
+msgid "Edit.Staff"
+msgstr "Henkilökunta"
+
+msgid "Homepage"
+msgstr "Kotisivu"
+
+msgid "Interactivity"
+msgstr "Interaktiivinen"
+
+msgid "Phone-Hotline"
+msgstr "Suoralinja puhelimelle"
+
+msgid "Phone-Studio"
+msgstr "Puhelin studioon"
+
+#, fuzzy
+msgid "SMS-Studio"
+msgstr "Puhelin studioon"
+
+msgid "Email-Hotline"
+msgstr "Suoralinja sähköpostille"
+
+msgid "Email-Studio"
+msgstr "Sähköposti studioon"
+
+msgid "Info"
+msgstr "Lisätiedot"
+
+msgid "NewsLocal"
+msgstr "Paikallisuutiset"
+
+msgid "DateTime"
+msgstr "Ajankohtaista"
+
+msgid "Traffic"
+msgstr "Liikenne"
+
+msgid "Advertising"
+msgstr "Mainos"
+
+msgid "Url"
+msgstr "Linkki"
+
+msgid "Exit"
+msgstr "Lopeta"
+
+msgid "Info-File saved"
+msgstr ""
+
+msgid "RTplus-File saved"
+msgstr "RTplus-tiedosto tallennettu"
+
+msgid "last seen Radiotext"
+msgstr "viimeksi nähty radioteksti"
+
+msgid "Time"
+msgstr "Kellonaika"
+
+msgid "Title"
+msgstr "Kappale"
+
+msgid "Artist"
+msgstr "Esittäjä"
+
+msgid "Refresh Off"
+msgstr "Älä päivitä"
+
+msgid "Refresh On"
+msgstr "Päivitä"
+
+msgid "Back"
+msgstr "Takaisin"
+
+msgid "Radio Background-Image/RDS-Text"
+msgstr "Taustakuva ja RDS-teksti radiokanaville"
+
+msgid "Show RDS-Radiotext"
+msgstr "Näytä RDS-teksti"
+
+msgid "Off"
+msgstr "pois"
+
+msgid "only Text"
+msgstr "vain teksti"
+
+msgid "Text+TagInfo"
+msgstr "teksti+tunniste"
+
+msgid "only, if some"
+msgstr "jos saatavilla"
+
+msgid "always"
+msgstr "aina"
+
+msgid "Top"
+msgstr "yläreuna"
+
+msgid "Bottom"
+msgstr "alareuna"
+
+msgid "latest at Top"
+msgstr "ylöspäin"
+
+msgid "latest at Bottom"
+msgstr "alaspäin"
+
+msgid "Black"
+msgstr "musta"
+
+msgid "White"
+msgstr "valkoinen"
+
+msgid "Red"
+msgstr "punainen"
+
+msgid "Green"
+msgstr "vihreä"
+
+msgid "Yellow"
+msgstr "keltainen"
+
+msgid "Magenta"
+msgstr "magenta"
+
+msgid "Blue"
+msgstr "sininen"
+
+msgid "Cyan"
+msgstr "syaani"
+
+msgid "Transparent"
+msgstr "läpinäkyvä"
+
+msgid "about MainMenu"
+msgstr "päävalikosta"
+
+msgid "Automatic"
+msgstr "automaattisesti"
+
+msgid "only Taginfo"
+msgstr "vain tunniste"
+
+msgid "Rass only"
+msgstr "vain Rass"
+
+msgid "Rass+Text mixed"
+msgstr "Teksti ja Rass"
+
+msgid "Activate"
+msgstr "Aktiivinen"
+
+msgid "Use StillPicture-Function"
+msgstr ""
+
+msgid "Hide MainMenuEntry"
+msgstr "Piilota valinta päävalikosta"
+
+msgid "RDSText Function"
+msgstr "RDS-tekstin toiminto"
+
+msgid "RDSText OSD-Position"
+msgstr "RDS-tekstin sijainti"
+
+msgid "RDSText OSD-Titlerow"
+msgstr "RDS-tekstin kappale"
+
+msgid "RDSText OSD-Rows (1-5)"
+msgstr "RDS-tekstin rivimäärä"
+
+msgid "RDSText OSD-Scrollmode"
+msgstr "RDS-tekstin vieritystapa"
+
+msgid "RDSText OSD-Taginfo"
+msgstr "RDS-tekstin tunnistetiedot"
+
+msgid "RDSText OSD-Skincolors used"
+msgstr "Käytä RDS-tekstille ulkoasun värejä"
+
+msgid "RDSText OSD-Backgr.Color"
+msgstr "RDS-tekstin taustaväri"
+
+msgid "RDSText OSD-Backgr.Transp."
+msgstr "RDS-tekstin taustan läpinäkyvyys"
+
+msgid "RDSText OSD-Foregr.Color"
+msgstr "RDS-tekstin väri"
+
+msgid "RDSText OSD-Timeout (0-1440 min)"
+msgstr "RDS-tekstin odotusaika (0-1440min)"
+
+msgid "RDSText OSD-Display"
+msgstr "RDS-tekstin esitys"
+
+msgid "RDSText StatusMsg (lcdproc & co)"
+msgstr "RDS-tekstin toiminto laajennoksille"
+
+msgid "RDSText Rass-Function"
+msgstr "Käytä RDS-tekstin Rass-toimintoa"
+
+msgid "External Info-Request"
+msgstr ""
+
+#~ msgid "with <0>"
+#~ msgstr "'0'-näppäimellä"
diff --git a/po/fr_FR.po b/po/fr_FR.po
new file mode 100644
index 0000000..e8e6493
--- /dev/null
+++ b/po/fr_FR.po
@@ -0,0 +1,350 @@
+# VDR plugin language source file.
+# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de>
+# This file is distributed under the same license as the VDR package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VDR 1.5.7\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2013-05-31 20:15+0200\n"
+"PO-Revision-Date: 2007-09-14 16:12+0200\n"
+"Last-Translator: Michaël Nival, Patrice Staudt\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "unknown program type"
+msgstr "Type de programme inconnu"
+
+msgid "News"
+msgstr "Informations"
+
+msgid "Current affairs"
+msgstr "Affaires courantes"
+
+msgid "Information"
+msgstr "Information"
+
+msgid "Sport"
+msgstr "Sport"
+
+msgid "Education"
+msgstr "Education"
+
+msgid "Drama"
+msgstr "Drame"
+
+msgid "Culture"
+msgstr "Culture"
+
+msgid "Science"
+msgstr "Science"
+
+msgid "Varied"
+msgstr "Divers"
+
+msgid "Pop music"
+msgstr "Musique Pop"
+
+msgid "Rock music"
+msgstr "Musique Rock"
+
+msgid "M.O.R. music"
+msgstr "Musique M.O.R."
+
+msgid "Light classical"
+msgstr "Classique facile"
+
+msgid "Serious classical"
+msgstr "Classique sérieux"
+
+msgid "Other music"
+msgstr "Autre musique"
+
+msgid "Alarm"
+msgstr "Alarme"
+
+msgid "ext. Info"
+msgstr "Infos externe"
+
+msgid "RTplus"
+msgstr "RTplus"
+
+msgid "Radiotext"
+msgstr "Radio Texte"
+
+msgid " [waiting ...]"
+msgstr " [attente ...]"
+
+msgid "Title :"
+msgstr "Titre :"
+
+msgid "Artist :"
+msgstr "Artiste :"
+
+msgid "Records"
+msgstr "Archive"
+
+msgid "Rass-Image(s) saved from Archiv "
+msgstr "Rass-image(2) saugarde de l'archive"
+
+msgid "Rass-Image(s) saved from Gallery"
+msgstr "Rass-image(2) saugarde de la gallerie"
+
+msgid "Rass-Image saved"
+msgstr "Rass-Image sauvegarder"
+
+msgid "Rass-Image failed"
+msgstr "Rass-Image erreur"
+
+msgid "Playlist"
+msgstr "Playlist"
+
+msgid "Sports"
+msgstr "Sports"
+
+msgid "Lottery"
+msgstr "Loterie"
+
+msgid "Weather"
+msgstr "Météo"
+
+msgid "Stockmarket"
+msgstr "Bourse"
+
+msgid "Other"
+msgstr "Autre"
+
+msgid "extra Info since"
+msgstr "Info extern depuis"
+
+msgid "RTplus Memory since"
+msgstr "Mémoire de RTplus depuis"
+
+msgid "Programme"
+msgstr "Programme"
+
+msgid "Stat.Short"
+msgstr ""
+
+msgid "Station"
+msgstr "Station"
+
+msgid "Now"
+msgstr "Maintenant"
+
+msgid "...Part"
+msgstr "...Détail"
+
+msgid "Next"
+msgstr "Suivant"
+
+msgid "Host"
+msgstr "Animateur"
+
+msgid "Edit.Staff"
+msgstr "Personne"
+
+msgid "Homepage"
+msgstr "Page d'accueil"
+
+msgid "Interactivity"
+msgstr "Interactivité"
+
+msgid "Phone-Hotline"
+msgstr "Téléphone hotline"
+
+msgid "Phone-Studio"
+msgstr "Téléphone studio"
+
+#, fuzzy
+msgid "SMS-Studio"
+msgstr "Téléphone studio"
+
+msgid "Email-Hotline"
+msgstr "E-mail hotline"
+
+msgid "Email-Studio"
+msgstr "E-mail studio"
+
+msgid "Info"
+msgstr "D'autres informations"
+
+msgid "NewsLocal"
+msgstr "Information local"
+
+msgid "DateTime"
+msgstr "Date-Heure"
+
+msgid "Traffic"
+msgstr "Traffic"
+
+msgid "Advertising"
+msgstr "Publicité"
+
+msgid "Url"
+msgstr "Url"
+
+msgid "Exit"
+msgstr "Sortir"
+
+msgid "Info-File saved"
+msgstr "Sauvegarde du fichier inf"
+
+msgid "RTplus-File saved"
+msgstr "Sauvé fichier TTplus"
+
+msgid "last seen Radiotext"
+msgstr "Dernier Radio-texte"
+
+msgid "Time"
+msgstr "Temps"
+
+msgid "Title"
+msgstr "Titre"
+
+msgid "Artist"
+msgstr "Artiste"
+
+msgid "Refresh Off"
+msgstr "Arrêter actualisation"
+
+msgid "Refresh On"
+msgstr "Démarrer actualisation"
+
+msgid "Back"
+msgstr "Retour"
+
+msgid "Radio Background-Image/RDS-Text"
+msgstr "Image de fond pour les radio/RDS-Texte"
+
+msgid "Show RDS-Radiotext"
+msgstr "Afficher RDS"
+
+msgid "Off"
+msgstr "Off"
+
+msgid "only Text"
+msgstr "Seulement le texte"
+
+msgid "Text+TagInfo"
+msgstr "Texte+Tag d'info"
+
+msgid "only, if some"
+msgstr "Seulement, si disponible"
+
+msgid "always"
+msgstr "Toujours"
+
+msgid "Top"
+msgstr "Haut"
+
+msgid "Bottom"
+msgstr "Bas"
+
+msgid "latest at Top"
+msgstr "En haut"
+
+msgid "latest at Bottom"
+msgstr "En bas"
+
+msgid "Black"
+msgstr "Noir"
+
+msgid "White"
+msgstr "Blanc"
+
+msgid "Red"
+msgstr "Rouge"
+
+msgid "Green"
+msgstr "Vert"
+
+msgid "Yellow"
+msgstr "Jaune"
+
+msgid "Magenta"
+msgstr "Magenta"
+
+msgid "Blue"
+msgstr "Bleu"
+
+msgid "Cyan"
+msgstr "Cyan"
+
+msgid "Transparent"
+msgstr "Transparent"
+
+msgid "about MainMenu"
+msgstr "A propos de menu principal"
+
+msgid "Automatic"
+msgstr "Automatique"
+
+msgid "only Taginfo"
+msgstr "Seulement Tag Info"
+
+msgid "Rass only"
+msgstr "Rass seulement"
+
+msgid "Rass+Text mixed"
+msgstr "Texte par dessus Rass"
+
+msgid "Activate"
+msgstr "Activer"
+
+msgid "Use StillPicture-Function"
+msgstr "Utiliser fonction image de font"
+
+msgid "Hide MainMenuEntry"
+msgstr "Cacher l'entrée dans le menu principal"
+
+msgid "RDSText Function"
+msgstr "Fonction de RDS-Texte"
+
+msgid "RDSText OSD-Position"
+msgstr "Position OSD de RDS-Texte"
+
+msgid "RDSText OSD-Titlerow"
+msgstr "Titre OSD de RDS-Texte"
+
+msgid "RDSText OSD-Rows (1-5)"
+msgstr "Ligne OSD de RDS-Texte (1-5)"
+
+msgid "RDSText OSD-Scrollmode"
+msgstr "Mode Scroll OSD de RDS-Texte "
+
+msgid "RDSText OSD-Taginfo"
+msgstr "Tag info OSD de RDS-Texte"
+
+msgid "RDSText OSD-Skincolors used"
+msgstr "Couleur du skin utilisé de RDS-texte"
+
+msgid "RDSText OSD-Backgr.Color"
+msgstr "Couleur de fond OSD de RDS-Texte"
+
+msgid "RDSText OSD-Backgr.Transp."
+msgstr "Fond transparent OSD de RDS-Texte"
+
+msgid "RDSText OSD-Foregr.Color"
+msgstr "Couleur du texte OSD de RDS-Texte"
+
+msgid "RDSText OSD-Timeout (0-1440 min)"
+msgstr "Timeout OSD de RDS-Texte (0-1440 min)"
+
+msgid "RDSText OSD-Display"
+msgstr "Affichage OSD de RDS-Texte"
+
+msgid "RDSText StatusMsg (lcdproc & co)"
+msgstr "Statut message de RDS-Texte (lcdproc & co)"
+
+msgid "RDSText Rass-Function"
+msgstr "Fonction Rass de RDSTexte"
+
+msgid "External Info-Request"
+msgstr "Demande d'infos externe"
+
+#~ msgid "with <0>"
+#~ msgstr "avec <0>"
diff --git a/po/hu_HU.po b/po/hu_HU.po
new file mode 100644
index 0000000..5cf5fce
--- /dev/null
+++ b/po/hu_HU.po
@@ -0,0 +1,350 @@
+# VDR plugin language source file.
+# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de>
+# This file is distributed under the same license as the VDR package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VDR 1.5.7\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2013-05-31 20:15+0200\n"
+"PO-Revision-Date: 2007-08-13 19:21+0200\n"
+"Last-Translator: Füley István\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-2\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "unknown program type"
+msgstr "ismeretlen adástipus"
+
+msgid "News"
+msgstr "Hírek"
+
+msgid "Current affairs"
+msgstr "aktuális"
+
+msgid "Information"
+msgstr "információ"
+
+msgid "Sport"
+msgstr "sport"
+
+msgid "Education"
+msgstr "nevelés"
+
+msgid "Drama"
+msgstr "rádiójáték"
+
+msgid "Culture"
+msgstr "kultúra"
+
+msgid "Science"
+msgstr "tudomány"
+
+msgid "Varied"
+msgstr "vegyes"
+
+msgid "Pop music"
+msgstr "pop zene"
+
+msgid "Rock music"
+msgstr "rock zene"
+
+msgid "M.O.R. music"
+msgstr "könnyûzene"
+
+msgid "Light classical"
+msgstr "könnyû klasszikus"
+
+msgid "Serious classical"
+msgstr "komolyzene"
+
+msgid "Other music"
+msgstr "egyéb zene"
+
+msgid "Alarm"
+msgstr "Riasztó"
+
+msgid "ext. Info"
+msgstr ""
+
+msgid "RTplus"
+msgstr "RTplus"
+
+msgid "Radiotext"
+msgstr "Rádiótext"
+
+msgid " [waiting ...]"
+msgstr "[várakozás...]"
+
+msgid "Title :"
+msgstr "Cím :"
+
+msgid "Artist :"
+msgstr "Elõadó :"
+
+msgid "Records"
+msgstr "Archívum"
+
+msgid "Rass-Image(s) saved from Archiv "
+msgstr "Rass-kép(ek) elmentve az archívumból"
+
+msgid "Rass-Image(s) saved from Gallery"
+msgstr "Rass-kép(ek) elmentve a galériából"
+
+msgid "Rass-Image saved"
+msgstr "Rass-Kép elmentve."
+
+msgid "Rass-Image failed"
+msgstr "Sikertelen Rass-Kép mentés"
+
+msgid "Playlist"
+msgstr "Playlist"
+
+msgid "Sports"
+msgstr "Sport"
+
+msgid "Lottery"
+msgstr "Lottó"
+
+msgid "Weather"
+msgstr "Idõjárás"
+
+msgid "Stockmarket"
+msgstr "Börze"
+
+msgid "Other"
+msgstr "Egyéb"
+
+msgid "extra Info since"
+msgstr ""
+
+msgid "RTplus Memory since"
+msgstr "RTplus innen kezdve"
+
+msgid "Programme"
+msgstr "Programinfó"
+
+msgid "Stat.Short"
+msgstr ""
+
+msgid "Station"
+msgstr "Rádióadó"
+
+msgid "Now"
+msgstr "Most"
+
+msgid "...Part"
+msgstr "...rész"
+
+msgid "Next"
+msgstr "Következõ"
+
+msgid "Host"
+msgstr "Müsorvezetõ"
+
+msgid "Edit.Staff"
+msgstr "Stáb"
+
+msgid "Homepage"
+msgstr "Honlap"
+
+msgid "Interactivity"
+msgstr "Interaktivitás"
+
+msgid "Phone-Hotline"
+msgstr "Telefonos forródrót"
+
+msgid "Phone-Studio"
+msgstr "Telefon studió"
+
+#, fuzzy
+msgid "SMS-Studio"
+msgstr "Telefon studió"
+
+msgid "Email-Hotline"
+msgstr "E-mail forródrót"
+
+msgid "Email-Studio"
+msgstr "E-mail studió"
+
+msgid "Info"
+msgstr "Egyéb információ"
+
+msgid "NewsLocal"
+msgstr "Helyi hírek"
+
+msgid "DateTime"
+msgstr "Dátum-óra"
+
+msgid "Traffic"
+msgstr "Forgalom"
+
+msgid "Advertising"
+msgstr "Reklám"
+
+msgid "Url"
+msgstr "Weblink"
+
+msgid "Exit"
+msgstr "Kilépés"
+
+msgid "Info-File saved"
+msgstr ""
+
+msgid "RTplus-File saved"
+msgstr "RTplus-file elmentve"
+
+msgid "last seen Radiotext"
+msgstr "utoljára vett rádiótext"
+
+msgid "Time"
+msgstr "Idõ"
+
+msgid "Title"
+msgstr "Cím"
+
+msgid "Artist"
+msgstr "Elõadó"
+
+msgid "Refresh Off"
+msgstr "Frissítés ki"
+
+msgid "Refresh On"
+msgstr "Frissítés be"
+
+msgid "Back"
+msgstr "Vissza"
+
+msgid "Radio Background-Image/RDS-Text"
+msgstr "Rádió háttérkép/RDS-Text"
+
+msgid "Show RDS-Radiotext"
+msgstr "RDS-Text megjelenítése"
+
+msgid "Off"
+msgstr "ki"
+
+msgid "only Text"
+msgstr "csak Text"
+
+msgid "Text+TagInfo"
+msgstr "Text és Taginfo"
+
+msgid "only, if some"
+msgstr "csak, ha létezik"
+
+msgid "always"
+msgstr "mindig"
+
+msgid "Top"
+msgstr "fenn"
+
+msgid "Bottom"
+msgstr "lenn"
+
+msgid "latest at Top"
+msgstr "legfrisebbet felülre"
+
+msgid "latest at Bottom"
+msgstr "legfrisebbet alulra"
+
+msgid "Black"
+msgstr "fekete"
+
+msgid "White"
+msgstr "fehér"
+
+msgid "Red"
+msgstr "vörös"
+
+msgid "Green"
+msgstr "zöld"
+
+msgid "Yellow"
+msgstr "sárga"
+
+msgid "Magenta"
+msgstr "bíbor"
+
+msgid "Blue"
+msgstr "kék"
+
+msgid "Cyan"
+msgstr "cián"
+
+msgid "Transparent"
+msgstr "átlátszó"
+
+msgid "about MainMenu"
+msgstr "mint a fõmenüben"
+
+msgid "Automatic"
+msgstr "automatikus"
+
+msgid "only Taginfo"
+msgstr "csak Taginfo"
+
+msgid "Rass only"
+msgstr "csak Rass"
+
+msgid "Rass+Text mixed"
+msgstr "Text és Rass"
+
+msgid "Activate"
+msgstr "Aktív"
+
+msgid "Use StillPicture-Function"
+msgstr ""
+
+msgid "Hide MainMenuEntry"
+msgstr "Elrejtés a fõmenüben"
+
+msgid "RDSText Function"
+msgstr "RDS-Text funkció "
+
+msgid "RDSText OSD-Position"
+msgstr "Az RDS-Text OSD pozicíója"
+
+msgid "RDSText OSD-Titlerow"
+msgstr "RDS-Text OSD fejléc"
+
+msgid "RDSText OSD-Rows (1-5)"
+msgstr "RDS-Text OSD sorok száma (1-5)"
+
+msgid "RDSText OSD-Scrollmode"
+msgstr "RDS-Text OSD görgetésének módja"
+
+msgid "RDSText OSD-Taginfo"
+msgstr "RDS-Text OSD-Taginfo"
+
+msgid "RDSText OSD-Skincolors used"
+msgstr "Felhasznált RDS-Text színek"
+
+msgid "RDSText OSD-Backgr.Color"
+msgstr "RDS-Text háttérszín"
+
+msgid "RDSText OSD-Backgr.Transp."
+msgstr "RDS-Text háttér átlátszósága"
+
+msgid "RDSText OSD-Foregr.Color"
+msgstr "RDS-Text fontszín"
+
+msgid "RDSText OSD-Timeout (0-1440 min)"
+msgstr "RDS-Text idõtúllépés (0-1440 perc)"
+
+msgid "RDSText OSD-Display"
+msgstr "RDS-Text megjelenítés"
+
+msgid "RDSText StatusMsg (lcdproc & co)"
+msgstr "RDS-Text állapotüzenet (lcdproc, stb)"
+
+msgid "RDSText Rass-Function"
+msgstr "RDS Rass funkció"
+
+msgid "External Info-Request"
+msgstr ""
+
+#~ msgid "with <0>"
+#~ msgstr "<0> bill."
diff --git a/po/it_IT.po b/po/it_IT.po
new file mode 100644
index 0000000..eab61d8
--- /dev/null
+++ b/po/it_IT.po
@@ -0,0 +1,350 @@
+# VDR plugin language source file.
+# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de>
+# This file is distributed under the same license as the VDR package.
+# Klaus Schmidinger <kls@cadsoft.de>, 2000
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VDR 1.5.7\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2013-05-31 20:15+0200\n"
+"PO-Revision-Date: 2008-06-15 22:39+0100\n"
+"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
+"Language-Team: <vdr@linuxtv.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-15\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "unknown program type"
+msgstr "tipo programma sconosciuto"
+
+msgid "News"
+msgstr "Notizie"
+
+msgid "Current affairs"
+msgstr "Attualità"
+
+msgid "Information"
+msgstr "Informazione"
+
+msgid "Sport"
+msgstr "Sport"
+
+msgid "Education"
+msgstr "Istruzione"
+
+msgid "Drama"
+msgstr "Dramma"
+
+msgid "Culture"
+msgstr "Cultura"
+
+msgid "Science"
+msgstr "Scienza"
+
+msgid "Varied"
+msgstr "Altro"
+
+msgid "Pop music"
+msgstr "Musica Pop"
+
+msgid "Rock music"
+msgstr "Musica Rock"
+
+msgid "M.O.R. music"
+msgstr "Musica M.O.R."
+
+msgid "Light classical"
+msgstr "Classica leggera"
+
+msgid "Serious classical"
+msgstr "Classica seria"
+
+msgid "Other music"
+msgstr "Altra musica"
+
+msgid "Alarm"
+msgstr "Allarme"
+
+msgid "ext. Info"
+msgstr "Info esterne"
+
+msgid "RTplus"
+msgstr "RTplus"
+
+msgid "Radiotext"
+msgstr "Radio testo"
+
+msgid " [waiting ...]"
+msgstr " [attendere ...]"
+
+msgid "Title :"
+msgstr "Titolo :"
+
+msgid "Artist :"
+msgstr "Artista :"
+
+msgid "Records"
+msgstr "Archivio"
+
+msgid "Rass-Image(s) saved from Archiv "
+msgstr "Immagini Rass salvate dall'Archivio"
+
+msgid "Rass-Image(s) saved from Gallery"
+msgstr "Immagini Rass salvate dalla Galleria"
+
+msgid "Rass-Image saved"
+msgstr "Immagine Rass salvata"
+
+msgid "Rass-Image failed"
+msgstr "Immagine Rass fallita"
+
+msgid "Playlist"
+msgstr "Lista esecuzione"
+
+msgid "Sports"
+msgstr "Sport"
+
+msgid "Lottery"
+msgstr "Lotteria"
+
+msgid "Weather"
+msgstr "Meteo"
+
+msgid "Stockmarket"
+msgstr "Borse"
+
+msgid "Other"
+msgstr "Altro"
+
+msgid "extra Info since"
+msgstr "Info extra da"
+
+msgid "RTplus Memory since"
+msgstr "Memoria RTplus da"
+
+msgid "Programme"
+msgstr "Programma"
+
+msgid "Stat.Short"
+msgstr "Brevi statistiche"
+
+msgid "Station"
+msgstr "Stazione"
+
+msgid "Now"
+msgstr "Adesso"
+
+msgid "...Part"
+msgstr "...Dettaglio"
+
+msgid "Next"
+msgstr "Prossimo"
+
+msgid "Host"
+msgstr "Animatore"
+
+msgid "Edit.Staff"
+msgstr "Staff"
+
+msgid "Homepage"
+msgstr "Pagina princ."
+
+msgid "Interactivity"
+msgstr "Interattività"
+
+msgid "Phone-Hotline"
+msgstr "Telefono assistenza"
+
+msgid "Phone-Studio"
+msgstr "Telefono studio"
+
+msgid "SMS-Studio"
+msgstr "SMS studio"
+
+msgid "Email-Hotline"
+msgstr "Email assistenza"
+
+msgid "Email-Studio"
+msgstr "Email studio"
+
+msgid "Info"
+msgstr "Informazioni"
+
+msgid "NewsLocal"
+msgstr "Notizie locali"
+
+msgid "DateTime"
+msgstr "Data-Ora"
+
+msgid "Traffic"
+msgstr "Traffico"
+
+msgid "Advertising"
+msgstr "Pubblicità"
+
+msgid "Url"
+msgstr "Sito web"
+
+msgid "Exit"
+msgstr "Esci"
+
+msgid "Info-File saved"
+msgstr "Info file salvate"
+
+msgid "RTplus-File saved"
+msgstr "File RTplus salvato"
+
+msgid "last seen Radiotext"
+msgstr "ultimo radio testo letto"
+
+msgid "Time"
+msgstr "Ora"
+
+msgid "Title"
+msgstr "Titolo"
+
+msgid "Artist"
+msgstr "Artista"
+
+msgid "Refresh Off"
+msgstr "Disattiva aggiornamenti"
+
+msgid "Refresh On"
+msgstr "Attiva aggiornamenti"
+
+msgid "Back"
+msgstr "Indietro"
+
+msgid "Radio Background-Image/RDS-Text"
+msgstr "Immagine sfondo per Radio/Testo RDS"
+
+msgid "Show RDS-Radiotext"
+msgstr "Mostra testi RDS"
+
+msgid "Off"
+msgstr "Disattivo"
+
+msgid "only Text"
+msgstr "solo testo"
+
+msgid "Text+TagInfo"
+msgstr "Testo+Scheda info"
+
+msgid "only, if some"
+msgstr "solo, se disp."
+
+msgid "always"
+msgstr "sempre"
+
+msgid "Top"
+msgstr "Alto"
+
+msgid "Bottom"
+msgstr "Basso"
+
+msgid "latest at Top"
+msgstr "ultimo in alto"
+
+msgid "latest at Bottom"
+msgstr "ultimo in basso"
+
+msgid "Black"
+msgstr "Nero"
+
+msgid "White"
+msgstr "Bianco"
+
+msgid "Red"
+msgstr "Rosso"
+
+msgid "Green"
+msgstr "Verde"
+
+msgid "Yellow"
+msgstr "Giallo"
+
+msgid "Magenta"
+msgstr "Magenta"
+
+msgid "Blue"
+msgstr "Blu"
+
+msgid "Cyan"
+msgstr "Ciano"
+
+msgid "Transparent"
+msgstr "Trasparente"
+
+msgid "about MainMenu"
+msgstr "info menu princ."
+
+msgid "Automatic"
+msgstr "Automatica"
+
+msgid "only Taginfo"
+msgstr "solo scheda info"
+
+msgid "Rass only"
+msgstr "Solo Rass"
+
+msgid "Rass+Text mixed"
+msgstr "Rass+testo misto"
+
+msgid "Activate"
+msgstr "Attiva"
+
+msgid "Use StillPicture-Function"
+msgstr "Utilizza funz. immagine princ."
+
+msgid "Hide MainMenuEntry"
+msgstr "Nascondi voce menu principale"
+
+msgid "RDSText Function"
+msgstr "Funzione testo RDS"
+
+msgid "RDSText OSD-Position"
+msgstr "Posizione OSD testo RDS"
+
+msgid "RDSText OSD-Titlerow"
+msgstr "Riga titolo OSD testo RDS"
+
+msgid "RDSText OSD-Rows (1-5)"
+msgstr "Righe OSD testo RDS (1-5)"
+
+msgid "RDSText OSD-Scrollmode"
+msgstr "Mod. scorr. OSD testo RDS"
+
+msgid "RDSText OSD-Taginfo"
+msgstr "Campo info OSD testo RDS"
+
+msgid "RDSText OSD-Skincolors used"
+msgstr "Colori interf. OSD testo RDS"
+
+msgid "RDSText OSD-Backgr.Color"
+msgstr "Colore sfondo OSD testo RDS"
+
+msgid "RDSText OSD-Backgr.Transp."
+msgstr "Trasp. sfondo OSD testo RDS"
+
+msgid "RDSText OSD-Foregr.Color"
+msgstr "Colore car. OSD testo RDS"
+
+msgid "RDSText OSD-Timeout (0-1440 min)"
+msgstr "Scad. testo RDS (0-1440 min)"
+
+msgid "RDSText OSD-Display"
+msgstr "Visualizz. OSD testo RDS"
+
+msgid "RDSText StatusMsg (lcdproc & co)"
+msgstr "Mess. stato testo RDS (lcdproc & co)"
+
+msgid "RDSText Rass-Function"
+msgstr "Funzione Rass testo RDS"
+
+msgid "External Info-Request"
+msgstr "Richiesta info esterna"
+
+#~ msgid "with <0>"
+#~ msgstr "con <0>"
diff --git a/radio.c b/radio.c
new file mode 100644
index 0000000..d01fa8b
--- /dev/null
+++ b/radio.c
@@ -0,0 +1,731 @@
+/*
+ * radio.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include <vdr/plugin.h>
+#include <vdr/status.h>
+#include <vdr/config.h>
+#include <vdr/interface.h>
+#include <vdr/transfer.h>
+#include "getopt.h"
+#include "radioaudio.h"
+#include "radiotools.h"
+#include "radioepg.h"
+#include "inforx.h"
+
+#if VDRVERSNUM < 10737
+ #error This version of radio-plugin requires vdr >= 1.7.37
+#endif
+
+static const char *VERSION = "1.0.0";
+static const char *DESCRIPTION = trNOOP("Radio Background-Image/RDS-Text");
+static const char *MAINMENUENTRY = trNOOP("Show RDS-Radiotext");
+char *ConfigDir;
+char *DataDir;
+char *LiveFile;
+char *ReplayFile;
+
+// Setup-Params
+int S_Activate = false;
+int S_StillPic = 1;
+int S_HMEntry = false;
+int S_RtFunc = 1;
+int S_RtOsdTitle = 1;
+int S_RtOsdTags = 2;
+int S_RtOsdPos = 1;
+int S_RtOsdRows = 2;
+int S_RtOsdLoop = 0;
+int S_RtOsdTO = 60;
+int S_RtSkinColor = 1;
+int S_RtBgCol = 0;
+int S_RtBgTra = 0xA0;
+int S_RtFgCol = 1;
+int S_RtDispl = 1;
+int S_RtMsgItems = 0;
+//int S_RtpMemNo = 25;
+int S_RassText = 1;
+int S_ExtInfo = 0;
+uint32_t rt_color[9];
+int S_Verbose = 1;
+int S_Encrypted = 0;
+// Radiotext
+char RT_Text[5][RT_MEL];
+char RTP_Artist[RT_MEL], RTP_Title[RT_MEL];
+int RT_Info, RT_Index, RT_PTY;
+time_t RTP_Starttime;
+bool RT_OsdTO = false, RTplus_Osd = false, RT_ReOpen = false;
+int RT_OsdTOTemp = 0, Radio_CA = 0;
+int RT_Charset = 0; // 0= ISO-8859-1, 1= UTF8, 2= ..
+// RadioCheck
+const cChannel *chan;
+int IsRadioOrReplay;
+// Info
+bool DoInfoReq = false, InfoRequest = false;
+int InfoTimeout = 3;
+
+struct RadioTextService_v1_0 {
+ int rds_info; // 0= no / 1= Text / 2= Text + RTplus-Tags (Item,Artist)
+ int rds_pty; // 0-31
+ char *rds_text;
+ char *rds_title;
+ char *rds_artist;
+ struct tm *title_start;
+};
+
+
+// --- cRadioCheck -------------------------------------------------------
+
+class cRadioCheck: public cThread {
+private:
+ static cRadioCheck *RadioCheck;
+protected:
+ virtual void Action(void);
+ void Stop(void);
+public:
+ cRadioCheck(void);
+ virtual ~cRadioCheck();
+ static void Init(void);
+ static void Exit(void);
+};
+
+cRadioCheck *cRadioCheck::RadioCheck = NULL;
+
+cRadioCheck::cRadioCheck(void)
+: cThread("radiocheck")
+{
+ IsRadioOrReplay = 0;
+}
+
+cRadioCheck::~cRadioCheck() {
+ if (Running())
+ Stop();
+}
+
+void cRadioCheck::Init(void) {
+ if (RadioCheck == NULL) {
+ RadioCheck = new cRadioCheck;
+ RadioCheck->Start();
+ }
+}
+
+void cRadioCheck::Exit(void) {
+ if (RadioCheck != NULL) {
+ RadioCheck->Stop();
+ DELETENULL(RadioCheck);
+ }
+}
+
+void cRadioCheck::Stop(void) {
+ Cancel(10);
+}
+
+void cRadioCheck::Action(void)
+{
+
+ if ((S_Verbose && 0x0f) >= 2)
+ printf("vdr-radio: background-checking starts\n");
+
+ while (Running()) {
+ cCondWait::SleepMs(2000);
+
+ // check Live-Radio
+ if (IsRadioOrReplay == 1 && chan != NULL) {
+ if (chan->Vpid()) {
+ isyslog("radio: channnel '%s' got Vpid= %d", chan->Name(), chan->Vpid());
+ IsRadioOrReplay = 0;
+ Channels.SwitchTo(cDevice::CurrentChannel());
+ //cDevice::PrimaryDevice()->SwitchChannel(chan, true);
+ }
+ else {
+ if ((InfoTimeout-=2) <= 0) {
+ InfoTimeout = 20;
+ int chtid = chan->Tid();
+ // Kanal-EPG PresentEvent
+ if (chan->Apid(0) > 0 && (chtid == PREMIERERADIO_TID || chtid == KDRADIO_TID
+ || chtid == UMRADIO_TID1 || chtid == UMRADIO_TID2 || chtid == UMRADIO_TID3 || chtid == UMRADIO_TID4 || chtid == UMRADIO_TID5)) {
+ cSchedulesLock schedLock;
+ const cSchedules *scheds = cSchedules::Schedules(schedLock);
+ if (scheds != NULL) {
+ const cSchedule *sched = scheds->GetSchedule(chan->GetChannelID());
+ if (sched != NULL) {
+ const cEvent *present = sched->GetPresentEvent();
+ if (present != NULL) {
+ if (chtid == PREMIERERADIO_TID) // Premiere
+ InfoTimeout = epg_premiere(present->Title(), present->Description(), present->StartTime(), present->EndTime());
+ else if (chtid == KDRADIO_TID) // Kabel Deutschland
+ InfoTimeout = epg_kdg(present->Description(), present->StartTime(), present->EndTime());
+ else // Unity Media Kabel
+ InfoTimeout = epg_unitymedia(present->Description(), present->StartTime(), present->EndTime());
+ InfoRequest = true;
+ }
+ else
+ dsyslog("radio: no event.present (Tid= %d, Apid= %d)", chtid, chan->Apid(0));
+ }
+ else
+ dsyslog("radio: no schedule (Tid= %d, Apid= %d)", chtid, chan->Apid(0));
+ }
+ }
+ // Artist/Title with external script?
+ else if (chan->Apid(0) > 0 && DoInfoReq) {
+ InfoTimeout = info_request(chtid, chan->Apid(0));
+ InfoRequest = (InfoTimeout > 0);
+ }
+ }
+ }
+ }
+
+ // temp. OSD-CloseTimeout
+ (RT_OsdTOTemp > 0) ? RT_OsdTOTemp -= 2 : RT_OsdTOTemp = 0; // in sec like this cycletime
+
+ // Radiotext-Autodisplay
+ if ((S_RtDispl == 2) && (RT_Info >= 0) && !RT_OsdTO && (RT_OsdTOTemp == 0) && RT_ReOpen && !Skins.IsOpen() && !cOsd::IsOpen())
+ cRemote::CallPlugin("radio");
+ }
+
+ if ((S_Verbose && 0x0f) >= 2)
+ printf("vdr-radio: background-checking ends\n");
+}
+
+
+// --- cMenuSetupRadio -------------------------------------------------------
+
+class cMenuSetupRadio : public cMenuSetupPage {
+private:
+ int newS_Activate;
+ int newS_StillPic;
+ int newS_HMEntry;
+ int newS_RtFunc;
+ int newS_RtOsdTitle;
+ int newS_RtOsdTags;
+ int newS_RtOsdPos;
+ int newS_RtOsdRows;
+ int newS_RtOsdLoop;
+ int newS_RtOsdTO;
+ int newS_RtSkinColor;
+ int newS_RtBgCol;
+ int newS_RtBgTra;
+ int newS_RtFgCol;
+ int newS_RtDispl;
+ int newS_RtMsgItems;
+ //int newS_RtpMemNo;
+ int newS_RassText;
+ int newS_ExtInfo;
+ const char *T_RtFunc[3];
+ const char *T_RtOsdTags[3];
+ const char *T_RtOsdPos[2];
+ const char *T_RtOsdLoop[2];
+ const char *T_RtBgColor[9];
+ const char *T_RtFgColor[9];
+ const char *T_RtDisplay[3];
+ const char *T_RtMsgItems[4];
+ const char *T_RassText[3];
+protected:
+ virtual void Store(void);
+public:
+ cMenuSetupRadio(void);
+};
+
+cMenuSetupRadio::cMenuSetupRadio(void)
+{
+ T_RtFunc[0] = tr("Off");
+ T_RtFunc[1] = tr("only Text");
+ T_RtFunc[2] = tr("Text+TagInfo");
+ T_RtOsdTags[0] = tr("Off");
+ T_RtOsdTags[1] = tr("only, if some");
+ T_RtOsdTags[2] = tr("always");
+ T_RtOsdPos[0] = tr("Top");
+ T_RtOsdPos[1] = tr("Bottom");
+ T_RtOsdLoop[0] = tr("latest at Top");
+ T_RtOsdLoop[1] = tr("latest at Bottom");
+ T_RtBgColor[0] = T_RtFgColor[0] = tr ("Black");
+ T_RtBgColor[1] = T_RtFgColor[1] = tr ("White");
+ T_RtBgColor[2] = T_RtFgColor[2] = tr ("Red");
+ T_RtBgColor[3] = T_RtFgColor[3] = tr ("Green");
+ T_RtBgColor[4] = T_RtFgColor[4] = tr ("Yellow");
+ T_RtBgColor[5] = T_RtFgColor[5] = tr ("Magenta");
+ T_RtBgColor[6] = T_RtFgColor[6] = tr ("Blue");
+ T_RtBgColor[7] = T_RtFgColor[7] = tr ("Cyan");
+ T_RtBgColor[8] = T_RtFgColor[8] = tr ("Transparent");
+ T_RtDisplay[0] = tr("Off");
+ T_RtDisplay[1] = tr("about MainMenu");
+ T_RtDisplay[2] = tr("Automatic");
+ T_RtMsgItems[0] = tr("Off");
+ T_RtMsgItems[1] = tr("only Taginfo");
+ T_RtMsgItems[2] = tr("only Text");
+ T_RtMsgItems[3] = tr("Text+TagInfo");
+ T_RassText[0] = tr("Off");
+ T_RassText[1] = tr("Rass only");
+ T_RassText[2] = tr("Rass+Text mixed");
+
+ newS_Activate = S_Activate;
+ newS_StillPic = S_StillPic;
+ newS_Activate = S_Activate;
+ newS_RtFunc = S_RtFunc;
+ newS_RtOsdTitle = S_RtOsdTitle;
+ newS_RtOsdTags = S_RtOsdTags;
+ newS_RtOsdPos = S_RtOsdPos;
+ newS_RtOsdRows = S_RtOsdRows;
+ newS_RtOsdLoop = S_RtOsdLoop;
+ newS_RtOsdTO = S_RtOsdTO;
+ newS_RtSkinColor = S_RtSkinColor;
+ newS_RtBgCol = S_RtBgCol;
+ newS_RtBgTra = S_RtBgTra;
+ newS_RtFgCol = S_RtFgCol;
+ newS_RtDispl = (S_RtDispl > 2 ? 2 : S_RtDispl);
+ newS_RtMsgItems = S_RtMsgItems;
+ //newS_RtpMemNo = S_RtpMemNo;
+ newS_RassText = S_RassText;
+ newS_ExtInfo = S_ExtInfo;
+
+ Add(new cMenuEditBoolItem( tr("Activate"), &newS_Activate));
+ Add(new cMenuEditBoolItem( tr("Use StillPicture-Function"), &newS_StillPic));
+ Add(new cMenuEditBoolItem( tr("Hide MainMenuEntry"), &newS_HMEntry));
+ Add(new cMenuEditStraItem( tr("RDSText Function"), &newS_RtFunc, 3, T_RtFunc));
+ Add(new cMenuEditStraItem( tr("RDSText OSD-Position"), &newS_RtOsdPos, 2, T_RtOsdPos));
+ Add(new cMenuEditBoolItem( tr("RDSText OSD-Titlerow"), &newS_RtOsdTitle));
+ Add(new cMenuEditIntItem( tr("RDSText OSD-Rows (1-5)"), &newS_RtOsdRows, 1, 5));
+ Add(new cMenuEditStraItem( tr("RDSText OSD-Scrollmode"), &newS_RtOsdLoop, 2, T_RtOsdLoop));
+ Add(new cMenuEditStraItem( tr("RDSText OSD-Taginfo"), &newS_RtOsdTags, 3, T_RtOsdTags));
+ Add(new cMenuEditBoolItem( tr("RDSText OSD-Skincolors used"), &newS_RtSkinColor));
+ if (newS_RtSkinColor == 0) {
+ Add(new cMenuEditStraItem( tr("RDSText OSD-Backgr.Color"), &newS_RtBgCol, 9, T_RtBgColor));
+ Add(new cMenuEditIntItem( tr("RDSText OSD-Backgr.Transp."), &newS_RtBgTra, 1, 255));
+ Add(new cMenuEditStraItem( tr("RDSText OSD-Foregr.Color"), &newS_RtFgCol, 8, T_RtFgColor));
+ }
+ Add(new cMenuEditIntItem( tr("RDSText OSD-Timeout (0-1440 min)"), &newS_RtOsdTO, 0, 1440));
+ Add(new cMenuEditStraItem( tr("RDSText OSD-Display"), &newS_RtDispl, 3, T_RtDisplay));
+ Add(new cMenuEditStraItem( tr("RDSText StatusMsg (lcdproc & co)"), &newS_RtMsgItems, 4, T_RtMsgItems));
+ //Add(new cMenuEditIntItem( tr("RDSplus Memorynumber (10-99)"), &newS_RtpMemNo, 10, 99));
+ Add(new cMenuEditStraItem( tr("RDSText Rass-Function"), &newS_RassText, 3, T_RassText));
+ Add(new cMenuEditBoolItem( tr("External Info-Request"), &newS_ExtInfo));
+}
+
+void cMenuSetupRadio::Store(void)
+{
+ SetupStore("Activate", S_Activate = newS_Activate);
+ SetupStore("UseStillPic", S_StillPic = newS_StillPic);
+ SetupStore("HideMenuEntry", S_HMEntry = newS_HMEntry);
+ SetupStore("RDSText-Function", S_RtFunc = newS_RtFunc);
+ SetupStore("RDSText-OsdTitle", S_RtOsdTitle = newS_RtOsdTitle);
+ SetupStore("RDSText-OsdTags", S_RtOsdTags = newS_RtOsdTags);
+ SetupStore("RDSText-OsdPosition", S_RtOsdPos = newS_RtOsdPos);
+ SetupStore("RDSText-OsdRows", S_RtOsdRows = newS_RtOsdRows);
+ SetupStore("RDSText-OsdLooping", S_RtOsdLoop = newS_RtOsdLoop);
+ SetupStore("RDSText-OsdSkinColor", S_RtSkinColor = newS_RtSkinColor);
+ SetupStore("RDSText-OsdBackgrColor", S_RtBgCol = newS_RtBgCol);
+ SetupStore("RDSText-OsdBackgrTrans", S_RtBgTra = newS_RtBgTra);
+ SetupStore("RDSText-OsdForegrColor", S_RtFgCol = newS_RtFgCol);
+ SetupStore("RDSText-OsdTimeout", S_RtOsdTO = newS_RtOsdTO);
+ SetupStore("RDSText-Display", S_RtDispl = newS_RtDispl);
+ SetupStore("RDSText-MsgItems", S_RtMsgItems = newS_RtMsgItems);
+ //SetupStore("RDSplus-MemNumber", S_RtpMemNo = newS_RtpMemNo);
+ SetupStore("RDSText-Rass", S_RassText = newS_RassText);
+ SetupStore("ExtInfo-Req", S_ExtInfo = newS_ExtInfo);
+}
+
+
+// --- cPluginRadio -------------------------------------------------------
+
+
+class cRadioImage;
+class cRadioAudio;
+
+class cPluginRadio : public cPlugin, cStatus {
+private:
+ // Add any member variables or functions you may need here.
+ bool ConfigDirParam;
+ bool DataDirParam;
+ bool LiveFileParam;
+ bool ReplayFileParam;
+ cRadioImage *radioImage;
+ cRadioAudio *radioAudio;
+public:
+ cPluginRadio(void);
+ virtual ~cPluginRadio();
+ 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 Stop(void);
+ virtual void Housekeeping(void);
+ virtual void MainThreadHook(void) { }
+ virtual cString Active(void) { return NULL; }
+ virtual const char *MainMenuEntry(void) { return (S_Activate==0 || S_RtFunc==0 || S_RtDispl==0 || S_HMEntry ? NULL : tr(MAINMENUENTRY)); }
+ virtual cOsdObject *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ virtual bool Service(const char *Id, void *Data);
+ virtual const char **SVDRPHelpPages(void);
+ virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
+protected:
+ virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView);
+ virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On);
+};
+
+cPluginRadio::cPluginRadio(void)
+{
+ // Initialize any member variables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PROADUCE ANY OUTPUT!
+
+ radioImage = 0;
+ radioAudio = 0;
+
+ ConfigDirParam = false;
+ DataDirParam = false;
+ LiveFileParam = false;
+ ReplayFileParam = false;
+
+ rt_color[0] = 0xFF000000; //Black
+ rt_color[1] = 0xFFFCFCFC; //White
+ rt_color[2] = 0xFFFC1414; //Red
+ rt_color[3] = 0xFF24FC24; //Green
+ rt_color[4] = 0xFFFCC024; //Yellow
+ rt_color[5] = 0xFFB000FC; //Magenta
+ rt_color[6] = 0xFF0000FC; //Blue
+ rt_color[7] = 0xFF00FCFC; //Cyan
+ rt_color[8] = 0x00000000; //Transparent
+}
+
+cPluginRadio::~cPluginRadio()
+{
+ // Clean up after yourself!
+ if (ConfigDir) free(ConfigDir);
+ if (DataDir) free(DataDir);
+ if (LiveFile) free(LiveFile);
+ if (ReplayFile) free(ReplayFile);
+
+ cRadioCheck::Exit();
+ radioImage->Exit();
+}
+
+
+const char *cPluginRadio::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return " -f dir, --files=dir use dir as image directory (default: <vdrconfig>/plugins/radio)\n"
+ " -d dir, --data=dir use dir as temp. data directory (default: <vdrconfig>/plugins/radio)\n"
+ " -l file, --live=file use file as default mpegfile in livemode (default: <dir>/radio.mpg)\n"
+ " -r file, --replay=file use file as default mpegfile in replaymode (default: <dir>/replay.mpg)\n"
+ " -e 1, --encrypted=1 use transfermode/backgroundimage @ encrypted radiochannels \n"
+ " -v level, --verbose=level set verbose level (default = 1, 0 = Off, 1 = RDS-Text+Tags, \n"
+ " 2 = +RDS-Telegram/Debug, 3 = +RawData 0xfd, \n"
+ " += 16 = Rass-Info, +=32 = TMC-Info) \n";
+}
+
+bool cPluginRadio::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+
+ static struct option long_options[] = {
+ { "files", required_argument, NULL, 'f' },
+ { "data", required_argument, NULL, 'd' },
+ { "live", required_argument, NULL, 'l' },
+ { "replay", required_argument, NULL, 'r' },
+ { "encrypted", required_argument, NULL, 'e' },
+ { "verbose", required_argument, NULL, 'v' },
+ { NULL }
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "f:d:l:r:e:v:", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'f':
+ printf("vdr-radio: arg files-dir = %s\n", optarg);
+ ConfigDir = strdup(optarg);
+ ConfigDirParam = true;
+ break;
+ case 'd':
+ printf("vdr-radio: arg data-dir = %s\n", optarg);
+ DataDir = strdup(optarg);
+ DataDirParam = true;
+ break;
+ case 'l':
+ printf("vdr-radio: arg live-mpeg = %s\n", optarg);
+ LiveFile = strdup(optarg);
+ LiveFileParam = true;
+ break;
+ case 'r':
+ printf("vdr-radio: arg replay-mpeg = %s\n", optarg);
+ ReplayFile = strdup(optarg);
+ ReplayFileParam = true;
+ break;
+ case 'v':
+ printf("vdr-radio: arg verbose = %s\n", optarg);
+ if (isnumber(optarg))
+ S_Verbose = atoi(optarg);
+ break;
+ case 'e':
+ printf("vdr-radio: arg encrypted = %s\n", optarg);
+ if (isnumber(optarg))
+ S_Encrypted = atoi(optarg);
+ break;
+ default:
+ printf("vdr-radio: arg char = %c\n", c);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cPluginRadio::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+ printf("vdr-radio: Radio-Plugin Backgr.Image/RDS-Text starts...\n");
+
+ radioImage = new cRadioImage;
+ if (!radioImage)
+ return false;
+ radioImage->Init();
+
+ radioAudio = new cRadioAudio;
+ if (!radioAudio)
+ return false;
+
+ if (!ConfigDirParam)
+ ConfigDir = strdup(ConfigDirectory(Name()));
+ if (!DataDirParam) {
+ DataDir = strdup("/tmp/vdr-radio.XXXXXX");
+ mkdtemp(DataDir);
+ }
+ if (!LiveFileParam)
+ asprintf(&LiveFile, "%s/radio.mpg", ConfigDir);
+ if (!ReplayFileParam)
+ asprintf(&ReplayFile, "%s/replay.mpg", ConfigDir);
+
+ cRadioCheck::Init();
+
+ return true;
+}
+
+void cPluginRadio::Stop(void)
+{
+ cRadioCheck::Exit();
+
+ if (IsRadioOrReplay > 0)
+ radioAudio->DisableRadioTextProcessing();
+
+ radioImage->Exit();
+}
+
+void cPluginRadio::Housekeeping(void)
+{
+ // Perform any cleanup or other regular tasks.
+}
+
+cOsdObject *cPluginRadio::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+/* if (!cDevice::PrimaryDevice()->Transferring() && !cDevice::PrimaryDevice()->Replaying()) {
+ //cRemote::CallPlugin("radio"); // try again later <-- disabled, looping if activate over menu @ tv in dvb-livemode
+ } */
+ if (S_Activate > 0 && S_RtFunc > 0 && S_RtDispl > 0 && IsRadioOrReplay > 0) {
+ if (!RTplus_Osd) {
+ cRadioTextOsd *rtosd = new cRadioTextOsd();
+ return rtosd;
+ }
+ else {
+ cRTplusOsd *rtposd = new cRTplusOsd();
+ return rtposd;
+ }
+ }
+
+ return NULL;
+}
+
+cMenuSetupPage *cPluginRadio::SetupMenu(void)
+{
+ // Return a setup menu in case the plugin supports one.
+ return new cMenuSetupRadio;
+}
+
+bool cPluginRadio::SetupParse(const char *Name, const char *Value)
+{
+ // Parse your own setup parameters and store their values.
+ if (!strcasecmp(Name, "Activate")) S_Activate = atoi(Value);
+ else if (!strcasecmp(Name, "UseStillPic")) S_StillPic = atoi(Value);
+ else if (!strcasecmp(Name, "HideMenuEntry")) S_HMEntry = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-Function")) S_RtFunc = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdTitle")) S_RtOsdTitle = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdTags")) S_RtOsdTags = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdPosition")) S_RtOsdPos = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdRows")) {
+ S_RtOsdRows = atoi(Value);
+ if (S_RtOsdRows > 5) S_RtOsdRows = 5;
+ }
+ else if (!strcasecmp(Name, "RDSText-OsdLooping")) S_RtOsdLoop = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdSkinColor")) S_RtSkinColor = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdBackgrColor")) S_RtBgCol = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdBackgrTrans")) S_RtBgTra = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdForegrColor")) S_RtFgCol = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-OsdTimeout")) {
+ S_RtOsdTO = atoi(Value);
+ if (S_RtOsdTO > 1440) S_RtOsdTO = 1440;
+ }
+ else if (!strcasecmp(Name, "RDSText-Display")) S_RtDispl = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-MsgItems")) S_RtMsgItems = atoi(Value);
+ //else if (!strcasecmp(Name, "RDSplus-MemNumber")) S_RtpMemNo = atoi(Value);
+ else if (!strcasecmp(Name, "RDSText-Rass")) S_RassText = atoi(Value);
+ else if (!strcasecmp(Name, "ExtInfo-Req")) S_ExtInfo = atoi(Value);
+ else
+ return false;
+
+ return true;
+}
+
+bool cPluginRadio::Service(const char *Id, void *Data)
+{
+ if (strcmp(Id,"RadioTextService-v1.0") == 0 && S_Activate > 0 && S_RtFunc >= 1) {
+ if (Data) {
+ RadioTextService_v1_0 *data = (RadioTextService_v1_0*)Data;
+ data->rds_pty = RT_PTY;
+ data->rds_info = (RT_Info < 0) ? 0 : RT_Info;
+ int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
+ data->rds_text = RT_Text[ind];
+ data->rds_title = RTP_Title;
+ data->rds_artist = RTP_Artist;
+ struct tm tm_store;
+ data->title_start = localtime_r(&RTP_Starttime, &tm_store);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+const char **cPluginRadio::SVDRPHelpPages(void)
+{
+ static const char *HelpPages[] = {
+ "RTINFO\n"
+ " Print the radiotext information.",
+ "RTCLOSE\n"
+ " Close the radiotext-osd,\n"
+ " Reopen can only be done over menu or channelswitch.",
+ "RTTCLOSE\n"
+ " Close the radiotext-osd temporarily,\n"
+ " Reopen will be done after osd-messagetimeout.",
+ NULL
+ };
+
+ return HelpPages;
+}
+
+cString cPluginRadio::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
+{
+ if (strcasecmp(Command, "RTINFO") == 0) {
+ // we use the default reply code here
+ if (RT_Info == 2) {
+ int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
+ return cString::sprintf(" Radiotext: %s\n RT-Title : %s\n RT-Artist: %s\n", RT_Text[ind], RTP_Title, RTP_Artist);
+ }
+ else if (RT_Info == 1) {
+ int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
+ return cString::sprintf(" Radiotext: %s\n", RT_Text[ind]);
+ }
+ else
+ return cString::sprintf(" Radiotext not available (yet)\n");
+ }
+ else if (strcasecmp(Command, "RTCLOSE") == 0) {
+ // we use the default reply code here
+ if (RT_OsdTO)
+ return cString::sprintf("RT-OSD already closed");
+ else {
+ RT_OsdTO = true;
+ return cString::sprintf("RT-OSD will be closed now");
+ }
+ }
+ else if (strcasecmp(Command, "RTTCLOSE") == 0) {
+ // we use the default reply code here
+ RT_OsdTOTemp = 2 * Setup.OSDMessageTime;
+ return cString::sprintf("RT-OSD will be temporarily closed");
+ }
+
+ return NULL;
+}
+
+void cPluginRadio::ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView)
+{
+ if (Device != cDevice::PrimaryDevice()) return;
+
+ IsRadioOrReplay = Radio_CA = 0;
+ radioAudio->DisableRadioTextProcessing();
+ InfoTimeout = 3;
+
+ if (S_Activate == false) return;
+
+ char *image;
+ if (cDevice::CurrentChannel() == ChannelNumber) {
+ chan = ChannelNumber ? Channels.GetByNumber(ChannelNumber) : NULL;
+ if (chan != NULL && chan->Vpid() == 0 && chan->Apid(0) > 0) {
+ asprintf(&image, "%s/%s.mpg", ConfigDir, chan->Name());
+ if (!file_exists(image)) {
+ dsyslog("radio: channel-image not found '%s' (Channelname= %s)", image, chan->Name());
+ free(image);
+ asprintf(&image, "%s", LiveFile);
+ if (!file_exists(image))
+ dsyslog("radio: live-image not found '%s' (Channelname= %s)", image, chan->Name());
+ }
+ dsyslog("radio: [ChannelSwitch # Apid= %d, Ca= %d] channelname '%s', use image '%s'", chan->Apid(0), chan->Ca(0), chan->Name(), image);
+ if ((Radio_CA = chan->Ca(0)) == 0 || S_Encrypted == 1)
+ cDevice::PrimaryDevice()->ForceTransferMode();
+ radioImage->SetBackgroundImage(image);
+ radioAudio->EnableRadioTextProcessing(chan->Name(), chan->Apid(0), false);
+ free(image);
+ IsRadioOrReplay = 1;
+ DoInfoReq = (S_ExtInfo > 0);
+ }
+ }
+}
+
+void cPluginRadio::Replaying(const cControl *Control, const char *Name, const char *FileName, bool On)
+{
+ IsRadioOrReplay = 0;
+ radioAudio->DisableRadioTextProcessing();
+
+ if (S_Activate == false) return;
+
+ bool isRadio = false;
+
+ if (On && FileName != NULL) {
+ char *vdrfile;
+ // check VDR PES-Recordings
+ asprintf(&vdrfile, "%s/001.vdr", FileName);
+ if (file_exists(vdrfile)) {
+ cFileName fn(FileName, false, true, true);
+ cUnbufferedFile *f = fn.Open();
+ if (f) {
+ uchar b[4] = { 0x00, 0x00, 0x00, 0x00 };
+ ReadFrame(f, b, sizeof (b), sizeof (b));
+ fn.Close();
+ isRadio = (b[0] == 0x00) && (b[1] == 0x00) && (b[2] == 0x01) && (0xc0 <= b[3] && b[3] <= 0xdf);
+ }
+ }
+ // check VDR TS-Recordings
+ asprintf(&vdrfile, "%s/info", FileName);
+ if (file_exists(vdrfile)) {
+ cRecordingInfo rfi(FileName);
+ if (rfi.Read()) {
+ if (rfi.FramesPerSecond() > 0 && rfi.FramesPerSecond() < 18) // max. seen 13.88 @ ARD-RadioTP 320k
+ isRadio = true;
+ }
+ }
+ free(vdrfile);
+ }
+
+ if (isRadio) {
+ if (!file_exists(ReplayFile))
+ dsyslog("radio: replay-image not found '%s'", ReplayFile);
+ else
+ radioImage->SetBackgroundImage(ReplayFile);
+ radioAudio->EnableRadioTextProcessing(Name, 0, true);
+ IsRadioOrReplay = 2;
+ }
+}
+
+
+VDRPLUGINCREATOR(cPluginRadio); // Don't touch this!
diff --git a/radioaudio.c b/radioaudio.c
new file mode 100644
index 0000000..8c6a2dc
--- /dev/null
+++ b/radioaudio.c
@@ -0,0 +1,2806 @@
+/*
+ * radioaudio.c - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include <vdr/remote.h>
+#include <vdr/status.h>
+#include <vdr/plugin.h>
+#include "radioaudio.h"
+#include "radioskin.h"
+#include "radiotools.h"
+#include <math.h>
+
+// OSD-Symbols
+#include "symbols/rds.xpm"
+#include "symbols/arec.xpm"
+#include "symbols/rass.xpm"
+#include "symbols/radio.xpm"
+#include "symbols/index.xpm"
+#include "symbols/marker.xpm"
+#include "symbols/page1.xpm"
+#include "symbols/pages2.xpm"
+#include "symbols/pages3.xpm"
+#include "symbols/pages4.xpm"
+#include "symbols/no0.xpm"
+#include "symbols/no1.xpm"
+#include "symbols/no2.xpm"
+#include "symbols/no3.xpm"
+#include "symbols/no4.xpm"
+#include "symbols/no5.xpm"
+#include "symbols/no6.xpm"
+#include "symbols/no7.xpm"
+#include "symbols/no8.xpm"
+#include "symbols/no9.xpm"
+#include "symbols/bok.xpm"
+#include "symbols/pageE.xpm"
+
+
+// Radiotext
+int RTP_ItemToggle = 1, RTP_TToggle = 0;
+bool RT_MsgShow = false, RT_PlusShow = false;
+bool RT_Replay = false;
+char *RT_Titel, *RTp_Titel;
+rtp_classes rtp_content;
+// RDS rest
+bool RDS_PSShow = false;
+int RDS_PSIndex = 0;
+char RDS_PSText[12][9];
+char RDS_PTYN[9];
+bool RdsLogo = false;
+// plugin audiorecorder service
+bool ARec_Receive = false, ARec_Record = false;
+// Rass ...
+int Rass_Show = -1; // -1=No, 0=Yes, 1=display
+int Rass_Archiv = -1; // -1=Off, 0=Index, 1000-9990=Slidenr.
+bool Rass_Flags[11][4]; // Slides+Gallery existent
+// ... Gallery (1..999)
+#define RASS_GALMAX 999
+bool Rass_Gallery[RASS_GALMAX+1];
+int Rass_GalStart, Rass_GalEnd, Rass_GalCount, Rass_SlideFoto;
+
+cRadioImage *RadioImage;
+cRDSReceiver *RDSReceiver;
+cRadioAudio *RadioAudio;
+cRadioTextOsd *RadioTextOsd;
+
+
+// RDS-Chartranslation: 0x80..0xff
+unsigned char rds_addchar[128] = {
+ 0xe1, 0xe0, 0xe9, 0xe8, 0xed, 0xec, 0xf3, 0xf2,
+ 0xfa, 0xf9, 0xd1, 0xc7, 0x8c, 0xdf, 0x8e, 0x8f,
+ 0xe2, 0xe4, 0xea, 0xeb, 0xee, 0xef, 0xf4, 0xf6,
+ 0xfb, 0xfc, 0xf1, 0xe7, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xaa, 0xa1, 0xa9, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xa3, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xba, 0xb9, 0xb2, 0xb3, 0xb1, 0xa1, 0xb6, 0xb7,
+ 0xb5, 0xbf, 0xf7, 0xb0, 0xbc, 0xbd, 0xbe, 0xa7,
+ 0xc1, 0xc0, 0xc9, 0xc8, 0xcd, 0xcc, 0xd3, 0xd2,
+ 0xda, 0xd9, 0xca, 0xcb, 0xcc, 0xcd, 0xd0, 0xcf,
+ 0xc2, 0xc4, 0xca, 0xcb, 0xce, 0xcf, 0xd4, 0xd6,
+ 0xdb, 0xdc, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xc3, 0xc5, 0xc6, 0xe3, 0xe4, 0xdd, 0xd5, 0xd8,
+ 0xde, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xf0,
+ 0xe3, 0xe5, 0xe6, 0xf3, 0xf4, 0xfd, 0xf5, 0xf8,
+ 0xfe, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+const char* ptynr2string(int nr)
+{
+ switch (nr) {
+ // Source: http://www.ebu.ch/trev_255-beale.pdf
+ case 0: return tr("unknown program type");
+ case 1: return tr("News");
+ case 2: return tr("Current affairs");
+ case 3: return tr("Information");
+ case 4: return tr("Sport");
+ case 5: return tr("Education");
+ case 6: return tr("Drama");
+ case 7: return tr("Culture");
+ case 8: return tr("Science");
+ case 9: return tr("Varied");
+ case 10: return tr("Pop music");
+ case 11: return tr("Rock music");
+ case 12: return tr("M.O.R. music");
+ case 13: return tr("Light classical");
+ case 14: return tr("Serious classical");
+ case 15: return tr("Other music");
+ // 16-30 "Spares"
+ case 31: return tr("Alarm");
+ default: return "?";
+ }
+}
+
+// announce text/items for lcdproc & other
+void radioStatusMsg(void)
+{
+ if (!RT_MsgShow || S_RtMsgItems <= 0)
+ return;
+
+ if (S_RtMsgItems >= 2) {
+ char temp[100];
+ int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
+ strcpy(temp, RT_Text[ind]);
+ cStatus::MsgOsdTextItem(rtrim(temp), false);
+ }
+
+ if ((S_RtMsgItems == 1 || S_RtMsgItems >= 3) && ((S_RtOsdTags == 1 && RT_PlusShow) || S_RtOsdTags >= 2)) {
+ struct tm tm_store;
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ cStatus::MsgOsdProgramme(mktime(ts), RTP_Title, RTP_Artist, 0, NULL, NULL);
+ }
+}
+
+
+// --- cRadioImage -------------------------------------------------------
+
+cRadioImage::cRadioImage(void)
+ : cThread("radioimage")
+{
+ imagepath = 0;
+ imageShown = false;
+ RadioImage = this;
+}
+
+cRadioImage::~cRadioImage() {
+ if (Running())
+ Stop();
+ free(imagepath);
+}
+
+void cRadioImage::Init(void) {
+ RadioImage->Start();
+}
+
+void cRadioImage::Exit(void) {
+ if (RadioImage != NULL) {
+ RadioImage->Stop();
+ DELETENULL(RadioImage);
+ }
+}
+
+void cRadioImage::Stop(void) {
+ Cancel(2);
+}
+
+void cRadioImage::Action(void)
+{
+ if ((S_Verbose && 0x0f) >= 2)
+ printf("vdr-radio: image-showing starts\n");
+
+ while (Running()) {
+ cCondWait::SleepMs(333);
+ if ((IsRadioOrReplay == 1) && imagepath && !imageShown) { // only live $20090905
+ imageShown = true;
+ Show(imagepath);
+ }
+ }
+
+ if ((S_Verbose && 0x0f) >= 2)
+ printf("vdr-radio: image-showing ends\n");
+}
+
+void cRadioImage::Show(const char *file)
+{
+ uchar *buffer;
+ int fd;
+ struct stat st;
+ struct video_still_picture sp;
+ if ((fd = open (file, O_RDONLY)) >= 0) {
+ fstat (fd, &st);
+ sp.iFrame = (char *) malloc (st.st_size);
+ if (sp.iFrame) {
+ sp.size = st.st_size;
+ if (read (fd, sp.iFrame, sp.size) > 0) {
+ buffer = (uchar *) sp.iFrame;
+ if (S_StillPic > 0)
+ cDevice::PrimaryDevice()->StillPicture(buffer, sp.size);
+ else {
+ for (int i = 1; i <= 25; i++)
+ send_pes_packet (buffer, sp.size, i);
+ }
+ }
+ free (sp.iFrame);
+ }
+ else {}
+ close (fd);
+ }
+ else {}
+}
+
+void cRadioImage::send_pes_packet(unsigned char *data, int len, int timestamp)
+{
+#define PES_MAX_SIZE 2048
+ int ptslen = timestamp ? 5 : 1;
+ static unsigned char pes_header[PES_MAX_SIZE];
+ pes_header[0] = pes_header[1] = 0;
+ pes_header[2] = 1;
+ pes_header[3] = 0xe0;
+
+ while(len > 0) {
+ int payload_size = len;
+ if(6 + ptslen + payload_size > PES_MAX_SIZE)
+ payload_size = PES_MAX_SIZE - (6 + ptslen);
+ pes_header[4] = (ptslen + payload_size) >> 8;
+ pes_header[5] = (ptslen + payload_size) & 255;
+ if (ptslen == 5) {
+ int x;
+ x = (0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1;
+ pes_header[8] = x;
+ x = ((((timestamp >> 15) & 0x7fff) << 1) | 1);
+ pes_header[7] = x >> 8;
+ pes_header[8] = x & 255;
+ x = ((((timestamp) & 0x7fff) < 1) | 1);
+ pes_header[9] = x >> 8;
+ pes_header[10] = x & 255;
+ }
+ else
+ pes_header[6] = 0x0f;
+
+ memcpy(&pes_header[6 + ptslen], data, payload_size);
+ cDevice::PrimaryDevice()->PlayPes(pes_header, 6 + ptslen + payload_size);
+ len -= payload_size;
+ data += payload_size;
+ ptslen = 1;
+ }
+}
+
+void cRadioImage::SetBackgroundImage(const char *Image)
+{
+ free(imagepath);
+ imagepath = 0;
+
+ if (Image) {
+ imageShown = false;
+ asprintf(&imagepath, "%s", Image);
+ }
+}
+
+
+// --- cRDSReceiver ------------------------------------------------------------
+
+cRDSReceiver::cRDSReceiver(int Pid)
+{
+ dsyslog("radio: additional RDS-Receiver starts on Pid=%d", Pid);
+
+ pid = Pid;
+ rt_start = rt_bstuff = false;
+}
+
+cRDSReceiver::~cRDSReceiver()
+{
+ dsyslog("radio: additional RDS-Receiver stopped");
+}
+
+void cRDSReceiver::Receive(uchar *Data, int Length)
+{
+ const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
+ static unsigned char mtext[mframel+1];
+ static int index;
+ static int mec = 0;
+
+ // check TS-Size, -Sync, PID, Payload
+ if (Length != TS_SIZE || Data[0] != 0x47 || pid != ((Data[1] & 0x1f)<<8)+Data[2] || !(Data[3] & 0x10))
+ return;
+
+ int offset;
+ if (Data[1] & 0x40) { // 1.TS-Frame, payload-unit-start
+ offset = (Data[3] & 0x20) ? Data[4] + 11 : 10; // Header + ADFL + 6 byte: PES-Startcode, -StreamID, -PacketLength
+ if (Data[offset-3] == 0xbd) { // StreamID = Private stream 1 (for rds)
+ offset += 3; // 3 byte: Extension + Headerlength
+ offset += Data[offset-1];
+ }
+ else
+ return;
+ }
+ else
+ offset = (Data[3] & 0x20) ? Data[4] + 5 : 4; // Header + ADFL
+
+ if (TS_SIZE-offset <= 0)
+ return;
+
+ // print TS-RawData with RDS
+ if ((S_Verbose & 0x0f) >= 3) {
+ printf("\n\nTS-Data(%d): ", Length);
+ for (int a=0; a<Length; a++)
+ printf("%02x ", Data[a]);
+ printf("(End)\n\n");
+ }
+
+ for (int i = 0, val = 0; i < (TS_SIZE-offset); i++) {
+ val = Data[offset+i];
+
+ if (val == 0xfe) { // Start
+ index = -1;
+ rt_start = true;
+ rt_bstuff = false;
+ mec = 0;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("\nRDS-Start: ");
+ }
+
+ if (rt_start) {
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("%02x ", val);
+ // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff
+ if (rt_bstuff) {
+ switch (val) {
+ case 0x00: mtext[index] = 0xfd; break;
+ case 0x01: mtext[index] = 0xfe; break;
+ case 0x02: mtext[index] = 0xff; break;
+ default: mtext[++index] = val; // should never be
+ }
+ rt_bstuff = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(Bytestuffing -> %02x) ", mtext[index]);
+ }
+ else
+ mtext[++index] = val;
+ if (val == 0xfd && index > 0) // stuffing found
+ rt_bstuff = true;
+
+ // early check for used MEC
+ if (index == 5) {
+ //mec = val;
+ switch (val) {
+ case 0x0a: // RT
+ case 0x46: // ODA-Data
+ case 0x07: // PTY
+ case 0x3e: // PTYN
+ case 0x30: // TMC
+ case 0x02: mec = val; // PS
+ RdsLogo = true;
+ break;
+ default: rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("[RDS-MEC '%02x' not used -> End]\n", val);
+ }
+ }
+ if (index >= mframel) { // max. rdslength, garbage ?
+ rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(RDS-Error: too long, garbage ?)\n");
+ }
+ }
+
+ if (rt_start && val == 0xff) { // End
+ rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(RDS-End)\n");
+ if (index < 9) { // min. rdslength, garbage ?
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error: too short -> garbage ?\n");
+ }
+ else {
+ // crc16-check
+ unsigned short crc16 = crc16_ccitt(mtext, index-3, true);
+ if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]);
+ }
+ else {
+ switch (mec) {
+ case 0x0a: RadioAudio->RadiotextDecode(mtext, index); // Radiotext
+ break;
+ case 0x46: switch ((mtext[7]<<8)+mtext[8]) { // ODA-ID
+ case 0x4bd7: RadioAudio->RadiotextDecode(mtext, index); // RT+
+ break;
+ case 0x0d45:
+ case 0xcd46: if ((S_Verbose & 0x20) > 0) {
+ unsigned char tmc[6]; // TMC Alert-C
+ int i;
+ for (i=9; i<=(index-3); i++)
+ tmc[i-9] = mtext[i];
+ tmc_parser(tmc, i-8);
+ }
+ break;
+ default: if ((S_Verbose & 0x0f) >= 2)
+ printf("[RDS-ODA AID '%02x%02x' not used -> End]\n", mtext[7], mtext[8]);
+ }
+ break;
+ case 0x07: RT_PTY = mtext[8]; // PTY
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY));
+ break;
+ case 0x3e: RadioAudio->RDS_PsPtynDecode(true, mtext, index); // PTYN
+ break;
+ case 0x02: RadioAudio->RDS_PsPtynDecode(false, mtext, index); // PS
+ break;
+ case 0x30: if ((S_Verbose & 0x20) > 0) { // TMC Alert-C
+ unsigned char tmc[6];
+ int i;
+ for (i=7; i<=(index-3); i++)
+ tmc[i-7] = mtext[i];
+ tmc_parser(tmc, i-6);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ }
+}
+
+
+// --- cRadioAudio -------------------------------------------------------------
+
+cRadioAudio::cRadioAudio()
+ : cAudio()
+ , enabled(false)
+ , first_packets(0)
+{
+ RadioAudio = this;
+ dsyslog("radio: new cRadioAudio");
+}
+
+cRadioAudio::~cRadioAudio()
+{
+ dsyslog("radio: delete cRadioAudio");
+}
+
+/* for old pes-recordings */
+void cRadioAudio::Play(const uchar *Data, int Length, uchar Id)
+{
+ if (!enabled)
+ return;
+
+ if (Id < 0xc0 || Id > 0xdf)
+ return;
+
+ // Rass-Images Slideshow
+ if (S_RassText > 0 && Rass_Archiv == -1 && Rass_Show == 1) {
+ Rass_Show = 0;
+ char *image;
+ asprintf(&image, "%s/Rass_show.mpg", DataDir);
+ RadioImage->SetBackgroundImage(image);
+ free(image);
+ }
+
+ // check Audo-Bitrate
+ if (S_RtFunc < 1)
+ return;
+ if (first_packets < 3) {
+ first_packets++;
+ if (first_packets == 3)
+ bitrate = audiobitrate(Data);
+ return;
+ }
+
+ // check Radiotext-PES
+ if (Radio_CA == 0)
+ RadiotextCheckPES(Data, Length);
+}
+
+void cRadioAudio::PlayTs(const uchar *Data, int Length)
+{
+ if (!enabled)
+ return;
+
+ // Rass-Images Slideshow
+ if (S_RassText > 0 && Rass_Archiv == -1 && Rass_Show == 1) {
+ Rass_Show = 0;
+ char *image;
+ asprintf(&image, "%s/Rass_show.mpg", DataDir);
+ RadioImage->SetBackgroundImage(image);
+ free(image);
+ }
+
+ if (S_RtFunc < 1)
+ return;
+ if (first_packets < 99) {
+ first_packets++;
+ return;
+ }
+
+ // check Radiotext-TS
+ if (Radio_CA == 0)
+ RadiotextCheckTS(Data, Length);
+}
+
+/* for old pes-recordings */
+void cRadioAudio::RadiotextCheckPES(const uchar *data, int len)
+{
+ const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
+ static unsigned char mtext[mframel+1];
+ static bool rt_start = false, rt_bstuff=false;
+ static int index;
+ static int mec = 0;
+
+ int offset = 0;
+ while (true) {
+
+ int pesl = (offset+5 < len) ? (data[offset+4] << 8) + data[offset+5] + 6 : -1;
+ if (pesl <= 0 || offset+pesl > len)
+ return;
+
+ offset += pesl;
+ int rdsl = data[offset-2]; // RDS DataFieldLength
+ // RDS DataSync = 0xfd @ end
+ if (data[offset-1] == 0xfd && rdsl > 0) {
+ // print RawData with RDS-Info
+ if ((S_Verbose & 0x0f) >= 3) {
+ printf("\n\nPES-Data(%d/%d): ", pesl, len);
+ for (int a=offset-pesl; a<offset; a++)
+ printf("%02x ", data[a]);
+ printf("(End)\n\n");
+ }
+
+ for (int i = offset-3, val; i > offset-3-rdsl; i--) { // <-- data reverse, from end to start
+ val = data[i];
+
+ if (val == 0xfe) { // Start
+ index = -1;
+ rt_start = true;
+ rt_bstuff = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("\nRDS-Start: ");
+ }
+
+ if (rt_start) {
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("%02x ", val);
+ // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff
+ if (rt_bstuff) {
+ switch (val) {
+ case 0x00: mtext[index] = 0xfd; break;
+ case 0x01: mtext[index] = 0xfe; break;
+ case 0x02: mtext[index] = 0xff; break;
+ default: mtext[++index] = val; // should never be
+ }
+ rt_bstuff = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(Bytestuffing -> %02x) ", mtext[index]);
+ }
+ else
+ mtext[++index] = val;
+ if (val == 0xfd && index > 0) // stuffing found
+ rt_bstuff = true;
+ // early check for used MEC
+ if (index == 5) {
+ //mec = val;
+ switch (val) {
+ case 0x0a: // RT
+ case 0x46: // ODA-Data
+ case 0xda: // Rass
+ case 0x07: // PTY
+ case 0x3e: // PTYN
+ case 0x30: // TMC
+ case 0x02: mec = val; // PS
+ RdsLogo = true;
+ break;
+ default: rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("[RDS-MEC '%02x' not used -> End]\n", val);
+ }
+ }
+ if (index >= mframel) { // max. rdslength, garbage ?
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error(PES): too long, garbage ?\n");
+ rt_start = false;
+ }
+ }
+
+ if (rt_start && val == 0xff) { // End
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(RDS-End)\n");
+ rt_start = false;
+ if (index < 9) { // min. rdslength, garbage ?
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error(PES): too short -> garbage ?\n");
+ }
+ else {
+ // crc16-check
+ unsigned short crc16 = crc16_ccitt(mtext, index-3, true);
+ if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error(PES): wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]);
+ }
+ else {
+ switch (mec) {
+ case 0x0a: RadiotextDecode(mtext, index); // Radiotext
+ break;
+ case 0x46: switch ((mtext[7]<<8)+mtext[8]) { // ODA-ID
+ case 0x4bd7: RadioAudio->RadiotextDecode(mtext, index); // RT+
+ break;
+ case 0x0d45:
+ case 0xcd46: if ((S_Verbose & 0x20) > 0) {
+ unsigned char tmc[6]; // TMC Alert-C
+ int i;
+ for (i=9; i<=(index-3); i++)
+ tmc[i-9] = mtext[i];
+ tmc_parser(tmc, i-8);
+ }
+ break;
+ default: if ((S_Verbose & 0x0f) >= 2)
+ printf("[RDS-ODA AID '%02x%02x' not used -> End]\n", mtext[7], mtext[8]);
+ }
+ break;
+ case 0x07: RT_PTY = mtext[8]; // PTY
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY));
+ break;
+ case 0x3e: RDS_PsPtynDecode(true, mtext, index); // PTYN
+ break;
+ case 0x02: RDS_PsPtynDecode(false, mtext, index); // PS
+ break;
+ case 0xda: RassDecode(mtext, index); // Rass
+ break;
+ case 0x30: if ((S_Verbose & 0x20) > 0) { // TMC Alert-C
+ unsigned char tmc[6];
+ int i;
+ for (i=7; i<=(index-3); i++)
+ tmc[i-7] = mtext[i];
+ tmc_parser(tmc, i-6);
+ }
+ }
+ }
+ }
+ }
+
+ }
+ }
+ }
+}
+
+void cRadioAudio::RadiotextCheckTS(const uchar *data, int len)
+{
+ static int pesfound = 0;
+ const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
+ static unsigned char mtext[mframel+1], lastframe[TS_SIZE-4];
+ static int rt_start = 0, rt_bstuff = 0;
+ static int index;
+ static int mec = 0;
+ int i, ii, val;
+
+ /* TS-Frame && Payload, correct AudioPID ? */
+ if (data[0] != 0x47 || !(data[3] & 0x10)) {// || audiopid != ((data[1] & 0x1f)<<8) + data[2])) {
+ pesfound = 0;
+ return;
+ }
+
+ if ((S_Verbose & 0x0f) >= 3) {
+ printf("\n\nTS-Data: ");
+ for (int a=0; a<len; a++)
+ printf("%02x ", data[a]);
+ printf("(TS-End)\n\n");
+ }
+
+ int offset = TS_SIZE - 1;
+ int rdsl = 0, afdl = 0;
+ if ((data[1] & 0x40) == 0x40) { // 1.TS-Frame
+ offset = ((data[3] & 0x20)>>4) ? data[4] + 5 : 4; // Header+ADFL
+ if (data[offset] == 0x00 && data[offset+1] == 0x00 && data[offset+2] == 0x01 && // PES-Startcode
+ data[offset+3] >= 0xc0 && data[offset+3] <= 0xdf) { // PES-Audiostream MP1/2
+ pesfound = 1;
+ if (!bratefound) {
+ bitrate = audiobitrate(data+offset);
+ bratefound = true;
+ }
+ return;
+ }
+ }
+ // RDS DataSync = 0xfd @ audio-end
+ else if (pesfound && data[3] == 0x3f && data[offset] == 0xfd) { // last TS-Frame
+ rdsl = data[offset-1];
+ pesfound = 0;
+ }
+ else if (pesfound) { // TS-Frames between
+ afdl = ((data[3] & 0x20)>>4) ? data[4] + 1 : 0; // AdaptationField-Length
+ // search for PES-Change
+ for (i = afdl+3; i < TS_SIZE-4; i++) {
+ if (data[i] == 0xfd && data[i+1] == 0xff && ((data[i+2] & 0xf0) == 0xf0) && ((data[i+3] & 0x04) == 0x04)) {
+ // && ((data[i+4] & 0x0f) != 0x0f))
+ offset = i;
+ rdsl = data[offset-1];
+ break;
+ }
+ }
+ }
+ else /* no PES-Audio MPEG-1/2 found */
+ return;
+
+ if (rdsl <= 0) { // save payload of last frame with no PES-Change
+ for (i = TS_SIZE-1, ii = 0; i > 3; i--)
+ lastframe[ii++] = data[i];
+ return;
+ }
+
+ // RDS data
+ for (i = offset-2, ii = 0; i > offset-2-rdsl; i--) { // <-- data reverse, from end to start
+ if (i > afdl+3)
+ val = data[i];
+ else if (ii < TS_SIZE-5)
+ val = lastframe[ii++];
+ else
+ return;
+
+ if (val == 0xfe) { // Start
+ index = -1;
+ rt_start = 1;
+ rt_bstuff = 0;
+ mec = 0;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("\nRDS-Start: ");
+ }
+
+ if (rt_start == 1) {
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("%02x ", val);
+
+ // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff
+ if (rt_bstuff == 1) {
+ switch (val) {
+ case 0x00: mtext[index] = 0xfd; break;
+ case 0x01: mtext[index] = 0xfe; break;
+ case 0x02: mtext[index] = 0xff; break;
+ default: mtext[++index] = val; // should never be
+ }
+ rt_bstuff = 0;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(Bytestuffing -> %02x) ", mtext[index]);
+ }
+ else
+ mtext[++index] = val;
+ if (val == 0xfd && index > 0) // stuffing found
+ rt_bstuff = 1;
+
+ // early check for used mec
+ if (index == 5) {
+ switch (val) {
+ case 0x0a: // RT
+ case 0x46: // ODA-Data
+ case 0xda: // Rass
+ case 0x07: // PTY
+ case 0x3e: // PTYN
+ case 0x30: // TMC
+ case 0x02: mec = val; // PS
+ RdsLogo = true;
+ break;
+ default: rt_start = 0;
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("[RDS-MEC '%02x' not used -> End]\n", val);
+ }
+ }
+ if (index >= mframel) { // max. rdslength, garbage ?
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error(TS): too long, garbage ?\n");
+ rt_start = 0;
+ }
+ }
+
+ if (rt_start == 1 && val == 0xff) { // End
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("(RDS-End)\n");
+ rt_start = 0;
+ if (index < 9) { // min. rdslength, garbage ?
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error(TS): too short -> garbage ?\n");
+ }
+ else {
+ // crc16-check
+ unsigned short crc16 = crc16_ccitt(mtext, index-3, 1);
+ if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error(TS): wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]);
+ }
+ else {
+ switch (mec) {
+ case 0x0a: RadiotextDecode(mtext, index); // Radiotext
+ break;
+ case 0x46: switch ((mtext[7]<<8)+mtext[8]) { // ODA-ID
+ case 0x4bd7: RadiotextDecode(mtext, index); // RT+
+ break;
+ case 0x0d45:
+ case 0xcd46: if ((S_Verbose & 0x20) > 0) {
+ unsigned char tmc[6]; // TMC Alert-C
+ int i;
+ for (i=9; i<=(index-3); i++)
+ tmc[i-9] = mtext[i];
+ tmc_parser(tmc, i-8);
+ }
+ break;
+ default: if ((S_Verbose & 0x0f) >= 2)
+ printf("[RDS-ODA AID '%02x%02x' not used -> End]\n", mtext[7], mtext[8]);
+ }
+ break;
+ case 0x07: RT_PTY = mtext[8]; // PTY
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY));
+ break;
+ case 0x3e: RDS_PsPtynDecode(1, mtext, index); // PTYN
+ break;
+ case 0x02: RDS_PsPtynDecode(0, mtext, index); // PS
+ break;
+ case 0xda: RassDecode(mtext, index); // Rass
+ break;
+ case 0x30: if ((S_Verbose & 0x20) > 0) { // TMC Alert-C
+ unsigned char tmc[6];
+ int i;
+ for (i=7; i<=(index-3); i++)
+ tmc[i-7] = mtext[i];
+ tmc_parser(tmc, i-6);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void cRadioAudio::RadiotextDecode(unsigned char *mtext, int len)
+{
+ static bool rtp_itoggle = false;
+ static int rtp_idiffs = 0;
+ static cTimeMs rtp_itime;
+ static char plustext[RT_MEL];
+
+ // byte 1+2 = ADD (10bit SiteAdress + 6bit EncoderAdress)
+ // byte 3 = SQC (Sequence Counter 0x00 = not used)
+ int leninfo = mtext[4]; // byte 4 = MFL (Message Field Length)
+ if (len >= leninfo+7) { // check complete length
+
+ // byte 5 = MEC (Message Element Code, 0x0a for RT, 0x46 for RTplus)
+ if (mtext[5] == 0x0a) {
+ // byte 6+7 = DSN+PSN (DataSetNumber+ProgramServiceNumber,
+ // ignore here, always 0x00 ?)
+ // byte 8 = MEL (MessageElementLength, max. 64+1 byte @ RT)
+ if (mtext[8] == 0 || mtext[8] > RT_MEL || mtext[8] > leninfo-4) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RT-Error: Length=0 or not correct (MFL= %d, MEL= %d)\n", mtext[4], mtext[8]);
+ return;
+ }
+ // byte 9 = RT-Status bitcodet (0=AB-flagcontrol, 1-4=Transmission-Number, 5+6=Buffer-Config,
+ // ingnored, always 0x01 ?)
+ char temptext[RT_MEL];
+ memset(temptext, 0x20, RT_MEL-1);
+ for (int i = 1, ii = 0; i < mtext[8]; i++) {
+ if (mtext[9+i] <= 0xfe)
+ // additional rds-character, see RBDS-Standard, Annex E
+ temptext[ii++] = (mtext[9+i] >= 0x80) ? rds_addchar[mtext[9+i]-0x80] : mtext[9+i];
+ }
+ memcpy(plustext, temptext, RT_MEL-1);
+ rds_entitychar(temptext);
+ // check repeats
+ bool repeat = false;
+ for (int ind = 0; ind < S_RtOsdRows; ind++) {
+ if (memcmp(RT_Text[ind], temptext, RT_MEL-1) == 0) {
+ repeat = true;
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RText-Rep[%d]: %s\n", ind, RT_Text[ind]);
+ }
+ }
+ if (!repeat) {
+ memcpy(RT_Text[RT_Index], temptext, RT_MEL-1);
+ // +Memory
+ char *temp;
+ asprintf(&temp, "%s", RT_Text[RT_Index]);
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", rtrim(temp));
+ free(temp);
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("Radiotext[%d]: %s\n", RT_Index, RT_Text[RT_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ }
+ RTP_TToggle = 0x03; // Bit 0/1 = Title/Artist
+ RT_MsgShow = true;
+ (RT_Info > 0) ? : RT_Info = 1;
+ radioStatusMsg();
+ }
+
+ else if (RTP_TToggle > 0 && mtext[5] == 0x46 && S_RtFunc >= 2) { // RTplus tags V2.1, only if RT
+ if (mtext[6] > leninfo-2 || mtext[6] != 8) { // byte 6 = MEL, only 8 byte for 2 tags
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RTp-Error: Length not correct (MEL= %d)\n", mtext[6]);
+ return;
+ }
+ uint rtp_typ[2], rtp_start[2], rtp_len[2];
+ // byte 7+8 = ApplicationID, always 0x4bd7
+ // byte 9 = Applicationgroup Typecode / PTY ?
+ // bit 10#4 = Item Togglebit
+ // bit 10#3 = Item Runningbit
+ // Tag1: bit 10#2..11#5 = Contenttype, 11#4..12#7 = Startmarker, 12#6..12#1 = Length
+ rtp_typ[0] = (0x38 & mtext[10]<<3) | mtext[11]>>5;
+ rtp_start[0] = (0x3e & mtext[11]<<1) | mtext[12]>>7;
+ rtp_len[0] = 0x3f & mtext[12]>>1;
+ // Tag2: bit 12#0..13#3 = Contenttype, 13#2..14#5 = Startmarker, 14#4..14#0 = Length(5bit)
+ rtp_typ[1] = (0x20 & mtext[12]<<5) | mtext[13]>>3;
+ rtp_start[1] = (0x38 & mtext[13]<<3) | mtext[14]>>5;
+ rtp_len[1] = 0x1f & mtext[14];
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("RTplus (tag=Typ/Start/Len): Toggle/Run = %d/%d, tag#1 = %d/%d/%d, tag#2 = %d/%d/%d\n",
+ (mtext[10]&0x10)>0, (mtext[10]&0x08)>0, rtp_typ[0], rtp_start[0], rtp_len[0], rtp_typ[1], rtp_start[1], rtp_len[1]);
+ // save info
+ for (int i = 0; i < 2; i++) {
+ if (rtp_start[i]+rtp_len[i]+1 >= RT_MEL) { // length-error
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RTp-Error (tag#%d = Typ/Start/Len): %d/%d/%d (Start+Length > 'RT-MEL' !)\n",
+ i+1, rtp_typ[i], rtp_start[i], rtp_len[i]);
+ }
+ else {
+ char temptext[RT_MEL];
+ memset(temptext, 0x20, RT_MEL-1);
+ memmove(temptext, plustext+rtp_start[i], rtp_len[i]+1);
+ rds_entitychar(temptext);
+ // +Memory
+ memset(rtp_content.temptext, 0x20, RT_MEL-1);
+ memcpy(rtp_content.temptext, temptext, RT_MEL-1);
+ switch (rtp_typ[i]) {
+ case 1: // Item-Title
+ if ((mtext[10] & 0x08) > 0 && (RTP_TToggle & 0x01) == 0x01) {
+ RTP_TToggle -= 0x01;
+ RT_Info = 2;
+ if (memcmp(RTP_Title, temptext, RT_MEL-1) != 0 || (mtext[10] & 0x10) != RTP_ItemToggle) {
+ memcpy(RTP_Title, temptext, RT_MEL-1);
+ if (RT_PlusShow && rtp_itime.Elapsed() > 1000)
+ rtp_idiffs = (int) rtp_itime.Elapsed()/1000;
+ if (!rtp_content.item_New) {
+ RTP_Starttime = time(NULL);
+ rtp_itime.Set(0);
+ sprintf(RTP_Artist, "---");
+ if (++rtp_content.item_Index >= MAX_RTPC)
+ rtp_content.item_Index = 0;
+ rtp_content.item_Start[rtp_content.item_Index] = time(NULL); // todo: replay-mode
+ rtp_content.item_Artist[rtp_content.item_Index] = NULL;
+ }
+ rtp_content.item_New = (!rtp_content.item_New) ? true : false;
+ if (rtp_content.item_Index >= 0)
+ asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", rtrim(rtp_content.temptext));
+ RT_PlusShow = RT_MsgShow = rtp_itoggle = true;
+ }
+ }
+ break;
+ case 4: // Item-Artist
+ if ((mtext[10] & 0x08) > 0 && (RTP_TToggle & 0x02) == 0x02) {
+ RTP_TToggle -= 0x02;
+ RT_Info = 2;
+ if (memcmp(RTP_Artist, temptext, RT_MEL-1) != 0 || (mtext[10] & 0x10) != RTP_ItemToggle) {
+ memcpy(RTP_Artist, temptext, RT_MEL-1);
+ if (RT_PlusShow && rtp_itime.Elapsed() > 1000)
+ rtp_idiffs = (int) rtp_itime.Elapsed()/1000;
+ if (!rtp_content.item_New) {
+ RTP_Starttime = time(NULL);
+ rtp_itime.Set(0);
+ sprintf(RTP_Title, "---");
+ if (++rtp_content.item_Index >= MAX_RTPC)
+ rtp_content.item_Index = 0;
+ rtp_content.item_Start[rtp_content.item_Index] = time(NULL); // todo: replay-mode
+ rtp_content.item_Title[rtp_content.item_Index] = NULL;
+ }
+ rtp_content.item_New = (!rtp_content.item_New) ? true : false;
+ if (rtp_content.item_Index >= 0)
+ asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", rtrim(rtp_content.temptext));
+ RT_PlusShow = RT_MsgShow = rtp_itoggle = true;
+ }
+ }
+ break;
+ case 12: // Info_News
+ asprintf(&rtp_content.info_News, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 13: // Info_NewsLocal
+ asprintf(&rtp_content.info_NewsLocal, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 14: // Info_Stockmarket
+ if (++rtp_content.info_StockIndex >= MAX_RTPC)
+ rtp_content.info_StockIndex = 0;
+ asprintf(&rtp_content.info_Stock[rtp_content.info_StockIndex], "%s", rtrim(rtp_content.temptext));
+ break;
+ case 15: // Info_Sport
+ if (++rtp_content.info_SportIndex >= MAX_RTPC)
+ rtp_content.info_SportIndex = 0;
+ asprintf(&rtp_content.info_Sport[rtp_content.info_SportIndex], "%s", rtrim(rtp_content.temptext));
+ break;
+ case 16: // Info_Lottery
+ if (++rtp_content.info_LotteryIndex >= MAX_RTPC)
+ rtp_content.info_LotteryIndex = 0;
+ asprintf(&rtp_content.info_Lottery[rtp_content.info_LotteryIndex], "%s", rtrim(rtp_content.temptext));
+ break;
+ case 24: // Info_DateTime
+ asprintf(&rtp_content.info_DateTime, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 25: // Info_Weather
+ if (++rtp_content.info_WeatherIndex >= MAX_RTPC)
+ rtp_content.info_WeatherIndex = 0;
+ asprintf(&rtp_content.info_Weather[rtp_content.info_WeatherIndex], "%s", rtrim(rtp_content.temptext));
+ break;
+ case 26: // Info_Traffic
+ asprintf(&rtp_content.info_Traffic, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 27: // Info_Alarm
+ asprintf(&rtp_content.info_Alarm, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 28: // Info_Advert
+ asprintf(&rtp_content.info_Advert, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 29: // Info_Url
+ asprintf(&rtp_content.info_Url, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 30: // Info_Other
+ if (++rtp_content.info_OtherIndex >= MAX_RTPC)
+ rtp_content.info_OtherIndex = 0;
+ asprintf(&rtp_content.info_Other[rtp_content.info_OtherIndex], "%s", rtrim(rtp_content.temptext));
+ break;
+ case 31: // Programme_Stationname.Short
+ asprintf(&rtp_content.prog_StatShort, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 32: // Programme_Stationname.Long
+ asprintf(&rtp_content.prog_Station, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 33: // Programme_Now
+ asprintf(&rtp_content.prog_Now, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 34: // Programme_Next
+ asprintf(&rtp_content.prog_Next, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 35: // Programme_Part
+ asprintf(&rtp_content.prog_Part, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 36: // Programme_Host
+ asprintf(&rtp_content.prog_Host, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 37: // Programme_EditorialStaff
+ asprintf(&rtp_content.prog_EditStaff, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 39: // Programme_Homepage
+ asprintf(&rtp_content.prog_Homepage, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 41: // Phone_Hotline
+ asprintf(&rtp_content.phone_Hotline, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 42: // Phone_Studio
+ asprintf(&rtp_content.phone_Studio, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 44: // SMS_Studio
+ asprintf(&rtp_content.sms_Studio, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 46: // Email_Hotline
+ asprintf(&rtp_content.email_Hotline, "%s", rtrim(rtp_content.temptext));
+ break;
+ case 47: // Email_Studio
+ asprintf(&rtp_content.email_Studio, "%s", rtrim(rtp_content.temptext));
+ break;
+ }
+ }
+ }
+
+ // Title-end @ no Item-Running'
+ if ((mtext[10] & 0x08) == 0) {
+ sprintf(RTP_Title, "---");
+ sprintf(RTP_Artist, "---");
+ if (RT_PlusShow) {
+ RT_PlusShow = false;
+ rtp_itoggle = true;
+ rtp_idiffs = (int) rtp_itime.Elapsed()/1000;
+ RTP_Starttime = time(NULL);
+ }
+ RT_MsgShow = (RT_Info > 0);
+ rtp_content.item_New = false;
+ }
+
+ if (rtp_itoggle) {
+ if ((S_Verbose & 0x0f) >= 1) {
+ struct tm tm_store;
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ if (rtp_idiffs > 0)
+ printf(" StartTime : %02d:%02d:%02d (last Title elapsed = %d s)\n",
+ ts->tm_hour, ts->tm_min, ts->tm_sec, rtp_idiffs);
+ else
+ printf(" StartTime : %02d:%02d:%02d\n", ts->tm_hour, ts->tm_min, ts->tm_sec);
+ printf(" RTp-Title : %s\n RTp-Artist: %s\n", RTP_Title, RTP_Artist);
+ }
+ RTP_ItemToggle = mtext[10] & 0x10;
+ rtp_itoggle = false;
+ rtp_idiffs = 0;
+ radioStatusMsg();
+ AudioRecorderService();
+ }
+
+ RTP_TToggle = 0;
+ }
+ }
+
+ else {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error: [RTDecode] Length not correct (MFL= %d, len= %d)\n", mtext[4], len);
+ }
+}
+
+void cRadioAudio::RDS_PsPtynDecode(bool ptyn, unsigned char *mtext, int len)
+{
+ if (len < 16) return;
+
+ // decode Text
+ for (int i = 8; i <= 15; i++) {
+ if (mtext[i] <= 0xfe) {
+ // additional rds-character, see RBDS-Standard, Annex E
+ if (!ptyn)
+ RDS_PSText[RDS_PSIndex][i-8] = (mtext[i] >= 0x80) ? rds_addchar[mtext[i]-0x80] : mtext[i];
+ else
+ RDS_PTYN[i-8] = (mtext[i] >= 0x80) ? rds_addchar[mtext[i]-0x80] : mtext[i];
+ }
+ }
+
+ if ((S_Verbose & 0x0f) >= 1) {
+ if (!ptyn)
+ printf("RDS-PS No= %d, Content[%d]= '%s'\n", mtext[7], RDS_PSIndex, RDS_PSText[RDS_PSIndex]);
+ else
+ printf("RDS-PTYN No= %d, Content= '%s'\n", mtext[7], RDS_PTYN);
+ }
+
+ if (!ptyn) {
+ RDS_PSIndex += 1; if (RDS_PSIndex >= 12) RDS_PSIndex = 0;
+ RT_MsgShow = RDS_PSShow = true;
+ }
+}
+
+void cRadioAudio::AudioRecorderService(void)
+{
+ /* check plugin audiorecorder service */
+ ARec_Receive = ARec_Record = false;
+
+ if (!RT_PlusShow || RT_Replay)
+ return;
+
+ Audiorecorder_StatusRtpChannel_v1_0 arec_service;
+ cPlugin *p;
+
+ arec_service.channel = chan;
+ p = cPluginManager::CallFirstService("Audiorecorder-StatusRtpChannel-v1.0", &arec_service);
+ if (p) {
+ ARec_Receive = (arec_service.status >= 2);
+ ARec_Record = (arec_service.status == 3);
+ }
+}
+
+// add <names> of DVB Radio Slides Specification 1.0, 20061228
+void cRadioAudio::RassDecode(unsigned char *mtext, int len)
+{
+ if (RT_Replay) // no recordings $20090905
+ return;
+
+ static uint splfd = 0, spmax = 0, index = 0;
+ static uint afiles, slidenumr, slideelem, filemax;
+ static int filetype;
+ static bool slideshow = false, slidesave = false, slidecan = false, slidedel = false, start = false;
+ static uchar daten[65536]; // mpegs-stills defined <= 50kB
+ FILE *fd;
+
+ // byte 1+2 = ADD (10bit SiteAdress + 6bit EncoderAdress)
+ // byte 3 = SQC (Sequence Counter 0x00 = not used)
+ // byte 4 = MFL (Message Field Length),
+ if (len >= mtext[4]+7) { // check complete length
+ // byte 5 = MEC (0xda for Rass)
+ // byte 6 = MEL
+ if (mtext[6] == 0 || mtext[6] > mtext[4]-2) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("Rass-Error: Length=0 or not correct (MFL= %d, MEL= %d)\n", mtext[4], mtext[6]);
+ return;
+ }
+ // byte 7+8 = Service-ID zugehöriger Datenkanal
+ // byte 9-11 = Nummer aktuelles Paket, <PNR>
+ uint plfd = mtext[11] | mtext[10]<<8 | mtext[9]<<16;
+ // byte 12-14 = Anzahl Pakete, <NOP>
+ uint pmax = mtext[14] | mtext[13]<<8 | mtext[12]<<16;
+
+ // byte 15+16 = Rass-Kennung = Header, <Rass-STA>
+ if (mtext[15] == 0x40 && mtext[16] == 0xda) { // first
+ // byte 17+18 = Anzahl Dateien im Archiv, <NOI>
+ afiles = mtext[18] | mtext[17]<<8;
+ // byte 19+20 = Slide-Nummer, <Rass-ID>
+ slidenumr = mtext[20] | mtext[19]<<8;
+ // byte 21+22 = Element-Nummer im Slide, <INR>
+ slideelem = mtext[22] | mtext[21]<<8;
+ // byte 23 = Slide-Steuerbyte, <Cntrl-Byte>: bit0 = Anzeige, bit1 = Speichern, bit2 = DarfAnzeige bei Senderwechsel, bit3 = Löschen
+ slideshow = mtext[23] & 0x01;
+ slidesave = mtext[23] & 0x02;
+ slidecan = mtext[23] & 0x04;
+ slidedel = mtext[23] & 0x08;
+ // byte 24 = Dateiart, <Item-Type>: 0=unbekannt/1=MPEG-Still/2=Definition
+ filetype = mtext[24];
+ if (filetype != 1 && filetype != 2) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("Rass-Error: Filetype '%d' unknown !\n", filetype);
+ //return;
+ }
+ // byte 25-28 = Dateilänge, <Item-Length>
+ filemax = mtext[28] | mtext[27]<<8 | mtext[26]<<16 | mtext[25]<<24;
+ if (filemax >= 65536) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("Rass-Error: Filesize '%d' will be too big !\n", filemax);
+ return;
+ }
+ // byte 29-31 = Dateioffset Paketnr old, now <rfu>
+ // byte 32 = Dateioffset Bytenr old, now <rfu>
+ if ((S_Verbose & 0x10) > 0) {
+ printf("Rass-Header: afiles= %d, slidenumr= %d, slideelem= %d\n slideshow= %d, -save= %d, -canschow= %d, -delete= %d\n filetype= %d, filemax= %d\n",
+ afiles, slidenumr, slideelem, slideshow, slidesave, slidecan, slidedel, filetype, filemax);
+ printf("Rass-Start ...\n");
+ }
+ start = true;
+ index = 0;
+ for (int i=33; i < len-2; i++) {
+ if (index < filemax)
+ daten[index++] = mtext[i];
+ else
+ start = false;
+ }
+ splfd = plfd;
+ }
+
+ else if (plfd < pmax && plfd == splfd+1) { // Between
+ splfd = plfd;
+ if (start) {
+ for (int i=15; i < len-2; i++) {
+ if (index < filemax)
+ daten[index++] = mtext[i];
+ else
+ start = false;
+ }
+ }
+ }
+
+ else if (plfd == pmax && plfd == splfd+1) { // Last
+ if (start) {
+ for (int i=15; i < len-4; i++) {
+ if (index <= filemax)
+ daten[index++] = mtext[i];
+ else {
+ start = false;
+ return;
+ }
+ }
+ if ((S_Verbose & 0x10) > 0)
+ printf("... Rass-End (%d bytes)\n", index);
+ }
+ if (filemax > 0) { // nothing todo, if 0 byte file
+ // crc-check with bytes 'len-4/3'
+ unsigned short crc16 = crc16_ccitt(daten, filemax, false);
+ if (crc16 != (mtext[len-4]<<8)+mtext[len-3]) {
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("Rass-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[len-4], mtext[len-3]);
+ start = false;
+ return;
+ }
+ }
+ // show & save file ?
+ if (index == filemax && enforce_directory(DataDir)) {
+ if (slideshow || (slidecan && Rass_Show == -1)) {
+ if (filetype == 1) { // show only mpeg-still
+ char *filepath;
+ asprintf(&filepath, "%s/%s", DataDir, "Rass_show.mpg");
+ if ((fd = fopen(filepath, "wb")) != NULL) {
+ fwrite(daten, 1, filemax, fd);
+ //fflush(fd); // for test in replaymode
+ fclose(fd);
+ Rass_Show = 1;
+ if ((S_Verbose & 0x10) > 0)
+ printf("Rass-File: ready for displaying :-)\n");
+ }
+ else
+ esyslog("radio: ERROR writing Rass-imagefile failed '%s'", filepath);
+ free(filepath);
+ }
+ }
+ if (slidesave || slidedel || slidenumr < RASS_GALMAX) {
+ // lfd. Fotogallery 100.. ???
+ if (slidenumr >= 100 && slidenumr < RASS_GALMAX) {
+ (Rass_SlideFoto < RASS_GALMAX) ? Rass_SlideFoto++ : Rass_SlideFoto = 100;
+ slidenumr = Rass_SlideFoto;
+ }
+ //
+ char *filepath;
+ (filetype == 2) ? asprintf(&filepath, "%s/Rass_%d.def", DataDir, slidenumr)
+ : asprintf(&filepath, "%s/Rass_%d.mpg", DataDir, slidenumr);
+ if ((fd = fopen(filepath, "wb")) != NULL) {
+ fwrite(daten, 1, filemax, fd);
+ fclose(fd);
+ if ((S_Verbose & 0x10) > 0)
+ printf("Rass-File: saving '%s'\n", filepath);
+ // archivemarker mpeg-stills
+ if (filetype == 1) {
+ // 0, 1000/1100/1110/1111..9000/9900/9990/9999
+ if (slidenumr == 0 || slidenumr > RASS_GALMAX) {
+ if (slidenumr == 0) {
+ Rass_Flags[0][0] = !slidedel;
+ (RT_Info > 0) ? : RT_Info = 0; // open RadioTextOsd for ArchivTip
+ }
+ else {
+ int islide = (int) floor(slidenumr/1000);
+ for (int i = 3; i >= 0; i--) {
+ if (fmod(slidenumr, pow(10, i)) == 0) {
+ Rass_Flags[islide][3-i] = !slidedel;
+ break;
+ }
+ }
+ }
+ }
+ // gallery
+ else {
+ Rass_Gallery[slidenumr] = !slidedel;
+ if (!slidedel && (int)slidenumr > Rass_GalEnd)
+ Rass_GalEnd = slidenumr;
+ if (!slidedel && (Rass_GalStart == 0 || (int)slidenumr < Rass_GalStart))
+ Rass_GalStart = slidenumr;
+ // counter
+ Rass_GalCount = 0;
+ for (int i = Rass_GalStart; i <= Rass_GalEnd; i++) {
+ if (Rass_Gallery[i])
+ Rass_GalCount++;
+ }
+ Rass_Flags[10][0] = (Rass_GalCount > 0);
+ }
+ }
+ }
+ else
+ esyslog("radio: ERROR writing Rass-image/data-file failed '%s'", filepath);
+ free(filepath);
+ }
+ }
+ start = false;
+ splfd = spmax = 0;
+ }
+
+ else {
+ start = false;
+ splfd = spmax = 0;
+ }
+ }
+
+ else {
+ start = false;
+ splfd = spmax = 0;
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("RDS-Error: [Rass] Length not correct (MFL= %d, len= %d)\n", mtext[4], len);
+ }
+}
+
+void cRadioAudio::EnableRadioTextProcessing(const char *Titel, int apid, bool replay)
+{
+ asprintf(&RT_Titel, "%s", Titel);
+ audiopid = apid;
+ RT_Replay = replay;
+ ARec_Receive = ARec_Record = false;
+
+ first_packets = 0;
+ enabled = true;
+ bratefound = false;
+ asprintf(&bitrate, "...");
+
+ // Radiotext init
+ if (S_RtFunc >= 1) {
+ RT_MsgShow = RT_PlusShow = RdsLogo = false;
+ RT_ReOpen = true;
+ RT_OsdTO = false;
+ RT_Index = RT_PTY = RTP_TToggle = 0;
+ RTP_ItemToggle = 1;
+ for (int i = 0; i < 5; i++)
+ memset(RT_Text[i], 0x20, RT_MEL-1);
+ sprintf(RTP_Title, "---");
+ sprintf(RTP_Artist, "---");
+ RTP_Starttime = time(NULL);
+ RT_Charset = 0;
+ //
+ RDS_PSShow = false;
+ RDS_PSIndex = 0;
+ for (int i = 0; i < 12; i++)
+ memset(RDS_PSText[i], 0x20, 8);
+ }
+ // ...Memory
+ rtp_content.start = time(NULL);
+ rtp_content.item_New = false;
+ rtp_content.rt_Index = -1;
+ rtp_content.item_Index = -1;
+ rtp_content.info_StockIndex = -1;
+ rtp_content.info_SportIndex = -1;
+ rtp_content.info_LotteryIndex = -1;
+ rtp_content.info_WeatherIndex = -1;
+ rtp_content.info_OtherIndex = -1;
+ for (int i = 0; i < MAX_RTPC; i++) {
+ rtp_content.radiotext[i] = NULL;
+ rtp_content.radiotext[MAX_RTPC+i] = NULL;
+ rtp_content.item_Title[i] = NULL;
+ rtp_content.item_Artist[i] = NULL;
+ rtp_content.info_Stock[i] = NULL;
+ rtp_content.info_Sport[i] = NULL;
+ rtp_content.info_Lottery[i] = NULL;
+ rtp_content.info_Weather[i] = NULL;
+ rtp_content.info_Other[i] = NULL;
+ }
+ rtp_content.info_News = NULL;
+ rtp_content.info_NewsLocal = NULL;
+ rtp_content.info_DateTime = NULL;
+ rtp_content.info_Traffic = NULL;
+ rtp_content.info_Alarm = NULL;
+ rtp_content.info_Advert = NULL;
+ rtp_content.info_Url = NULL;
+ rtp_content.prog_StatShort = NULL;
+ rtp_content.prog_Station = NULL;
+ rtp_content.prog_Now = NULL;
+ rtp_content.prog_Next = NULL;
+ rtp_content.prog_Part = NULL;
+ rtp_content.prog_Host = NULL;
+ rtp_content.prog_EditStaff = NULL;
+ rtp_content.prog_Homepage = NULL;
+ rtp_content.phone_Hotline = NULL;
+ rtp_content.phone_Studio = NULL;
+ rtp_content.sms_Studio = NULL;
+ rtp_content.email_Hotline = NULL;
+ rtp_content.email_Studio = NULL;
+
+ // Rass init
+ Rass_Show = Rass_Archiv = -1;
+ for (int i = 0; i <= 10; i++) {
+ for (int ii = 0; ii < 4; ii++)
+ Rass_Flags[i][ii] = false;
+ }
+ Rass_GalStart = Rass_GalEnd = Rass_GalCount = 0;
+ for (int i = 0; i < RASS_GALMAX; i++)
+ Rass_Gallery[i] = false;
+ Rass_SlideFoto = 99;
+ //
+ InfoRequest = false;
+
+ if (S_RtFunc < 1) return;
+
+ // RDS-Receiver for seperate Data-PIDs, only Livemode, hardcoded Astra_19E + Hotbird 13E
+ int pid = 0;
+ if (!replay) {
+ switch (chan->Tid()) {
+ case 1113: switch (pid = chan->Apid(0)) { // Astra_19.2E - 12633 GHz
+ /* case 0x161: pid = 0x229; // radio top40
+ break; */
+ case 0x400: // Hitradio FFH
+ case 0x406: // planet radio
+ case 0x40c: pid += 1; // harmony.ffm
+ break;
+ default: return;
+ }
+ break;
+ case 5300: switch (pid = chan->Apid(0)) { // Hotbird_13E - 11747 GHz, no Radiotext @ moment, only TMC + MECs 25/26
+ case 0xdc3: // Radio 1
+ case 0xdd3: // Radio 3
+ case 0xddb: // Radio 5
+ case 0xde3: // Radio Exterior
+ case 0xdeb: pid += 1; // Radio 4
+ break;
+ default: return;
+ }
+ break;
+ default: return;
+ }
+ RDSReceiver = new cRDSReceiver(pid);
+ rdsdevice = cDevice::ActualDevice();
+ rdsdevice->AttachReceiver(RDSReceiver);
+ }
+
+}
+
+void cRadioAudio::DisableRadioTextProcessing()
+{
+ RT_Replay = enabled = false;
+
+ // Radiotext & Rass
+ RT_Info = -1;
+ RT_ReOpen = false;
+ Rass_Show = Rass_Archiv = -1;
+ Rass_GalStart = Rass_GalEnd = Rass_GalCount = 0;
+
+ if (RadioTextOsd != NULL)
+ RadioTextOsd->Hide();
+
+ if (RDSReceiver != NULL) {
+ rdsdevice->Detach(RDSReceiver);
+ delete RDSReceiver;
+ RDSReceiver = NULL;
+ rdsdevice = NULL;
+ }
+}
+
+
+// --- cRadioTextOsd ------------------------------------------------------
+
+cBitmap cRadioTextOsd::rds(rds_xpm);
+cBitmap cRadioTextOsd::arec(arec_xpm);
+cBitmap cRadioTextOsd::rass(rass_xpm);
+cBitmap cRadioTextOsd::index(index_xpm);
+cBitmap cRadioTextOsd::radio(radio_xpm);
+cBitmap cRadioTextOsd::marker(marker_xpm);
+cBitmap cRadioTextOsd::page1(page1_xpm);
+cBitmap cRadioTextOsd::pages2(pages2_xpm);
+cBitmap cRadioTextOsd::pages3(pages3_xpm);
+cBitmap cRadioTextOsd::pages4(pages4_xpm);
+cBitmap cRadioTextOsd::no0(no0_xpm);
+cBitmap cRadioTextOsd::no1(no1_xpm);
+cBitmap cRadioTextOsd::no2(no2_xpm);
+cBitmap cRadioTextOsd::no3(no3_xpm);
+cBitmap cRadioTextOsd::no4(no4_xpm);
+cBitmap cRadioTextOsd::no5(no5_xpm);
+cBitmap cRadioTextOsd::no6(no6_xpm);
+cBitmap cRadioTextOsd::no7(no7_xpm);
+cBitmap cRadioTextOsd::no8(no8_xpm);
+cBitmap cRadioTextOsd::no9(no9_xpm);
+cBitmap cRadioTextOsd::bok(bok_xpm);
+cBitmap cRadioTextOsd::pageE(pageE_xpm);
+
+cRadioTextOsd::cRadioTextOsd()
+ : cCharSetConv((RT_Charset == 0) ? "ISO-8859-1" : NULL)
+{
+ RadioTextOsd = this;
+ osd = NULL;
+ qosd = NULL;
+ rtclosed = rassclosed = false;
+ RT_ReOpen = false;
+}
+
+cRadioTextOsd::~cRadioTextOsd()
+{
+ if (Rass_Archiv >= 0) {
+ if (!RT_Replay)
+ Rass_Archiv = RassImage(-1, -1, false);
+ else {
+ Rass_Archiv = -1;
+ RadioImage->SetBackgroundImage(ReplayFile);
+ }
+ }
+
+ if (osd != NULL)
+ delete osd;
+ if (qosd != NULL)
+ delete qosd;
+ RadioTextOsd = NULL;
+ RT_ReOpen = !RT_OsdTO;
+
+ cRemote::Put(LastKey);
+}
+
+void cRadioTextOsd::Show(void)
+{
+ LastKey = kNone;
+ RT_OsdTO = false;
+ osdtimer.Set();
+
+ ftext = cFont::GetFont(fontSml);
+ fheight = ftext->Height() + 4;
+ bheight = (S_RtOsdTags >=1 ) ? fheight * (S_RtOsdRows+3) : fheight * (S_RtOsdRows+1);
+ bheight += 20;
+
+ asprintf(&RTp_Titel, "%s - %s", InfoRequest ? tr("ext. Info") : tr("RTplus"), RT_Titel);
+
+ if (S_RtDispl >= 1 && (!Rass_Flags[0][0] || S_RassText >= 2)) { // Rass_Show == -1
+ RT_MsgShow = (RT_Info >= 1);
+ ShowText();
+ }
+}
+
+void cRadioTextOsd::Hide(void)
+{
+ RTOsdClose();
+ RassOsdClose();
+}
+
+void cRadioTextOsd::RTOsdClose(void)
+{
+ if (osd != NULL) {
+ delete osd;
+ osd = NULL;
+ }
+}
+
+void cRadioTextOsd::ShowText(void)
+{
+ char stext[3][100];
+ int yoff = 17, ii = 1;
+
+ if (!osd && !qosd && !Skins.IsOpen() && !cOsd::IsOpen()) {
+ if (S_RtOsdPos == 1)
+ osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight-bheight);
+ else
+ osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop);
+ tArea Area = {0, 0, Setup.OSDWidth-1, bheight-1, 4};
+ osd->SetAreas(&Area, 1);
+ }
+
+ if (osd) {
+ uint32_t bcolor, fcolor;
+ int skin = theme_skin();
+ ftitel = cFont::GetFont(fontOsd);
+ ftext = cFont::GetFont(fontSml);
+ if (S_RtOsdTitle == 1) {
+ // Title
+ bcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrTitleBack : (0x00FFFFFF | S_RtBgTra<<24) & rt_color[S_RtBgCol];
+ fcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrTitleText : rt_color[S_RtFgCol];
+ osd->DrawRectangle(0, 0, Setup.OSDWidth-1, ftitel->Height()+9, bcolor);
+ osd->DrawEllipse(0, 0, 5, 5, 0x00000000, -2);
+ osd->DrawEllipse(Setup.OSDWidth-6, 0, Setup.OSDWidth-1, 5, 0x00000000, -1);
+ sprintf(stext[0], RT_PTY == 0 ? "%s - %s %s%s" : "%s - %s (%s)%s",
+ RT_Titel, InfoRequest ? tr("ext. Info") : tr("Radiotext"),
+ RT_PTY == 0 ? RDS_PTYN : ptynr2string(RT_PTY), RT_MsgShow ? ":" : tr(" [waiting ...]"));
+ osd->DrawText(4, 5, stext[0], fcolor, clrTransparent, ftitel, Setup.OSDWidth-4, ftitel->Height());
+ // Radio, RDS- or Rass-Symbol, ARec-Symbol or Bitrate
+ int inloff = (ftitel->Height() + 9 - 20) / 2;
+ if (Rass_Flags[0][0]) {
+ osd->DrawBitmap(Setup.OSDWidth-51, inloff, rass, bcolor, fcolor);
+ if (ARec_Record)
+ osd->DrawBitmap(Setup.OSDWidth-107, inloff, arec, bcolor, 0xFFFC1414); // FG=Red
+ else {
+ inloff = (ftitel->Height() + 9 - ftext->Height()) / 2;
+ osd->DrawText(4, inloff, RadioAudio->bitrate, fcolor, clrTransparent, ftext, Setup.OSDWidth-59, ftext->Height(), taRight);
+ }
+ }
+ else {
+ if (InfoRequest && !RdsLogo) {
+ osd->DrawBitmap(Setup.OSDWidth-72, inloff+1, radio, fcolor, bcolor);
+ osd->DrawBitmap(Setup.OSDWidth-48, inloff-1, radio, fcolor, bcolor);
+ }
+ else
+ osd->DrawBitmap(Setup.OSDWidth-84, inloff, rds, bcolor, fcolor);
+ if (ARec_Record)
+ osd->DrawBitmap(Setup.OSDWidth-140, inloff, arec, bcolor, 0xFFFC1414); // FG=Red
+ else {
+ inloff = (ftitel->Height() + 9 - ftext->Height()) / 2;
+ osd->DrawText(4, inloff, RadioAudio->bitrate, fcolor, clrTransparent, ftext, Setup.OSDWidth-92, ftext->Height(), taRight);
+ }
+ }
+ }
+ else
+ osd->DrawRectangle(0, 0, Setup.OSDWidth-1, ftitel->Height()+9, 0x00000000);
+ // Body
+ bcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrBack : (0x00FFFFFF | S_RtBgTra<<24) & rt_color[S_RtBgCol];
+ fcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrText : rt_color[S_RtFgCol];
+ osd->DrawRectangle(0, ftitel->Height()+10, Setup.OSDWidth-1, bheight-1, bcolor);
+ osd->DrawEllipse(0, bheight-6, 5, bheight-1, 0x00000000, -3);
+ osd->DrawEllipse(Setup.OSDWidth-6, bheight-6, Setup.OSDWidth-1, bheight-1, 0x00000000, -4);
+ if (S_RtOsdTitle == 1)
+ osd->DrawRectangle(5, ftitel->Height()+9, Setup.OSDWidth-6, ftitel->Height()+9, fcolor);
+ if (RT_MsgShow) {
+ // RT-Text roundloop
+ int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1;
+ if (S_RtOsdLoop == 1) { // latest bottom
+ for (int i = ind+1; i < S_RtOsdRows; i++)
+ osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height());
+ for (int i = 0; i <= ind; i++)
+ osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height());
+ }
+ else { // latest top
+ for (int i = ind; i >= 0; i--)
+ osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height());
+ for (int i = S_RtOsdRows-1; i > ind; i--)
+ osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height());
+ }
+ // + RT-Plus or PS-Text = 2 rows
+ if ((S_RtOsdTags == 1 && RT_PlusShow) || S_RtOsdTags >= 2) {
+ if (!RDS_PSShow || !strstr(RTP_Title, "---") || !strstr(RTP_Artist, "---")) {
+ sprintf(stext[1], "> %s", tr("Title :"));
+ sprintf(stext[2], "> %s", tr("Artist :"));
+ int fwidth = ftext->Width(stext[1]);
+ fwidth = max(fwidth, ftext->Width(stext[2])) + 15;
+ osd->DrawText(4, 6+yoff+fheight*(ii), stext[1], fcolor, clrTransparent, ftext, fwidth-5, ftext->Height());
+ osd->DrawText(fwidth, 6+yoff+fheight*(ii++), Convert(RTP_Title), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height());
+ osd->DrawText(4, 3+yoff+fheight*(ii), stext[2], fcolor, clrTransparent, ftext, fwidth-5, ftext->Height());
+ osd->DrawText(fwidth, 3+yoff+fheight*(ii++), Convert(RTP_Artist), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height());
+ }
+ else {
+ char *temp;
+ asprintf(&temp, "%s", "");
+ int ind = (RDS_PSIndex == 0) ? 11 : RDS_PSIndex - 1;
+ for (int i = ind+1; i < 12; i++)
+ asprintf(&temp, "%s%s ", temp, RDS_PSText[i]);
+ for (int i = 0; i <= ind; i++)
+ asprintf(&temp, "%s%s ", temp, RDS_PSText[i]);
+ snprintf(stext[1], 6*9, "%s", temp);
+ snprintf(stext[2], 6*9, "%s", temp+(6*9));
+ free(temp);
+ osd->DrawText(6, 6+yoff+fheight*ii, "[", fcolor, clrTransparent, ftext, 12, ftext->Height());
+ osd->DrawText(Setup.OSDWidth-12, 6+yoff+fheight*ii, "]", fcolor, clrTransparent, ftext, Setup.OSDWidth-6, ftext->Height());
+ osd->DrawText(16, 6+yoff+fheight*(ii++), stext[1], fcolor, clrTransparent, ftext, Setup.OSDWidth-16, ftext->Height(), taCenter);
+ osd->DrawText(6, 3+yoff+fheight*ii, "[", fcolor, clrTransparent, ftext, 12, ftext->Height());
+ osd->DrawText(Setup.OSDWidth-12, 3+yoff+fheight*ii, "]", fcolor, clrTransparent, ftext, Setup.OSDWidth-6, ftext->Height());
+ osd->DrawText(16, 3+yoff+fheight*(ii++), stext[2], fcolor, clrTransparent, ftext, Setup.OSDWidth-16, ftext->Height(), taCenter);
+ }
+ }
+ }
+ osd->Flush();
+ }
+
+ RT_MsgShow = false;
+}
+
+int cRadioTextOsd::RassImage(int QArchiv, int QKey, bool DirUp)
+{
+ int i;
+
+ if (QKey >= 0 && QKey <= 9) {
+ if (QArchiv == 0)
+ (Rass_Flags[QKey][0]) ? QArchiv = QKey * 1000 : QArchiv = 0;
+ else if (QArchiv > 0) {
+ if (floor(QArchiv/1000) == QKey) {
+ for (i = 3; i >= 0; i--) {
+ if (fmod(QArchiv, pow(10, i)) == 0)
+ break;
+ }
+ (i > 0) ? QArchiv += QKey * (int) pow(10, --i) : QArchiv = QKey * 1000;
+ (Rass_Flags[QKey][3-i]) ? : QArchiv = QKey * 1000;
+ }
+ else
+ (Rass_Flags[QKey][0]) ? QArchiv = QKey * 1000 : QArchiv = 0;
+ }
+ }
+ // Gallery
+ else if (QKey > 9 && Rass_GalCount >= 0) {
+ if (QArchiv < Rass_GalStart || QArchiv > Rass_GalEnd)
+ QArchiv = Rass_GalStart - 1;
+ if (DirUp) {
+ for (i = QArchiv+1; i <= Rass_GalEnd; i++) {
+ if (Rass_Gallery[i])
+ break;
+ }
+ QArchiv = (i <= Rass_GalEnd) ? i : Rass_GalStart;
+ }
+ else {
+ for (i = QArchiv-1; i >= Rass_GalStart; i--) {
+ if (Rass_Gallery[i])
+ break;
+ }
+ QArchiv = (i >= Rass_GalStart) ? i : Rass_GalEnd;
+ }
+ }
+
+ // show mpeg-still
+ char *image;
+ if (QArchiv >= 0)
+ asprintf(&image, "%s/Rass_%d.mpg", DataDir, QArchiv);
+ else
+ asprintf(&image, "%s/Rass_show.mpg", DataDir);
+ RadioImage->SetBackgroundImage(image);
+ free(image);
+
+ return QArchiv;
+}
+
+void cRadioTextOsd::RassOsd(void)
+{
+ ftext = cFont::GetFont(fontSml);
+ int fh = ftext->Height();
+
+ if (!qosd && !osd && !Skins.IsOpen() && !cOsd::IsOpen()) {
+ qosd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight - (29+264-6+36));
+ tArea Area = {0, 0, 97, 29+264+5, 4};
+ qosd->SetAreas(&Area, 1);
+ }
+
+ if (qosd) {
+ uint32_t bcolor, fcolor;
+ int skin = theme_skin();
+ // Logo
+ bcolor = radioSkin[skin].clrTitleBack;
+ fcolor = radioSkin[skin].clrTitleText;
+ qosd->DrawRectangle(0, 1, 97, 29, bcolor);
+ qosd->DrawEllipse(0, 0, 5, 5, 0x00000000, -2);
+ qosd->DrawEllipse(92, 0, 97, 5, 0x00000000, -1);
+ qosd->DrawBitmap(25, 5, rass, bcolor, fcolor);
+ // Body
+ bcolor = radioSkin[skin].clrBack;
+ fcolor = radioSkin[skin].clrText;
+ int offs = 29 + 2;
+ qosd->DrawRectangle(0, offs, 97, 29+264+5, bcolor);
+ qosd->DrawEllipse(0, 29+264, 5, 29+264+5, 0x00000000, -3);
+ qosd->DrawEllipse(92, 29+264, 97, 29+264+5, 0x00000000, -4);
+ qosd->DrawRectangle(5, 29, 92, 29, fcolor);
+ // Keys+Index
+ offs += 4;
+ qosd->DrawBitmap(4, offs, no0, bcolor, fcolor);
+ qosd->DrawBitmap(44, offs, index, bcolor, fcolor);
+ qosd->DrawBitmap(4, 24+offs, no1, bcolor, fcolor);
+ qosd->DrawBitmap(4, 48+offs, no2, bcolor, fcolor);
+ qosd->DrawBitmap(4, 72+offs, no3, bcolor, fcolor);
+ qosd->DrawBitmap(4, 96+offs, no4, bcolor, fcolor);
+ qosd->DrawBitmap(4, 120+offs, no5, bcolor, fcolor);
+ qosd->DrawBitmap(4, 144+offs, no6, bcolor, fcolor);
+ qosd->DrawBitmap(4, 168+offs, no7, bcolor, fcolor);
+ qosd->DrawBitmap(4, 192+offs, no8, bcolor, fcolor);
+ qosd->DrawBitmap(4, 216+offs, no9, bcolor, fcolor);
+ qosd->DrawBitmap(4, 240+offs, bok, bcolor, fcolor);
+ // Content
+ bool mark = false;
+ for (int i = 1; i <= 9; i++) {
+ // Pages
+ if (Rass_Flags[i][0] && Rass_Flags[i][1] && Rass_Flags[i][2] && Rass_Flags[i][3])
+ qosd->DrawBitmap(48, (i*24)+offs, pages4, bcolor, fcolor);
+ else if (Rass_Flags[i][0] && Rass_Flags[i][1] && Rass_Flags[i][2])
+ qosd->DrawBitmap(48, (i*24)+offs, pages3, bcolor, fcolor);
+ else if (Rass_Flags[i][0] && Rass_Flags[i][1])
+ qosd->DrawBitmap(48, (i*24)+offs, pages2, bcolor, fcolor);
+ else if (Rass_Flags[i][0])
+ qosd->DrawBitmap(48, (i*24)+offs, page1, bcolor, fcolor);
+ // Marker
+ if (floor(Rass_Archiv/1000) == i) {
+ qosd->DrawBitmap(28, (i*24)+offs, marker, bcolor, fcolor);
+ mark = true;
+ }
+ }
+ // Gallery
+ if (Rass_GalCount > 0) {
+ char *temp;
+ qosd->DrawBitmap(48, 240+offs, pageE, bcolor, fcolor);
+ asprintf(&temp, "%d", Rass_GalCount);
+ qosd->DrawText(67, 240+offs+(20-fh), temp, fcolor, clrTransparent, ftext, 97, fh);
+ free(temp);
+ }
+ // Marker gallery/index
+ if (!mark) {
+ if (Rass_Archiv > 0 && Rass_Archiv <= RASS_GALMAX)
+ qosd->DrawBitmap(30, 240+offs, marker, bcolor, fcolor);
+ else
+ qosd->DrawBitmap(28, offs, marker, bcolor, fcolor);
+ }
+ qosd->Flush();
+ }
+}
+
+void cRadioTextOsd::RassOsdTip(void)
+{
+ ftext = cFont::GetFont(fontSml);
+ int fh = ftext->Height();
+
+ if (!qosd && !osd && !Skins.IsOpen() && !cOsd::IsOpen()) {
+ qosd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight - (29+(2*fh)-6+36));
+ tArea Area = {0, 0, 97, 29+(2*fh)+5, 4};
+ qosd->SetAreas(&Area, 1);
+ }
+
+ if (qosd) {
+ uint32_t bcolor, fcolor;
+ int skin = theme_skin();
+ // Title
+ bcolor = radioSkin[skin].clrTitleBack;
+ fcolor = radioSkin[skin].clrTitleText;
+ qosd->DrawRectangle(0, 0, 97, 29, bcolor);
+ qosd->DrawEllipse(0, 0, 5, 5, 0x00000000, -2);
+ qosd->DrawEllipse(92, 0, 97, 5, 0x00000000, -1);
+ qosd->DrawBitmap(25, 5, rass, bcolor, fcolor);
+ // Body
+ bcolor = radioSkin[skin].clrBack;
+ fcolor = radioSkin[skin].clrText;
+ qosd->DrawRectangle(0, 29+2, 97, 29+(2*fh)+5, bcolor);
+ qosd->DrawEllipse(0, 29+(2*fh), 5, 29+(2*fh)+5, 0x00000000, -3);
+ qosd->DrawEllipse(92, 29+(2*fh), 97, 29+(2*fh)+5, 0x00000000, -4);
+ qosd->DrawRectangle(5, 29, 92, 29, fcolor);
+ qosd->DrawText(5, 29+4, tr("Records"), fcolor, clrTransparent, ftext, 97, fh);
+ qosd->DrawText(5, 29+fh+4, ".. <0>", fcolor, clrTransparent, ftext, 97, fh);
+ qosd->Flush();
+ }
+}
+
+void cRadioTextOsd::RassOsdClose(void)
+{
+ if (qosd != NULL) {
+ delete qosd;
+ qosd = NULL;
+ }
+}
+
+void cRadioTextOsd::RassImgSave(const char *size, int pos)
+{
+ char *infile, *outfile, *cmd;
+ int filenr = 0, error = 0;
+ struct tm *ts, tm_store;
+
+ if (!enforce_directory(DataDir))
+ return;
+
+ time_t t = time(NULL);
+ ts = localtime_r(&t, &tm_store);
+ switch (pos) {
+ // all from 1-9
+ case 1 ... 9: for (int i = 3; i >= 0; i--) {
+ filenr += (int) (pos * pow(10, i));
+ if (Rass_Flags[pos][3-i]) {
+ asprintf(&infile, "%s/Rass_%d.mpg", DataDir, filenr);
+ asprintf(&outfile, "%s/Rass_%s-%04d_%02d%02d%02d%02d.jpg", DataDir, RT_Titel, filenr,
+ ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
+ asprintf(&cmd, "ffmpeg -i \"%s\" -s %s -f mjpeg -y \"%s\"", infile, size, outfile);
+ if ((error = system(cmd)))
+ i = -1;
+ }
+ }
+ asprintf(&cmd, "%s '%d'", tr("Rass-Image(s) saved from Archiv "), pos);
+ break;
+ // all from gallery
+ case 10: for (int i = Rass_GalStart; i <= Rass_GalEnd; i++) {
+ if (Rass_Gallery[i]) {
+ asprintf(&infile, "%s/Rass_%d.mpg", DataDir, i);
+ asprintf(&outfile, "%s/Rass_%s-Gallery%04d_%02d%02d.jpg", DataDir, RT_Titel, i,
+ ts->tm_mon+1, ts->tm_mday);
+ asprintf(&cmd, "ffmpeg -i \"%s\" -s %s -f mjpeg -y \"%s\"", infile, size, outfile);
+ if ((error = system(cmd)))
+ i = Rass_GalEnd + 1;
+ }
+ }
+ asprintf(&cmd, "%s", tr("Rass-Image(s) saved from Gallery"));
+ break;
+ // single
+ default: asprintf(&infile, "%s/Rass_%d.mpg", DataDir, Rass_Archiv);
+ asprintf(&outfile, "%s/Rass_%s-%04d_%02d%02d%02d%02d.jpg", DataDir, RT_Titel, Rass_Archiv,
+ ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
+ asprintf(&cmd, "ffmpeg -i \"%s\" -s %s -f mjpeg -y \"%s\"", infile, size, outfile);
+ error = system(cmd);
+ asprintf(&cmd, "%s: %s", tr("Rass-Image saved"), outfile);
+ }
+ free(infile);
+
+ // Info
+ RassOsdClose();
+ if (error) {
+ asprintf(&cmd, "%s: %s", tr("Rass-Image failed"), outfile);
+ Skins.Message(mtError, cmd, Setup.OSDMessageTime);
+ }
+ else
+ Skins.Message(mtInfo, cmd, Setup.OSDMessageTime);
+
+ free(outfile);
+ free(cmd);
+}
+
+void cRadioTextOsd::rtp_print(void)
+{
+ struct tm tm_store;
+ time_t t = time(NULL);
+ printf("\n>>> %s-Memoryclasses @ %s", InfoRequest ? "Info" : "RTplus", asctime(localtime_r(&t, &tm_store)));
+ printf(" on '%s' since %s", RT_Titel, asctime(localtime_r(&rtp_content.start, &tm_store)));
+
+ printf("--- Programme ---\n");
+ if (rtp_content.prog_StatShort != NULL) printf("StationShort: %s\n", rtp_content.prog_StatShort);
+ if (rtp_content.prog_Station != NULL) printf(" Station: %s\n", rtp_content.prog_Station);
+ if (rtp_content.prog_Now != NULL) printf(" Now: %s\n", rtp_content.prog_Now);
+ if (rtp_content.prog_Next != NULL) printf(" Next: %s\n", rtp_content.prog_Next);
+ if (rtp_content.prog_Part != NULL) printf(" Part: %s\n", rtp_content.prog_Part);
+ if (rtp_content.prog_Host != NULL) printf(" Host: %s\n", rtp_content.prog_Host);
+ if (rtp_content.prog_EditStaff != NULL) printf(" Ed.Staff: %s\n", rtp_content.prog_EditStaff);
+ if (rtp_content.prog_Homepage != NULL) printf(" Homepage: %s\n", rtp_content.prog_Homepage);
+
+ printf("--- Interactivity ---\n");
+ if (rtp_content.phone_Hotline != NULL) printf(" Phone-Hotline: %s\n", rtp_content.phone_Hotline);
+ if (rtp_content.phone_Studio != NULL) printf(" Phone-Studio: %s\n", rtp_content.phone_Studio);
+ if (rtp_content.sms_Studio != NULL) printf(" SMS-Studio: %s\n", rtp_content.sms_Studio);
+ if (rtp_content.email_Hotline != NULL) printf(" Email-Hotline: %s\n", rtp_content.email_Hotline);
+ if (rtp_content.email_Studio != NULL) printf(" Email-Studio: %s\n", rtp_content.email_Studio);
+
+ printf("--- Info ---\n");
+ if (rtp_content.info_News != NULL) printf(" News: %s\n", rtp_content.info_News);
+ if (rtp_content.info_NewsLocal != NULL) printf(" NewsLocal: %s\n", rtp_content.info_NewsLocal);
+ if (rtp_content.info_DateTime != NULL) printf(" DateTime: %s\n", rtp_content.info_DateTime);
+ if (rtp_content.info_Traffic != NULL) printf(" Traffic: %s\n", rtp_content.info_Traffic);
+ if (rtp_content.info_Alarm != NULL) printf(" Alarm: %s\n", rtp_content.info_Alarm);
+ if (rtp_content.info_Advert != NULL) printf(" Advertisg: %s\n", rtp_content.info_Advert);
+ if (rtp_content.info_Url != NULL) printf(" Url: %s\n", rtp_content.info_Url);
+ // no sorting
+ for (int i = 0; i < MAX_RTPC; i++)
+ if (rtp_content.info_Stock[i] != NULL) printf(" Stock[%02d]: %s\n", i, rtp_content.info_Stock[i]);
+ for (int i = 0; i < MAX_RTPC; i++)
+ if (rtp_content.info_Sport[i] != NULL) printf(" Sport[%02d]: %s\n", i, rtp_content.info_Sport[i]);
+ for (int i = 0; i < MAX_RTPC; i++)
+ if (rtp_content.info_Lottery[i] != NULL) printf(" Lottery[%02d]: %s\n", i, rtp_content.info_Lottery[i]);
+ for (int i = 0; i < MAX_RTPC; i++)
+ if (rtp_content.info_Weather[i] != NULL) printf(" Weather[%02d]: %s\n", i, rtp_content.info_Weather[i]);
+ for (int i = 0; i < MAX_RTPC; i++)
+ if (rtp_content.info_Other[i] != NULL) printf(" Other[%02d]: %s\n", i, rtp_content.info_Other[i]);
+/*
+ printf("--- Item-Playlist ---\n");
+ // no sorting
+ if (rtp_content.item_Index >= 0) {
+ for (int i = 0; i < MAX_RTPC; i++) {
+ if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
+ struct tm tm_store;
+ struct tm *ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
+ printf(" [%02d] %02d:%02d Title: %s | Artist: %s\n",
+ i, ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
+ }
+ }
+ }
+
+ printf("--- Last seen Radiotext ---\n");
+ // no sorting
+ if (rtp_content.rt_Index >= 0) {
+ for (int i = 0; i < 2*MAX_RTPC; i++)
+ if (rtp_content.radiotext[i] != NULL) printf(" [%03d] %s\n", i, rtp_content.radiotext[i]);
+ }
+*/
+ printf("<<<\n");
+}
+
+#define rtplog 0
+eOSState cRadioTextOsd::ProcessKey(eKeys Key)
+{
+ // RTplus Infolog
+ if (rtplog == 1 && (S_Verbose & 0x0f) >= 1) {
+ static int ct = 0;
+ if (++ct >= 60) {
+ ct = 0;
+ rtp_print();
+ }
+ }
+
+ // check end @ replay
+ if (RT_Replay) {
+ int rplayCur, rplayTot;
+ cControl::Control()->GetIndex(rplayCur, rplayTot, false);
+ if (rplayCur >= rplayTot-1) {
+ Hide();
+ return osEnd;
+ }
+ }
+
+ // Timeout or no Info/Rass
+ if (RT_OsdTO || (RT_OsdTOTemp > 0) || (RT_Info < 0)) {
+ Hide();
+ return osEnd;
+ }
+
+ eOSState state = cOsdObject::ProcessKey(Key);
+ if (state != osUnknown) return state;
+
+ // Key pressed ...
+ if (Key != kNone && Key < k_Release) {
+ if (osd) { // Radiotext, -plus Osd
+ switch (Key) {
+ case kBack: RTOsdClose();
+ rtclosed = true;
+ //rassclosed = false;
+ break;
+ case k0: RTOsdClose();
+ RTplus_Osd = true;
+ cRemote::CallPlugin("radio");
+ return osEnd;
+ default: Hide();
+ LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
+ return osEnd;
+ }
+ }
+ else if (qosd && Rass_Archiv >= 0) { // Rass-Archiv Osd
+ int i, pos;
+ pos = (Rass_Archiv > 0 && Rass_Archiv <= RASS_GALMAX) ? 10 : (int) floor(Rass_Archiv/1000);
+ switch (Key) {
+ // back to Slideshow
+ case kBlue:
+ case kBack: if (!RT_Replay)
+ Rass_Archiv = RassImage(-1, 0, false);
+ else {
+ Rass_Archiv = -1;
+ RadioImage->SetBackgroundImage(ReplayFile);
+ }
+ RassOsdClose();
+ rassclosed = rtclosed = false;
+ break;
+ // Archiv-Sides
+ case k0 ... k9: Rass_Archiv = RassImage(Rass_Archiv, Key-k0, false);
+ RassOsd();
+ break;
+ case kOk: if (Rass_Flags[10][0]) {
+ Rass_Archiv = RassImage(Rass_Archiv, 10, true);
+ RassOsd();
+ }
+ break;
+ case kLeft:
+ case kRight: Rass_Archiv = RassImage(Rass_Archiv, pos, (Key == kRight) ? true : false);
+ RassOsd();
+ break;
+ case kDown: (pos == 10) ? i = 0 : i = pos + 1;
+ while (i != pos) {
+ if (Rass_Flags[i][0]) {
+ Rass_Archiv = RassImage(Rass_Archiv, i, true);
+ RassOsd();
+ return osContinue;
+ }
+ if (++i > 10) i = 0;
+ }
+ break;
+ case kUp: (pos == 0) ? i = 10 : i = pos - 1;
+ while (i != pos) {
+ if (Rass_Flags[i][0]) {
+ Rass_Archiv = RassImage(Rass_Archiv, i, true);
+ RassOsd();
+ return osContinue;
+ }
+ if (--i < 0) i = 10;
+ }
+ break;
+ case kRed: RassImgSave("1024x576", 0);
+ break;
+ case kGreen: RassImgSave("1024x576", pos);
+ break;
+ case kYellow: break; // todo, what ?
+ default: Hide();
+ LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
+ return osEnd;
+ }
+ }
+ else if (qosd && Rass_Archiv == -1) { // Rass-Slideshow Osd
+ switch (Key) {
+ // close
+ case kBack: RassOsdClose();
+ rassclosed = true;
+ //rtclosed = false;
+ break;
+ // Archiv-Index
+ case k0: if (Rass_Flags[0][0]) {
+ RassOsdClose();
+ Rass_Archiv = RassImage(0, 0, false);
+ RassOsd();
+ }
+ break;
+ default: Hide();
+ LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
+ return osEnd;
+ }
+ }
+ else { // no RT && no Rass
+ Hide();
+ LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key;
+ return osEnd;
+ }
+ }
+ // no Key pressed ...
+ else if (S_RtOsdTO > 0 && osdtimer.Elapsed()/1000/60 >= (uint)S_RtOsdTO) {
+ RT_OsdTO = true;
+ Hide();
+ return osEnd;
+ }
+ else if (Rass_Archiv >= 0)
+ RassOsd();
+ else if (RT_MsgShow && !rtclosed && (!Rass_Flags[0][0]|| S_RassText >= 2 || rassclosed)) { // Rass_Show == -1
+ RassOsdClose();
+ ShowText();
+ }
+ else if (Rass_Flags[0][0] && !rassclosed && (S_RassText < 2 || rtclosed)) {
+ RTOsdClose();
+ RassOsdTip();
+ }
+
+ return osContinue;
+}
+
+
+// --- cRTplusOsd ------------------------------------------------------
+
+cRTplusOsd::cRTplusOsd(void)
+ : cOsdMenu(RTp_Titel, 3, 12)
+ , cCharSetConv((RT_Charset == 0) ? "ISO-8859-1" : NULL)
+{
+ RTplus_Osd = false;
+
+ bcount = helpmode = 0;
+ listtyp[0] = tr("Radiotext");
+ listtyp[1] = tr("Playlist");
+ listtyp[2] = tr("Sports");
+ listtyp[3] = tr("Lottery");
+ listtyp[4] = tr("Weather");
+ listtyp[5] = tr("Stockmarket");
+ listtyp[6] = tr("Other");
+
+ Load();
+ Display();
+}
+
+cRTplusOsd::~cRTplusOsd()
+{
+}
+
+void cRTplusOsd::Load(void)
+{
+ char text[80];
+
+ struct tm tm_store;
+ struct tm *ts = localtime_r(&rtp_content.start, &tm_store);
+ snprintf(text, sizeof(text), "%s %02d:%02d", InfoRequest ? tr("extra Info since") : tr("RTplus Memory since"), ts->tm_hour, ts->tm_min);
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+
+ snprintf(text, sizeof(text), "-- %s --", tr("Programme"));
+ Add(new cOsdItem(hk(text)));
+ if (rtp_content.prog_StatShort != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Stat.Short"), Convert(rtp_content.prog_StatShort));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_Station != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Station"), Convert(rtp_content.prog_Station));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_Now != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Now"), Convert(rtp_content.prog_Now));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_Part != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("...Part"), Convert(rtp_content.prog_Part));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_Next != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Next"), Convert(rtp_content.prog_Next));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_Host != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Host"), Convert(rtp_content.prog_Host));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_EditStaff != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Edit.Staff"), Convert(rtp_content.prog_EditStaff));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.prog_Homepage != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Homepage"), Convert(rtp_content.prog_Homepage));
+ Add(new cOsdItem(hk(text)));
+ }
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+
+ snprintf(text, sizeof(text), "-- %s --", tr("Interactivity"));
+ Add(new cOsdItem(hk(text)));
+ if (rtp_content.phone_Hotline != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Phone-Hotline"), Convert(rtp_content.phone_Hotline));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.phone_Studio != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Phone-Studio"), Convert(rtp_content.phone_Studio));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.sms_Studio != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("SMS-Studio"), Convert(rtp_content.sms_Studio));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.email_Hotline != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Email-Hotline"), Convert(rtp_content.email_Hotline));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.email_Studio != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Email-Studio"), Convert(rtp_content.email_Studio));
+ Add(new cOsdItem(hk(text)));
+ }
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+
+ snprintf(text, sizeof(text), "-- %s --", tr("Info"));
+ Add(new cOsdItem(hk(text)));
+ if (rtp_content.info_News != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("News"), Convert(rtp_content.info_News));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.info_NewsLocal != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("NewsLocal"), Convert(rtp_content.info_NewsLocal));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.info_DateTime != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("DateTime"), Convert(rtp_content.info_DateTime));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.info_Traffic != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Traffic"), Convert(rtp_content.info_Traffic));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.info_Alarm != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Alarm"), Convert(rtp_content.info_Alarm));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.info_Advert != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Advertising"), Convert(rtp_content.info_Advert));
+ Add(new cOsdItem(hk(text)));
+ }
+ if (rtp_content.info_Url != NULL) {
+ snprintf(text, sizeof(text), "\t%s:\t%s", tr("Url"), Convert(rtp_content.info_Url));
+ Add(new cOsdItem(hk(text)));
+ }
+
+ for (int i = 0; i <= 6; i++)
+ btext[i] = NULL;
+ bcount = 0;
+ asprintf(&btext[bcount++], "%s", listtyp[0]);
+ if (rtp_content.item_Index >= 0)
+ asprintf(&btext[bcount++], "%s", listtyp[1]);
+ if (rtp_content.info_SportIndex >= 0)
+ asprintf(&btext[bcount++], "%s", listtyp[2]);
+ if (rtp_content.info_LotteryIndex >= 0)
+ asprintf(&btext[bcount++], "%s", listtyp[3]);
+ if (rtp_content.info_WeatherIndex >= 0)
+ asprintf(&btext[bcount++], "%s", listtyp[4]);
+ if (rtp_content.info_StockIndex >= 0)
+ asprintf(&btext[bcount++], "%s", listtyp[5]);
+ if (rtp_content.info_OtherIndex >= 0)
+ asprintf(&btext[bcount++], "%s", listtyp[6]);
+
+ switch (bcount) {
+ case 4: if (helpmode == 0)
+ SetHelp(btext[0], btext[1], btext[2], ">>");
+ else if (helpmode == 1)
+ SetHelp("<<", btext[3], NULL, tr("Exit"));
+ break;
+ case 5: if (helpmode == 0)
+ SetHelp(btext[0], btext[1], btext[2], ">>");
+ else if (helpmode == 1)
+ SetHelp("<<", btext[3], btext[4], tr("Exit"));
+ break;
+ case 6: if (helpmode == 0)
+ SetHelp(btext[0], btext[1], btext[2], ">>");
+ else if (helpmode == 1)
+ SetHelp("<<", btext[3], btext[4], ">>");
+ else if (helpmode == 2)
+ SetHelp("<<", btext[5], NULL, tr("Exit"));
+ break;
+ case 7: if (helpmode == 0)
+ SetHelp(btext[0], btext[1], btext[2], ">>");
+ else if (helpmode == 1)
+ SetHelp("<<", btext[3], btext[4], ">>");
+ else if (helpmode == 2)
+ SetHelp("<<", btext[5], btext[6], tr("Exit"));
+ break;
+ default: helpmode = 0;
+ SetHelp(btext[0], btext[1], btext[2], tr("Exit"));
+ }
+}
+
+void cRTplusOsd::Update(void)
+{
+ Clear();
+ Load();
+ Display();
+}
+
+int cRTplusOsd::rtptyp(char *btext)
+{
+ for (int i = 0; i <= 6; i++) {
+ if (strcmp(btext, listtyp[i]) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+void cRTplusOsd::rtp_fileprint(void)
+{
+ struct tm *ts, tm_store;
+ char *fname, *fpath;
+ FILE *fd;
+ int ind, lfd = 0;
+
+ if (!enforce_directory(DataDir))
+ return;
+
+ time_t t = time(NULL);
+ ts = localtime_r(&t, &tm_store);
+ asprintf(&fname, "%s_%s_%04d-%02d-%02d.%02d.%02d", InfoRequest ? "Info" : "RTplus", RT_Titel, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min);
+ asprintf(&fpath, "%s/%s", DataDir, fname);
+ if ((fd = fopen(fpath, "w")) != NULL) {
+
+ fprintf(fd, ">>> %s-Memoryclasses @ %s", InfoRequest ? "Info" : "RTplus", asctime(localtime_r(&t, &tm_store)));
+ fprintf(fd, " on '%s' since %s", RT_Titel, asctime(localtime_r(&rtp_content.start, &tm_store)));
+
+ fprintf(fd, "--- Programme ---\n");
+ if (rtp_content.prog_StatShort != NULL) fprintf(fd, "StationShort: %s\n", rtp_content.prog_StatShort);
+ if (rtp_content.prog_Station != NULL) fprintf(fd, " Station: %s\n", rtp_content.prog_Station);
+ if (rtp_content.prog_Now != NULL) fprintf(fd, " Now: %s\n", rtp_content.prog_Now);
+ if (rtp_content.prog_Part != NULL) fprintf(fd, " Part: %s\n", rtp_content.prog_Part);
+ if (rtp_content.prog_Next != NULL) fprintf(fd, " Next: %s\n", rtp_content.prog_Next);
+ if (rtp_content.prog_Host != NULL) fprintf(fd, " Host: %s\n", rtp_content.prog_Host);
+ if (rtp_content.prog_EditStaff != NULL) fprintf(fd, " Ed.Staff: %s\n", rtp_content.prog_EditStaff);
+ if (rtp_content.prog_Homepage != NULL) fprintf(fd, " Homepage: %s\n", rtp_content.prog_Homepage);
+
+ fprintf(fd, "--- Interactivity ---\n");
+ if (rtp_content.phone_Hotline != NULL) fprintf(fd, " Phone-Hotline: %s\n", rtp_content.phone_Hotline);
+ if (rtp_content.phone_Studio != NULL) fprintf(fd, " Phone-Studio: %s\n", rtp_content.phone_Studio);
+ if (rtp_content.sms_Studio != NULL) fprintf(fd, " SMS-Studio: %s\n", rtp_content.sms_Studio);
+ if (rtp_content.email_Hotline != NULL) fprintf(fd, " Email-Hotline: %s\n", rtp_content.email_Hotline);
+ if (rtp_content.email_Studio != NULL) fprintf(fd, " Email-Studio: %s\n", rtp_content.email_Studio);
+
+ fprintf(fd, "--- Info ---\n");
+ if (rtp_content.info_News != NULL) fprintf(fd, " News: %s\n", rtp_content.info_News);
+ if (rtp_content.info_NewsLocal != NULL) fprintf(fd, " NewsLocal: %s\n", rtp_content.info_NewsLocal);
+ if (rtp_content.info_DateTime != NULL) fprintf(fd, " DateTime: %s\n", rtp_content.info_DateTime);
+ if (rtp_content.info_Traffic != NULL) fprintf(fd, " Traffic: %s\n", rtp_content.info_Traffic);
+ if (rtp_content.info_Alarm != NULL) fprintf(fd, " Alarm: %s\n", rtp_content.info_Alarm);
+ if (rtp_content.info_Advert != NULL) fprintf(fd, " Advertisg: %s\n", rtp_content.info_Advert);
+ if (rtp_content.info_Url != NULL) fprintf(fd, " Url: %s\n", rtp_content.info_Url);
+
+
+ if (rtp_content.item_Index >= 0) {
+ fprintf(fd, "--- Item-Playlist ---\n");
+ ind = rtp_content.item_Index;
+ if (ind < (MAX_RTPC-1) && rtp_content.item_Title[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
+ ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
+ fprintf(fd, " %02d:%02d Title: '%s' | Artist: '%s'\n", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
+ ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
+ fprintf(fd, " %02d:%02d Title: '%s' | Artist: '%s'\n", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]);
+ }
+ }
+ }
+
+ if (rtp_content.info_SportIndex >= 0) {
+ fprintf(fd, "--- Sports ---\n");
+ ind = rtp_content.info_SportIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Sport[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Sport[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Sport[i]);
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Sport[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Sport[i]);
+ }
+ }
+
+ if (rtp_content.info_LotteryIndex >= 0) {
+ fprintf(fd, "--- Lottery ---\n");
+ ind = rtp_content.info_LotteryIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Lottery[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Lottery[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Lottery[i]);
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Lottery[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Lottery[i]);
+ }
+ }
+
+ if (rtp_content.info_WeatherIndex >= 0) {
+ fprintf(fd, "--- Weather ---\n");
+ ind = rtp_content.info_WeatherIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Weather[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Weather[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Weather[i]);
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Weather[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Weather[i]);
+ }
+ }
+
+ if (rtp_content.info_StockIndex >= 0) {
+ fprintf(fd, "--- Stockmarket ---\n");
+ ind = rtp_content.info_StockIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Stock[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Stock[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Stock[i]);
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Stock[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Stock[i]);
+ }
+ }
+
+ if (rtp_content.info_OtherIndex >= 0) {
+ fprintf(fd, "--- Other ---\n");
+ ind = rtp_content.info_OtherIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Other[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Other[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Other[i]);
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Other[i] != NULL)
+ fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Other[i]);
+ }
+ }
+
+ fprintf(fd, "--- Last seen Radiotext ---\n");
+ ind = rtp_content.rt_Index;
+ if (ind < (2*MAX_RTPC-1) && rtp_content.radiotext[ind+1] != NULL) {
+ for (int i = ind+1; i < 2*MAX_RTPC; i++) {
+ if (rtp_content.radiotext[i] != NULL)
+ fprintf(fd, " %03d. %s\n", ++lfd, rtp_content.radiotext[i]);
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.radiotext[i] != NULL)
+ fprintf(fd, " %03d. %s\n", ++lfd, rtp_content.radiotext[i]);
+ }
+
+ fprintf(fd, "<<<\n");
+ fclose(fd);
+
+ char *infotext;
+ asprintf(&infotext, "%s: %s", InfoRequest ? tr("Info-File saved") : tr("RTplus-File saved"), fpath);
+ Skins.Message(mtInfo, infotext, Setup.OSDMessageTime);
+ free(infotext);
+ }
+ else
+ esyslog("radio: ERROR writing RTplus-File failed '%s'", fpath);
+
+ free(fpath);
+ free(fname);
+}
+
+eOSState cRTplusOsd::ProcessKey(eKeys Key)
+{
+ int typ, ind;
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (HasSubMenu())
+ return osContinue;
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kBack:
+ case kOk: return osEnd;
+ case kBlue: if (bcount >= 4 && helpmode == 0) {
+ helpmode += 1;
+ Update();
+ }
+ else if (bcount >= 6 && helpmode == 1) {
+ helpmode += 1;
+ Update();
+ }
+ else
+ return osEnd;
+ break;
+ case k0: Update();
+ break;
+ case k8: rtp_fileprint();
+ break;
+ case kRed: if (helpmode == 0) {
+ if (btext[0] != NULL)
+ if ((typ = rtptyp(btext[0])) >= 0)
+ AddSubMenu(new cRTplusList(typ));
+ }
+ else {
+ helpmode -= 1;
+ Update();
+ }
+ break;
+ case kGreen: ind = (helpmode*2) + 1;
+ if (btext[ind] != NULL) {
+ if ((typ = rtptyp(btext[ind])) >= 0)
+ AddSubMenu(new cRTplusList(typ));
+ }
+ break;
+ case kYellow: ind = (helpmode*2) + 2;
+ if (btext[ind] != NULL) {
+ if ((typ = rtptyp(btext[ind])) >= 0)
+ AddSubMenu(new cRTplusList(typ));
+ }
+ break;
+ default: state = osContinue;
+ }
+ }
+
+ static int ct;
+ if (++ct >= 60) {
+ ct = 0;
+ Update();
+ }
+
+ return state;
+}
+
+
+// --- cRTplusList ------------------------------------------------------
+
+cRTplusList::cRTplusList(int Typ)
+ : cOsdMenu(RTp_Titel, 4)
+ , cCharSetConv((RT_Charset == 0) ? "ISO-8859-1" : NULL)
+{
+ typ = Typ;
+ refresh = false;
+
+ Load();
+ Display();
+}
+
+cRTplusList::~cRTplusList()
+{
+ typ = 0;
+}
+
+void cRTplusList::Load(void)
+{
+ char text[80];
+ struct tm *ts, tm_store;
+ int ind, lfd = 0;
+ char ctitle[80];
+
+ ts = localtime_r(&rtp_content.start, &tm_store);
+ switch (typ) {
+ case 0: snprintf(text, sizeof(text), "-- %s (max. %d) --", tr("last seen Radiotext"), 2*MAX_RTPC);
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.rt_Index;
+ if (ind < (2*MAX_RTPC-1) && rtp_content.radiotext[ind+1] != NULL) {
+ for (int i = ind+1; i < 2*MAX_RTPC; i++) {
+ if (rtp_content.radiotext[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.radiotext[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.radiotext[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.radiotext[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ case 1: SetCols(6, 19, 1);
+ snprintf(text, sizeof(text), "-- %s --", tr("Playlist"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s\t%s\t\t%s", tr("Time"), tr("Title"), tr("Artist"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.item_Index;
+ if (ind < (MAX_RTPC-1) && rtp_content.item_Title[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
+ ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
+ snprintf(ctitle, sizeof(ctitle), "%s", Convert(rtp_content.item_Title[i]));
+ snprintf(text, sizeof(text), "%02d:%02d\t%s\t\t%s", ts->tm_hour, ts->tm_min, ctitle, Convert(rtp_content.item_Artist[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) {
+ ts = localtime_r(&rtp_content.item_Start[i], &tm_store);
+ snprintf(ctitle, sizeof(ctitle), "%s", Convert(rtp_content.item_Title[i]));
+ snprintf(text, sizeof(text), "%02d:%02d\t%s\t\t%s", ts->tm_hour, ts->tm_min, ctitle, Convert(rtp_content.item_Artist[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ case 2: snprintf(text, sizeof(text), "-- %s --", tr("Sports"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.info_SportIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Sport[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Sport[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Sport[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Sport[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Sport[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ case 3: snprintf(text, sizeof(text), "-- %s --", tr("Lottery"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.info_LotteryIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Lottery[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Lottery[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Lottery[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Lottery[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Lottery[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ case 4: snprintf(text, sizeof(text), "-- %s --", tr("Weather"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.info_WeatherIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Weather[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Weather[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Weather[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Weather[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Weather[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ case 5: snprintf(text, sizeof(text), "-- %s --", tr("Stockmarket"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.info_StockIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Stock[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Stock[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Stock[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Stock[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Stock[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ case 6: snprintf(text, sizeof(text), "-- %s --", tr("Other"));
+ Add(new cOsdItem(hk(text)));
+ snprintf(text, sizeof(text), "%s", " ");
+ Add(new cOsdItem(hk(text)));
+ ind = rtp_content.info_OtherIndex;
+ if (ind < (MAX_RTPC-1) && rtp_content.info_Other[ind+1] != NULL) {
+ for (int i = ind+1; i < MAX_RTPC; i++) {
+ if (rtp_content.info_Other[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Other[i]));
+ Add(new cOsdItem(hk(text)));
+ }
+ }
+ }
+ for (int i = 0; i <= ind; i++) {
+ if (rtp_content.info_Other[i] != NULL) {
+ snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Other[i]));
+ Add(new cOsdItem(hk(text)), refresh);
+ }
+ }
+ break;
+ }
+
+ SetHelp(NULL, NULL , refresh ? tr("Refresh Off") : tr("Refresh On"), tr("Back"));
+}
+
+void cRTplusList::Update(void)
+{
+ Clear();
+ Load();
+ Display();
+}
+
+eOSState cRTplusList::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case k0: Update();
+ break;
+ case kYellow: refresh = (refresh) ? false : true;
+ Update();
+ break;
+ case kBack:
+ case kOk:
+ case kBlue: return osBack;
+ default: state = osContinue;
+ }
+ }
+
+ static int ct;
+ if (refresh) {
+ if (++ct >= 20) {
+ ct = 0;
+ Update();
+ }
+ }
+
+ return state;
+}
+
+
+//--------------- End -----------------------------------------------------------------
diff --git a/radioaudio.h b/radioaudio.h
new file mode 100644
index 0000000..90c9cae
--- /dev/null
+++ b/radioaudio.h
@@ -0,0 +1,241 @@
+/*
+ * radioaudio.h - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef __RADIO_AUDIO_H
+#define __RADIO_AUDIO_H
+
+#include <linux/types.h>
+#include <linux/dvb/video.h>
+#include <vdr/player.h>
+#include <vdr/device.h>
+#include <vdr/audio.h>
+#include <vdr/osd.h>
+#include <vdr/menu.h>
+#include <vdr/receiver.h>
+
+extern char *ConfigDir;
+extern char *DataDir;
+extern char *ReplayFile;
+
+//Setup-Params
+extern int S_RtFunc;
+extern int S_StillPic;
+extern int S_RtOsdTitle;
+extern int S_RtOsdTags;
+extern int S_RtOsdPos;
+extern int S_RtOsdRows;
+extern int S_RtOsdLoop;
+extern int S_RtOsdTO;
+extern int S_RtSkinColor;
+extern int S_RtBgCol;
+extern int S_RtBgTra;
+extern int S_RtFgCol;
+extern int S_RtDispl;
+extern int S_RtMsgItems;
+extern int S_RassText;
+extern int S_RockAnt;
+extern uint32_t rt_color[9];
+extern int S_Verbose;
+//Radiotext
+#define RT_MEL 65
+extern char RT_Text[5][RT_MEL];
+extern char RTP_Artist[RT_MEL], RTP_Title[RT_MEL];
+extern int RT_Info, RT_Index, RT_PTY;
+extern time_t RTP_Starttime;
+extern bool RT_OsdTO, RTplus_Osd, RT_ReOpen;
+extern int Radio_CA;
+extern int RT_OsdTOTemp;
+extern int IsRadioOrReplay;
+extern int RT_Charset;
+// Info
+extern bool InfoRequest;
+
+void radioStatusMsg(void);
+
+// seperate thread for showing RadioImages
+class cRadioImage: public cThread {
+private:
+ char *imagepath;
+ bool imageShown;
+ void Show (const char *file);
+ void send_pes_packet(unsigned char *data, int len, int timestamp);
+protected:
+ virtual void Action(void);
+ void Stop(void);
+public:
+ cRadioImage(void);
+ virtual ~cRadioImage();
+ static void Init(void);
+ static void Exit(void);
+ void SetBackgroundImage(const char *Image);
+};
+
+// RDS-Receiver for seperate Data-Pids
+class cRDSReceiver : public cReceiver {
+private:
+ int pid;
+ bool rt_start;
+ bool rt_bstuff;
+protected:
+ virtual void Receive(uchar *Data, int Length);
+public:
+ cRDSReceiver(int Pid);
+ virtual ~cRDSReceiver(void);
+};
+
+class cRadioAudio : public cAudio {
+private:
+ bool enabled;
+ int first_packets;
+ int audiopid;
+ bool bratefound;
+ //Radiotext
+ cDevice *rdsdevice;
+ void RadiotextCheckPES(const uchar *Data, int Length);
+ void RadiotextCheckTS(const uchar *Data, int Length);
+ void AudioRecorderService(void);
+ void RassDecode(uchar *Data, int Length);
+protected:
+ virtual void Play(const uchar *Data, int Length, uchar Id);
+ virtual void PlayTs(const uchar *Data, int Length);
+ virtual void Mute(bool On) {};
+ virtual void Clear(void) {};
+public:
+ cRadioAudio(void);
+ virtual ~cRadioAudio(void);
+ char *bitrate;
+ void EnableRadioTextProcessing(const char *Titel, int apid, bool replay = false);
+ void DisableRadioTextProcessing();
+ void RadiotextDecode(uchar *Data, int Length);
+ void RDS_PsPtynDecode(bool PTYN, uchar *Data, int Length);
+};
+
+class cRadioTextOsd : public cOsdObject, public cCharSetConv {
+private:
+ cOsd *osd;
+ cOsd *qosd;
+ cOsd *qiosd;
+ const cFont *ftitel;
+ const cFont *ftext;
+ int fheight;
+ int bheight;
+ eKeys LastKey;
+ cTimeMs osdtimer;
+ void rtp_print(void);
+ bool rtclosed;
+ bool rassclosed;
+ static cBitmap rds, arec, rass, radio;
+ static cBitmap index, marker, page1, pages2, pages3, pages4, pageE;
+ static cBitmap no0, no1, no2, no3, no4, no5, no6, no7, no8, no9, bok;
+public:
+ cRadioTextOsd();
+ ~cRadioTextOsd();
+ virtual void Hide(void);
+ virtual void Show(void);
+ virtual void ShowText(void);
+ virtual void RTOsdClose(void);
+ int RassImage(int QArchiv, int QKey, bool DirUp);
+ virtual void RassOsd(void);
+ virtual void RassOsdTip(void);
+ virtual void RassOsdClose(void);
+ virtual void RassImgSave(const char *size, int pos);
+ virtual eOSState ProcessKey(eKeys Key);
+ virtual bool IsInteractive(void) { return false; }
+};
+
+class cRTplusOsd : public cOsdMenu, public cCharSetConv {
+private:
+ int bcount;
+ int helpmode;
+ const char *listtyp[7];
+ char *btext[7];
+ int rtptyp(char *btext);
+ void rtp_fileprint(void);
+public:
+ cRTplusOsd(void);
+ virtual ~cRTplusOsd();
+ virtual void Load(void);
+ virtual void Update(void);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+class cRTplusList : public cOsdMenu, public cCharSetConv {
+private:
+ int typ;
+ bool refresh;
+public:
+ cRTplusList(int Typ = 0);
+ ~cRTplusList();
+ virtual void Load(void);
+ virtual void Update(void);
+ virtual eOSState ProcessKey(eKeys Key);
+};
+
+
+// Radiotext-Memory RT+Classes 2.1
+#define MAX_RTPC 50
+struct rtp_classes {
+ time_t start;
+ char temptext[RT_MEL];
+ char *radiotext[2*MAX_RTPC];
+ int rt_Index;
+ // Item
+ bool item_New;
+ char *item_Title[MAX_RTPC]; // 1
+ char *item_Artist[MAX_RTPC]; // 4
+ time_t item_Start[MAX_RTPC];
+ int item_Index;
+ // Info
+ char *info_News; // 12
+ char *info_NewsLocal; // 13
+ char *info_Stock[MAX_RTPC]; // 14
+ int info_StockIndex;
+ char *info_Sport[MAX_RTPC]; // 15
+ int info_SportIndex;
+ char *info_Lottery[MAX_RTPC]; // 16
+ int info_LotteryIndex;
+ char *info_DateTime; // 24
+ char *info_Weather[MAX_RTPC]; // 25
+ int info_WeatherIndex;
+ char *info_Traffic; // 26
+ char *info_Alarm; // 27
+ char *info_Advert; // 28
+ char *info_Url; // 29
+ char *info_Other[MAX_RTPC]; // 30
+ int info_OtherIndex;
+ // Programme
+ char *prog_StatShort; // 31
+ char *prog_Station; // 32
+ char *prog_Now; // 33
+ char *prog_Next; // 34
+ char *prog_Part; // 35
+ char *prog_Host; // 36
+ char *prog_EditStaff; // 37
+ char *prog_Homepage; // 39
+ // Interactivity
+ char *phone_Hotline; // 41
+ char *phone_Studio; // 42
+ char *sms_Studio; // 44
+ char *email_Hotline; // 46
+ char *email_Studio; // 47
+// to be continue...
+};
+
+// plugin audiorecorder service
+struct Audiorecorder_StatusRtpChannel_v1_0 {
+ const cChannel *channel;
+ int status;
+ /*
+ * 0 = channel is unknown ...
+ * 1 = no receiver is attached
+ * 2 = receiver is attached
+ * 3 = actual recording
+ */
+};
+extern const cChannel *chan;
+
+#endif //__RADIO_AUDIO_H
diff --git a/radioepg.c b/radioepg.c
new file mode 100644
index 0000000..69bfff0
--- /dev/null
+++ b/radioepg.c
@@ -0,0 +1,370 @@
+/*
+ * radioepg.c - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include "radioepg.h"
+
+
+// Premiere-Radio
+int epg_premiere(const char *epgtitle, const char *epgdescr, time_t epgstart, time_t epgend)
+{
+ int i;
+ const char *p;
+ char artist[RT_MEL], titel[RT_MEL], album[RT_MEL], jahr[RT_MEL];
+ struct tm tm_store;
+
+ // EPG not actual
+ if (epgtitle == NULL || epgdescr == NULL) {
+ dsyslog("radio: epg_premiere called, no title or description, nextCall in 5 s\n");
+ return 5;
+ }
+
+ // Interpret
+ p = strstr(epgtitle, PEPG_ARTIST);
+ if (p != NULL) {
+ p += strlen(PEPG_ARTIST);
+ strcpy(artist, p);
+ // Titel
+ p = strstr(epgdescr, PEPG_TITEL);
+ if (p != NULL) {
+ p += strlen(PEPG_TITEL);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(titel, p-i, i);
+ titel[i] = '\0';
+ }
+ else
+ sprintf(titel, "---");
+ // Album
+ p = strstr(epgdescr, PEPG_ALBUM);
+ if (p != NULL) {
+ p += strlen(PEPG_ALBUM);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(album, p-i, i);
+ album[i] = '\0';
+ }
+ else
+ sprintf(album, "---");
+ }
+ else { // P-Klassik ?
+ // Komponist
+ p = strstr(epgtitle, PEPG_KOMP);
+ if (p != NULL) {
+ p += strlen(PEPG_KOMP);
+ strcpy(artist, p);
+ // und Interpret
+ p = strstr(epgdescr, PEPG_ARTIST);
+ if (p != NULL) {
+ strcpy(album, artist); // Album = Komponist
+ p += strlen(PEPG_ARTIST);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(artist, p-i, i);
+ artist[i] = '\0';
+ }
+ else
+ sprintf(album, "---");
+ // Werk
+ p = strstr(epgdescr, PEPG_WERK);
+ if (p != NULL) {
+ p += strlen(PEPG_WERK);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(titel, p-i, i);
+ titel[i] = '\0';
+ }
+ else
+ sprintf(titel, "---");
+ }
+ else {
+ sprintf(artist, "---");
+ sprintf(titel, "---");
+ }
+ }
+
+ // Jahr
+ p = strstr(epgdescr, PEPG_JAHR);
+ if (p != NULL) {
+ p += strlen(PEPG_JAHR);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(jahr, p-i, i);
+ jahr[i] = '\0';
+ }
+ else
+ sprintf(jahr, "----");
+ // quick hack for epg-blabla
+ if (strlen(jahr) > 24)
+ sprintf(jahr, "----");
+
+ int nextevent = epgend - time(NULL);
+
+ if (strcmp(RTP_Artist, artist)!=0 || strcmp(RTP_Title, titel)!=0) {
+ snprintf(RTP_Artist, RT_MEL, "%s", artist);
+ snprintf(RTP_Title, RT_MEL, "%s", titel);
+ RTP_Starttime = epgstart;
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ if (strcmp(album, "---") != 0) {
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], " ... %s (%s)", album, jahr);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ }
+ if (++rtp_content.item_Index >= MAX_RTPC)
+ rtp_content.item_Index = 0;
+ if (rtp_content.item_Index >= 0) {
+ rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime;
+ asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist);
+ asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title);
+ }
+ RT_MsgShow = RT_PlusShow = true;
+ (RT_Info > 0) ? : RT_Info = 2;
+ radioStatusMsg();
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("Premiereradio: %s / %s\n", RTP_Artist, RTP_Title);
+ }
+
+ dsyslog("radio: epg_premiere called, nextEvent in %ds\n", nextevent);
+ return (nextevent < 0) ? 10 : nextevent+2;
+}
+
+
+// Kabel Deutschland Radio
+int epg_kdg(const char *epgdescr, time_t epgstart, time_t epgend)
+{
+ int i;
+ const char *p;
+ char artist[RT_MEL], titel[RT_MEL], album[RT_MEL], komp[RT_MEL];
+ struct tm tm_store;
+
+ // EPG not actual
+ if (epgdescr == NULL) {
+ dsyslog("radio: epg_kdg called, no description, nextCall in 5s\n");
+ return 5;
+ }
+
+ // Titel
+ p = strstr(epgdescr, KDEPG_TITEL);
+ if (p != NULL) {
+ p += strlen(KDEPG_TITEL);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(titel, p-i, i);
+ titel[i] = '\0';
+ }
+ else
+ sprintf(titel, "---");
+ // Interpret
+ p = strstr(epgdescr, KDEPG_ARTIST);
+ if (p != NULL) {
+ p += strlen(KDEPG_ARTIST);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(artist, p-i, i);
+ artist[i] = '\0';
+ }
+ else
+ sprintf(artist, "---");
+ // Album
+ p = strstr(epgdescr, KDEPG_ALBUM);
+ if (p != NULL) {
+ p += strlen(KDEPG_ALBUM);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(album, p-i, i);
+ album[i] = '\0';
+ }
+ else
+ sprintf(album, "---");
+ // Komponist
+ p = strstr(epgdescr, KDEPG_KOMP);
+ if (p != NULL) {
+ p += strlen(KDEPG_KOMP);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(komp, p-i, i);
+ komp[i] = '\0';
+ }
+ else
+ sprintf(komp, "---");
+
+ int nextevent = epgend - time(NULL);
+
+ if (strcmp(RTP_Artist, artist)!=0 || strcmp(RTP_Title, titel)!=0) {
+ snprintf(RTP_Artist, RT_MEL, "%s", artist);
+ snprintf(RTP_Title, RT_MEL, "%s", titel);
+ RTP_Starttime = epgstart;
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ if (strcmp(album, "---") != 0) {
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], " ... %s (%s)", album, komp);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ }
+ if (++rtp_content.item_Index >= MAX_RTPC)
+ rtp_content.item_Index = 0;
+ if (rtp_content.item_Index >= 0) {
+ rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime;
+ asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist);
+ asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title);
+ }
+ RT_MsgShow = RT_PlusShow = true;
+ (RT_Info > 0) ? : RT_Info = 2;
+ radioStatusMsg();
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("KDG-Radio: %s / %s\n", RTP_Artist, RTP_Title);
+ }
+
+ dsyslog("radio: epg_kdg called, nextEvent in %ds\n", nextevent);
+ return (nextevent < 0) ? 10 : nextevent+2;
+}
+
+// Unity Media - Music Choice, Kabel
+int epg_unitymedia(const char *epgdescr, time_t epgstart, time_t epgend)
+{
+ int i;
+ const char *p;
+ char artist[RT_MEL], titel[RT_MEL], album[RT_MEL], jahr[RT_MEL], komp[RT_MEL];
+ struct tm tm_store;
+
+ // EPG not actual
+ if (epgdescr == NULL) {
+ dsyslog("radio: epg_unitymedia called, no title or description, nextCall in 5s\n");
+ return 5;
+ }
+
+ // Titel
+ p = strstr(epgdescr, UMEPG_TITEL);
+ if (p != NULL) {
+ p += strlen(UMEPG_TITEL);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(titel, p-i, i);
+ titel[i] = '\0';
+ }
+ else {
+ // Kein titel check for Werk
+ p = strstr(epgdescr, UMEPG_WERK);
+ if (p != NULL) {
+ p += strlen(UMEPG_WERK);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(titel, p-i, i);
+ titel[i] = '\0';
+ }
+ else
+ sprintf(titel, "---");
+ }
+
+ // Interpret
+ p = strstr(epgdescr, UMEPG_ARTIST);
+ if (p != NULL) {
+ p += strlen(UMEPG_ARTIST);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(artist, p-i, i);
+ artist[i] = '\0';
+ }
+ else {
+ p = strstr(epgdescr, UMEPG_KOMP);
+ if (p != NULL) {
+ p += strlen(UMEPG_KOMP);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(artist, p-i, i);
+ artist[i] = '\0';
+ }
+ else
+ sprintf(artist, "---");
+ }
+
+ // Komponist
+ p = strstr(epgdescr, UMEPG_KOMP);
+ if (p != NULL) {
+ p += strlen(UMEPG_KOMP);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(komp, p-i, i);
+ komp[i] = '\0';
+ }
+ else
+ sprintf(komp, "---");
+
+ // Album
+ p = strstr(epgdescr, UMEPG_ALBUM);
+ if (p != NULL) {
+ p += strlen(UMEPG_ALBUM);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(album, p-i, i);
+ album[i] = '\0';
+ }
+ else
+ sprintf(album, "---");
+
+ // Jahr
+ p = strstr(epgdescr, UMEPG_JAHR);
+ if (p != NULL) {
+ p += strlen(UMEPG_JAHR);
+ i = 1;
+ while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i;
+ memcpy(jahr, p-i, i);
+ jahr[i] = '\0';
+ }
+ else
+ sprintf(jahr, "---");
+
+ int nextevent = epgend - time(NULL);
+ if (strcmp(RTP_Artist, artist)!=0 || strcmp(RTP_Title, titel)!=0) {
+ snprintf(RTP_Artist, RT_MEL, "%s", artist);
+ snprintf(RTP_Title, RT_MEL, "%s", titel);
+ RTP_Starttime = epgstart;
+ struct tm *ts = localtime_r(&RTP_Starttime, &tm_store);
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ if (strcmp(album, "---") != 0) {
+ if (++rtp_content.rt_Index >= 2*MAX_RTPC)
+ rtp_content.rt_Index = 0;
+ asprintf(&rtp_content.radiotext[rtp_content.rt_Index], " ... %s (%s)", album, jahr);
+ snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]);
+ RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0;
+ }
+ if (++rtp_content.item_Index >= MAX_RTPC)
+ rtp_content.item_Index = 0;
+ if (rtp_content.item_Index >= 0) {
+ rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime;
+ asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist);
+ asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title);
+ }
+ RT_Charset = 1; // UTF8 ?!?
+ RT_MsgShow = RT_PlusShow = true;
+ (RT_Info > 0) ? : RT_Info = 2;
+ radioStatusMsg();
+ if ((S_Verbose & 0x0f) >= 1)
+ printf("UnityMedia-Radio: %s / %s\n", RTP_Artist, RTP_Title);
+ }
+
+ dsyslog("radio: epg_um called, nextEvent in %ds\n", nextevent);
+ return (nextevent < 0) ? 10 : nextevent+2;
+}
+
+// end
diff --git a/radioepg.h b/radioepg.h
new file mode 100644
index 0000000..56318e6
--- /dev/null
+++ b/radioepg.h
@@ -0,0 +1,61 @@
+/*
+ * radioeph.h - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef _RADIOEPG__H
+#define _RADIOEPG__H
+
+#include <stdio.h>
+#include <time.h>
+#include "radioaudio.h"
+
+extern bool RT_MsgShow, RT_PlusShow;
+extern rtp_classes rtp_content;
+
+
+/* Premiere */
+#define PREMIERERADIO_TID 17 // Premiere changes to SKY, EPG working ???
+// EPG-Info
+#define PEPG_ARTIST "Interpret: "
+#define PEPG_TITEL "Titel: "
+#define PEPG_ALBUM "Album: "
+#define PEPG_JAHR "Jahr: "
+// Klassik
+#define PEPG_WERK "Werk: "
+#define PEPG_KOMP "Komponist: "
+int epg_premiere(const char *epgtitle, const char *epgdescr, time_t epgstart, time_t epgend);
+
+
+/* Kabel Deutschlang */
+#define KDRADIO_TID 10003
+// EPG-Info
+#define KDEPG_ARTIST "Artist: "
+#define KDEPG_TITEL "Song: "
+#define KDEPG_ALBUM "Album: "
+#define KDEPG_KOMP "Comp: "
+int epg_kdg(const char *epgdescr, time_t epgstart, time_t epgend);
+
+
+/* Unity Media, Kabel */
+#define UMRADIO_TID1 111
+#define UMRADIO_TID2 131
+#define UMRADIO_TID3 141
+#define UMRADIO_TID4 181
+#define UMRADIO_TID5 191
+
+// EPG-Info
+#define UMEPG_SUFFIX "Music Choice bei Unitymedia"
+#define UMEPG_ARTIST "Interpret: "
+#define UMEPG_TITEL "Titel: "
+#define UMEPG_ALBUM "Album: "
+#define UMEPG_JAHR "Jahr: "
+#define UMEPG_WERK "Werk: "
+#define UMEPG_KOMP "Komponist: "
+
+int epg_unitymedia(const char *epgdescr, time_t epgstart, time_t epgend);
+
+
+#endif
diff --git a/radioskin.c b/radioskin.c
new file mode 100644
index 0000000..0b4aa18
--- /dev/null
+++ b/radioskin.c
@@ -0,0 +1,345 @@
+/*
+ * radioskin.c - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include "radioskin.h"
+#include <vdr/config.h>
+
+
+const cRadioSkin radioSkin[eRadioSkinMaxNumber] =
+{
+ {
+ // dummy
+ "dummy",
+ 0xFFFCFCFC, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x7F000000, // clrBack
+ 0xFFFCFCFC, // clrText
+ },
+ {
+ // Classic
+ "default~classic",
+ 0xFF00FCFC, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x7F000000, // clrBack
+ 0xFFFCFCFC, // clrText
+ },
+ {
+ // ST:TNG
+ "default~sttng",
+ 0xFFFCC024, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x7F000000, // clrBack
+ 0xFFFCC024, // clrText
+ },
+ {
+ // EgalsTry
+ "default~EgalsTry",
+ 0xDFBEBAC3, // clrTitleBack
+ 0xFF280249, // clrTitleText
+ 0xCA280249, // clrBack
+ 0xDFD4D7DB, // clrText
+ },
+ {
+ // EgalsTry
+ "blue~EgalsTry",
+ 0xDFBEBAC3, // clrTitleBack
+ 0xFF280249, // clrTitleText
+ 0xCA2B1B9E, // clrBack
+ 0xDFCFCFCF, // clrText
+ },
+ {
+ // Enigma
+ "default~Enigma",
+ 0xB84158BC, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xB8DEE5FA, // clrBack
+ 0xFF000000, // clrText
+ },
+ {
+ // Enigma-DarkBlue
+ "DarkBlue~Enigma",
+ 0xB84158BC, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xB82B2B3C, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Enigma-WineRed
+ "WineRed~Enigma",
+ 0xB8BC5241, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xB8FAE2DE, // clrBack
+ 0xFF000000, // clrText
+ },
+ {
+ // Enigma-AppleGreen
+ "AppleGreen~Enigma",
+ 0xB847BC41, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xB8E2FADE, // clrBack
+ 0xFF000000, // clrText
+ },
+ {
+ // Enigma-WomensLike
+ "WomensLike~Enigma",
+ 0xB8BC41B2, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xB8FADEFA, // clrBack
+ 0xFF000000, // clrText
+ },
+ {
+ // Enigma-YellowSun
+ "YellowSun~Enigma",
+ 0xE5ffd927, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0xE5fae9bc, // clrBack
+ 0xFF000000, // clrText
+ },
+ {
+ // Enigma-Black
+ "Black~Enigma",
+ 0xEE37383a, // clrTitleBack
+ 0xFFDDDDDD, // clrTitleText
+ 0xEE3e4044, // clrBack
+ 0xFFDDDDDD, // clrText
+ },
+ {
+ // Enigma-Blue
+ "Blue~Enigma",
+ 0xEE4158BC, // clrTitleBack
+ 0xFFDDDDDD, // clrTitleText
+ 0xEE496DCC, // clrBack
+ 0xFFDDDDDD, // clrText
+ },
+ {
+ // Enigma-Blue2
+ "Blue2~Enigma",
+ 0xEE4158BC, // clrTitleBack
+ 0xFFDDDDDD, // clrTitleText
+ 0xEE393D8C, // clrBack
+ 0xFFDDDDDD, // clrText
+ },
+ {
+ // Enigma-Blue3
+ "Blue3~Enigma",
+ 0xEE4158BC, // clrTitleBack
+ 0xFFDDDDDD, // clrTitleText
+ 0xEE333388, // clrBack
+ 0xFFDDDDDD, // clrText
+ },
+ {
+ // Enigma-Coolblue
+ "Coolblue~Enigma",
+ 0xEEC40000, // clrTitleBack
+ 0xFFDDDDDD, // clrTitleText
+ 0xEE000066, // clrBack
+ 0xFFDDDDDD, // clrText
+ },
+ {
+ // Enigma-Grey
+ "Grey~Enigma",
+ 0xEE5f6064, // clrTitleBack
+ 0xFFDDDDDD, // clrTitleText
+ 0xEE3e4044, // clrBack
+ 0xFFDDDDDD, // clrText
+ },
+ {
+ // Enigma-MoBuntu
+ "MoBuntu~Enigma",
+ 0xDF793809, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xDF200F02, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Enigma-bgw
+ "bgw~Enigma",
+ 0xE5333333, // clrTitleBack
+ 0xFFDCDCDC, // clrTitleText
+ 0xE5DCDCDC, // clrBack
+ 0xFF000000, // clrText
+ },
+ {
+ // DeepBlue
+ "default~DeepBlue",
+ 0xC832557A, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0xC80C0C0C, // clrBack
+ 0xFF9A9A9A, // clrText
+ },
+ {
+ // SilverGreen
+ "default~SilverGreen",
+ 0xD9293841, // clrTitleBack
+ 0xFFB3BDCA, // clrTitleText
+ 0xD9526470, // clrBack
+ 0xFFB3BDCA, // clrText
+ },
+ {
+ // LightBlue 16/256
+ "default~lightblue",
+ 0xC88488AA, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xC853567B, // clrBack
+ 0xFF8488AA, // clrText
+ },
+ {
+ // Soppalusikka
+ "default~soppalusikka",
+ 0xC833AAEE, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0xC8000066, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Soppalusikka-Mint
+ "mint~soppalusikka",
+ 0xCCBBFFFF, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0xBB005555, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Soppalusikka-Orange
+ "orange~soppalusikka",
+ 0xDDFF5500, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x88111100, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Soppalusikka-Vanilla
+ "vanilla~soppalusikka",
+ 0xFF00FCFC, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x7F000000, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Soppalusikka-Blackberry
+ "blackberry~soppalusikka",
+ 0xDD0000C0, // clrTitleBack
+ 0xFFEEEEEE, // clrTitleText
+ 0x88111100, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Soppalusikka-Citron
+ "citron~soppalusikka",
+ 0xDDFCC024, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0xAF101000, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // Elchi-default
+ "default~Elchi",
+ 0xCC2BA7F1, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x77000066, // clrBack
+ 0xFFFCFCFC, // clrText
+ },
+ {
+ // Elchi-MVBlack
+ "MVBlack~Elchi",
+ 0xCC0000C0, // clrTitleBack
+ 0xFFEEEEEE, // clrTitleText
+ 0x88111100, // clrBack
+ 0xFFEEBB22, // clrText
+ },
+ {
+ // Elchi-MVWhite
+ "MVWhite~Elchi",
+ 0xCC0000C0, // clrTitleBack
+ 0xFFEEEEEE, // clrTitleText
+ 0x88CCCCCC, // clrBack
+ 0xFF444488, // clrText
+ },
+ {
+ // Elchi-Moose
+ "Moose~Elchi",
+ 0xCC2BA7F1, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0x77000066, // clrBack
+ 0xFFFCFCFC, // clrText
+ },
+ {
+ // Elchi_Plugin
+ "change~Elchi_Plugin",
+ 0xC833AAEE, // clrTitleBack
+ 0xFF000000, // clrTitleText
+ 0xC8000066, // clrBack
+ 0xFFFFFFFF, // clrText
+ },
+ {
+ // EgalOrange
+ "default~EgalOrange",
+ 0xDFCC8037, // clrTitleBack
+ 0xFF202020, // clrTitleText
+ 0xBF2D4245, // clrBack
+ 0xDFCFCFCF, // clrText
+ },
+ {
+ // Moronimo, can't test it
+ "default~Moronimo",
+ 0xDF3E5578, // clrTitleBack
+ 0xFF9BBAD7, // clrTitleText
+ 0xDF294A6B, // clrBack
+ 0xFF9A9A9A, // clrText
+ },
+ {
+ // Duotone, can't test it
+ "default~DuoTone",
+ 0xFFFCFCFC, // clrTitleBack
+ 0x7F000000, // clrTitleText
+ 0x7F000000, // clrBack
+ 0xFFFCFCFC, // clrText
+ },
+ {
+ // EgalT2-default
+ "default~EgalT2",
+ 0x9F000000, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0x9F000000, // clrBack
+ 0xFFABABAB, // clrText
+ },
+ {
+ // EgalT2-BluYell
+ "bluyell~EgalT2",
+ 0x9F00005F, // clrTitleBack
+ 0xFFFCF680, // clrTitleText
+ 0x9F00005F, // clrBack
+ 0xAFC4BF64, // clrText
+ },
+ {
+ // EgalT2-Purple
+ "purple~EgalT2",
+ 0xAF3e074c, // clrTitleBack
+ 0xFFFFFFFF, // clrTitleText
+ 0xAF3e074c, // clrBack
+ 0xFFABABAB, // clrText
+ },
+};
+
+int theme_skin(void)
+{
+ //printf("vdr-radio: Theme~Skin = %s~%s\n", Setup.OSDTheme, Setup.OSDSkin);
+ char *temp;
+ int i = 0;
+
+ asprintf(&temp, "%s~%s", Setup.OSDTheme, Setup.OSDSkin);
+ for (i = eRadioSkinMaxNumber-1; i > 0; i--) {
+ if (strstr(temp, radioSkin[i].name) != NULL)
+ break;
+ }
+ free(temp);
+
+ return i;
+}
+
+
+//--------------- End -----------------------------------------------------------------
diff --git a/radioskin.h b/radioskin.h
new file mode 100644
index 0000000..b14d3cf
--- /dev/null
+++ b/radioskin.h
@@ -0,0 +1,69 @@
+/*
+ * radioskin.h - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef __RADIO_SKIN_H
+#define __RADIO_SKIN_H
+
+
+enum eRadioSkin
+{
+ eRadioSkinDummy,
+ eRadioSkinClassicDefault,
+ eRadioSkinSttngDefault,
+ eRadioSkinEgalsTryDefault,
+ eRadioSkinEgalsTryBlue,
+ eRadioSkinEnigmaDefault,
+ eRadioSkinEnigmaDarkBlue,
+ eRadioSkinEnigmaWineRed,
+ eRadioSkinEnigmaAppleGreen,
+ eRadioSkinEnigmaWomensLike,
+ eRadioSkinEnigmaYellowSun,
+ eRadioSkinEnigmaBlack,
+ eRadioSkinEnigmaBlue,
+ eRadioSkinEnigmaBlue2,
+ eRadioSkinEnigmaBlue3,
+ eRadioSkinEnigmaCoolblue,
+ eRadioSkinEnigmaGrey,
+ eRadioSkinEnigmaMoBuntu,
+ eRadioSkinEnigmabgw,
+ eRadioSkinDeepBlueDefault,
+ eRadioSkinSilverGreenDefault,
+ eRadioSkinLightBlueDefault,
+ eRadioSkinSoppalusikkaDefault,
+ eRadioSkinSoppalusikkaMint,
+ eRadioSkinSoppalusikkaOrange,
+ eRadioSkinSoppalusikkaVanilla,
+ eRadioSkinSoppalusikkaBlackberry,
+ eRadioSkinSoppalusikkaCitron,
+ eRadioSkinElchiDefault,
+ eRadioSkinElchiMVBlack,
+ eRadioSkinElchiMVWhite,
+ eRadioSkinElchiMoose,
+ eRadioSkinElchiPluginDefault,
+ eRadioSkinEgalOrangeDefault,
+ eRadioSkinMoronimoDefault,
+ eRadioSkinDuotoneDefault,
+ eRadioSkinEgalT2Default,
+ eRadioSkinEgalT2BluYell,
+ eRadioSkinEgalT2Purple,
+ eRadioSkinMaxNumber
+};
+
+struct cRadioSkin
+{
+ const char *name; // Theme~Skin
+ unsigned int clrTitleBack; // Title-Background
+ unsigned int clrTitleText; // Title-Text
+ unsigned int clrBack; // Background
+ unsigned int clrText; // Text
+};
+extern const cRadioSkin radioSkin[eRadioSkinMaxNumber];
+
+int theme_skin(void);
+
+
+#endif //__RADIO_SKIN_H
diff --git a/radiotools.c b/radiotools.c
new file mode 100644
index 0000000..8ca9c19
--- /dev/null
+++ b/radiotools.c
@@ -0,0 +1,1882 @@
+/*
+ * radiotools.c - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <vdr/tools.h>
+#include "radiotools.h"
+#include "radioaudio.h"
+
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+bool file_exists(const char *filename)
+{
+ struct stat file_stat;
+
+ return ((stat(filename, &file_stat) == 0) ? true : false);
+}
+
+bool enforce_directory(const char *path)
+{
+ struct stat sbuf;
+
+ if (stat(path, &sbuf) != 0) {
+ dsyslog("radio: creating directory %s", path);
+ if (mkdir(path, ACCESSPERMS)) {
+ esyslog("radio: ERROR failed to create directory %s", path);
+ return false;
+ }
+ }
+ else {
+ if (!S_ISDIR(sbuf.st_mode)) {
+ esyslog("radio: ERROR failed to create directory %s: file exists but is not a directory", path);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+#define crc_timetest 0
+#if crc_timetest
+ #include <time.h>
+ #include <sys/time.h>
+#endif
+
+unsigned short crc16_ccitt(unsigned char *daten, int len, bool skipfirst)
+{
+#if crc_timetest
+ struct timeval t;
+ unsigned long long tstart = 0;
+ if (gettimeofday(&t, NULL) == 0)
+ tstart = t.tv_sec*1000000 + t.tv_usec;
+#endif
+
+ // CRC16-CCITT: x^16 + x^12 + x^5 + 1
+ // with start 0xffff and result invers
+ register unsigned short crc = 0xffff;
+
+ if (skipfirst) *daten++;
+ while (len--) {
+ crc = (crc >> 8) | (crc << 8);
+ crc ^= *daten++;
+ crc ^= (crc & 0xff) >> 4;
+ crc ^= (crc << 8) << 4;
+ crc ^= ((crc & 0xff) << 4) << 1;
+ }
+
+#if crc_timetest
+ if (tstart > 0 && gettimeofday(&t, NULL) == 0)
+ printf("vdr-radio: crc-calctime = %d usec\n", (int)((t.tv_sec*1000000 + t.tv_usec) - tstart));
+#endif
+
+ return ~(crc);
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+#define EntityChars 56
+const char *entitystr[EntityChars] = { "&apos;", "&amp;", "&quot;", "&gt", "&lt", "&copy;", "&times;", "&nbsp;",
+ "&Auml;", "&auml;", "&Ouml;", "&ouml;", "&Uuml;", "&uuml;", "&szlig;", "&deg;",
+ "&Agrave;", "&Aacute;", "&Acirc;", "&Atilde;", "&agrave;", "&aacute;", "&acirc;", "&atilde;",
+ "&Egrave;", "&Eacute;", "&Ecirc;", "&Euml;", "&egrave;", "&eacute;", "&ecirc;", "&euml;",
+ "&Igrave;", "&Iacute;", "&Icirc;", "&Iuml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;",
+ "&Ograve;", "&Oacute;", "&Ocirc;", "&Otilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;",
+ "&Ugrave;", "&Uacute;", "&Ucirc;", "&Ntilde;", "&ugrave;", "&uacute;", "&ucirc;", "&ntilde;" };
+const char *entitychar[EntityChars] = { "'", "&", "\"", ">", "<", "c", "*", " ",
+ "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß", "°",
+ "À", "Á", "Â", "Ã", "à", "á", "â", "ã",
+ "È", "É", "Ê", "Ë", "è", "é", "ê", "ë",
+ "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï",
+ "Ò", "Ó", "Ô", "Õ", "ò", "ó", "ô", "õ",
+ "Ù", "Ú", "Û", "Ñ", "ù", "ú", "û", "ñ" };
+
+char *rds_entitychar(char *text)
+{
+ int i = 0, l, lof, lre, space;
+ char *temp;
+
+ while (i < EntityChars) {
+ if ((temp = strstr(text, entitystr[i])) != NULL) {
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("RText-Entity: %s\n", text);
+ l = strlen(entitystr[i]);
+ lof = (temp-text);
+ if (strlen(text) < RT_MEL) {
+ lre = strlen(text) - lof - l;
+ space = 1;
+ }
+ else {
+ lre = RT_MEL - 1 - lof - l;
+ space = 0;
+ }
+ memmove(text+lof, entitychar[i], 1);
+ memmove(text+lof+1, temp+l, lre);
+ if (space != 0)
+ memmove(text+lof+1+lre, " ", l-1);
+ }
+ else i++;
+ }
+
+ return text;
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+#define XhtmlChars 56
+const char *xhtmlstr[XhtmlChars] = { "&#039;", "&#038;", "&#034;", "&#062;", "&#060;", "&#169;", "&#042;", "&#160;",
+ "&#196;", "&#228;", "&#214;", "&#246;", "&#220;", "&#252;", "&#223;", "&#176;",
+ "&#192;", "&#193;", "&#194;", "&#195;", "&#224;", "&#225;", "&#226;", "&#227;",
+ "&#200;", "&#201;", "&#202;", "&#203;", "&#232;", "&#233;", "&#234;", "&#235;",
+ "&#204;", "&#205;", "&#206;", "&#207;", "&#236;", "&#237;", "&#238;", "&#239;",
+ "&#210;", "&#211;", "&#212;", "&#213;", "&#242;", "&#243;", "&#244;", "&#245;",
+ "&#217;", "&#218;", "&#219;", "&#209;", "&#249;", "&#250;", "&#251;", "&#241;" };
+/* hex todo: "&#x27;", "&#x26;", */
+/* see *entitychar[]
+const char *xhtmlychar[EntityChars] = { "'", "&", "\"", ">", "<", "c", "*", " ",
+ "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß", "°",
+ "À", "Á", "Â", "Ã", "à", "á", "â", "ã",
+ "È", "É", "Ê", "Ë", "è", "é", "ê", "ë",
+ "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï",
+ "Ò", "Ó", "Ô", "Õ", "ò", "ó", "ô", "õ",
+ "Ù", "Ú", "Û", "Ñ", "ù", "ú", "û", "ñ" };
+*/
+
+char *xhtml2text(char *text)
+{
+ int i = 0, l, lof, lre, space;
+ char *temp;
+
+ while (i < XhtmlChars) {
+ if ((temp = strstr(text, xhtmlstr[i])) != NULL) {
+ if ((S_Verbose & 0x0f) >= 2)
+ printf("XHTML-Char: %s\n", text);
+ l = strlen(xhtmlstr[i]);
+ lof = (temp-text);
+ if (strlen(text) < RT_MEL) {
+ lre = strlen(text) - lof - l;
+ space = 1;
+ }
+ else {
+ lre = RT_MEL - 1 - lof - l;
+ space = 0;
+ }
+ memmove(text+lof, entitychar[i], 1);
+ memmove(text+lof+1, temp+l, lre);
+ if (space != 0)
+ memmove(text+lof+1+lre, " ", l-1);
+ }
+ else i++;
+ }
+
+ rds_entitychar(text);
+ return text;
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+char *rtrim(char *text)
+{
+ char *s = text + strlen(text) - 1;
+ while (s >= text && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
+ *s-- = 0;
+
+ return text;
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+const char *bitrates[5][16] = {
+ // MPEG 1, Layer 1-3
+ { "free", "32k", "64k", "96k", "128k", "160k", "192k", "224k", "256k", "288k", "320k", "352k", "384k", "416k", "448k", "bad" },
+ { "free", "32k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "160k", "192k", "224k", "256k", "320k", "384k", "bad" },
+ { "free", "32k", "40k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "160k", "192k", "224k", "256k", "320k", "bad" }
+/* MPEG 2/2.5, Layer 1+2/3
+ { "free", "32k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "144k", "160k", "176k", "192k", "224k", "256k", "bad" },
+ { "free", "8k", "16k", "24k", "32k", "40k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "144k", "160k", "bad" }
+*/
+};
+
+char *audiobitrate(const unsigned char *data)
+{
+ int hl = (data[8] > 0) ? 9 + data[8] : 9;
+ //printf("vdr-radio: audioheader = <%02x %02x %02x %02x>\n", data[hl], data[hl+1], data[hl+2], data[hl+3]);
+
+ char *temp;
+ if (data[hl] == 0xff && (data[hl+1] & 0xe0) == 0xe0) { // syncword o.k.
+ int layer = (data[hl+1] & 0x06) >> 1; // Layer description
+ if (layer > 0) {
+ switch ((data[hl+1] & 0x18) >> 3) { // Audio Version ID
+ case 0x00: asprintf(&temp, "V2.5");
+ break;
+ case 0x01: asprintf(&temp, "Vres");
+ break;
+ case 0x02: asprintf(&temp, "V2");
+ break;
+ case 0x03: asprintf(&temp, "%s", bitrates[3-layer][data[hl+2] >> 4]);
+ break;
+ }
+ }
+ else
+ asprintf(&temp, "Lres");
+ }
+ else
+ asprintf(&temp, "???");
+
+ return temp;
+}
+
+/* ----------------------------------------------------------------------------------------------------------- */
+
+const char *tmc_duration[8] = {
+ "none",
+ "15 minutes",
+ "30 minutes",
+ "1 hour",
+ "2 hours",
+ "3 hours",
+ "4 hours",
+ "all day",
+};
+
+const char *tmc_direction[2] = { "+", "-" };
+
+const char *tmc_event[2048] = {
+ "---", // 0
+ "traffic problem",
+ "queuing traffic (with average speeds Q). Danger of stationary traffic",
+ "..", "..", "..", "..", "..", "..", "..", "..", // 10
+ "overheight warning system triggered",
+ "(Q) accident(s), traffic being directed around accident area",
+ "..", "..", "..",
+ "closed, rescue and recovery work in progress",
+ "..", "..", "..",
+ "service area overcrowded, drive to another service area", // 20
+ "..",
+ "service area, fuel station closed",
+ "service area, restaurant closed",
+ "bridge closed",
+ "tunnel closed",
+ "bridge blocked",
+ "tunnel blocked",
+ "road closed intermittently",
+ "..", "..", // 30
+ "..", "..", "..", "..", "..",
+ "fuel station reopened",
+ "restaurant reopened",
+ "..", "..",
+ "smog alert ended", // 40
+ "(Q) overtaking lane(s) closed",
+ "(Q) overtaking lane(s) blocked",
+ "..", "..", "..", "..", "..", "..", "..", "..", // 50
+ "roadworks, (Q) overtaking lane(s) closed",
+ "(Q sets of) roadworks on the hard shoulder",
+ "(Q sets of) roadworks in the emergency lane",
+ "..",
+ "traffic problem expected",
+ "traffic congestion expected",
+ "normal traffic expected",
+ "..", "..", "..", // 60
+ "(Q) object(s) on roadway {something that does not neccessarily block the road}",
+ "(Q) burst pipe(s)",
+ "(Q) object(s) on the road. Danger",
+ "burst pipe. Danger",
+ "..", "..", "..", "..", "..",
+ "traffic congestion, average speed of ?? km/h", // 70
+ "traffic congestion, average speed of ?? km/h",
+ "traffic congestion, average speed of ?? km/h",
+ "traffic congestion, average speed of ?? km/h",
+ "traffic congestion, average speed of ?? km/h",
+ "traffic congestion, average speed of ?? km/h",
+ "traffic congestion, average speed of ?? km/h",
+ "..", "..", "..", "..", // 80
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 90
+ "delays (Q) for cars",
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", // 100
+ "stationary traffic",
+ "stationary traffic for 1 km",
+ "stationary traffic for 2 km",
+ "stationary traffic for 4 km",
+ "stationary traffic for 6 km",
+ "stationary traffic for 10 km",
+ "stationary traffic expected",
+ "queuing traffic (with average speeds Q)",
+ "queuing traffic for 1 km (with average speeds Q)",
+ "queuing traffic for 2 km (with average speeds Q)", // 110
+ "queuing traffic for 4 km (with average speeds Q)",
+ "queuing traffic for 6 km (with average speeds Q)",
+ "queuing traffic for 10 km (with average speeds Q)",
+ "queuing traffic expected",
+ "slow traffic (with average speeds Q)",
+ "slow traffic for 1 km (with average speeds Q)",
+ "slow traffic for 2 km (with average speeds Q)",
+ "slow traffic for 4 km (with average speeds Q)",
+ "slow traffic for 6 km (with average speeds Q)",
+ "slow traffic for 10 km (with average speeds Q)", // 120
+ "slow traffic expected",
+ "heavy traffic (with average speeds Q)",
+ "heavy traffic expected",
+ "traffic flowing freely (with average speeds Q)",
+ "traffic building up (with average speeds Q)",
+ "no problems to report",
+ "traffic congestion cleared",
+ "message cancelled",
+ "stationary traffic for 3 km",
+ "danger of stationary traffic", // 130
+ "queuing traffic for 3 km (with average speeds Q)",
+ "danger of queuing traffic (with average speeds Q)",
+ "long queues (with average speeds Q)",
+ "slow traffic for 3 km (with average speeds Q)",
+ "traffic easing",
+ "traffic congestion (with average speeds Q)",
+ "traffic lighter than normal (with average speeds Q)",
+ "queuing traffic (with average speeds Q). Approach with care",
+ "queuing traffic around a bend in the road",
+ "queuing traffic over the crest of a hill", // 140
+ "all accidents cleared, no problems to report",
+ "traffic heavier than normal (with average speeds Q)",
+ "traffic very much heavier than normal (with average speeds Q)",
+ "..", "..", "..", "..", "..", "..", "..", // 150
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 160
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 170
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 180
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 190
+ "..", "..", "..", "..", "..", "..", "..", "..", "..",
+ "multi vehicle pile up. Delays (Q)", // 200
+ "(Q) accident(s)",
+ "(Q) serious accident(s)",
+ "multi-vehicle accident (involving Q vehicles)",
+ "accident involving (a/Q) heavy lorr(y/ies)",
+ "(Q) accident(s) involving hazardous materials",
+ "(Q) fuel spillage accident(s)",
+ "(Q) chemical spillage accident(s)",
+ "vehicles slowing to look at (Q) accident(s)",
+ "(Q) accident(s) in the opposing lanes",
+ "(Q) shed load(s)", // 210
+ "(Q) broken down vehicle(s)",
+ "(Q) broken down heavy lorr(y/ies)",
+ "(Q) vehicle fire(s)",
+ "(Q) incident(s)",
+ "(Q) accident(s). Stationary traffic",
+ "(Q) accident(s). Stationary traffic for 1 km",
+ "(Q) accident(s). Stationary traffic for 2 km",
+ "(Q) accident(s). Stationary traffic for 4 km",
+ "(Q) accident(s). Stationary traffic for 6 km",
+ "(Q) accident(s). Stationary traffic for 10 km", // 220
+ "(Q) accident(s). Danger of stationary traffic",
+ "(Q) accident(s). Queuing traffic",
+ "(Q) accident(s). Queuing traffic for 1 km",
+ "(Q) accident(s). Queuing traffic for 2 km",
+ "(Q) accident(s). Queuing traffic for 4 km",
+ "(Q) accident(s). Queuing traffic for 6 km",
+ "(Q) accident(s). Queuing traffic for 10 km",
+ "(Q) accident(s). Danger of queuing traffic",
+ "(Q) accident(s). Slow traffic",
+ "(Q) accident(s). Slow traffic for 1 km", // 230
+ "(Q) accident(s). Slow traffic for 2 km",
+ "(Q) accident(s). Slow traffic for 4 km",
+ "(Q) accident(s). Slow traffic for 6 km",
+ "(Q) accident(s). Slow traffic for 10 km",
+ "(Q) accident(s). Slow traffic expected",
+ "(Q) accident(s). Heavy traffic",
+ "(Q) accident(s). Heavy traffic expected",
+ "(Q) accident(s). Traffic flowing freely",
+ "(Q) accident(s). Traffic building up",
+ "road closed due to (Q) accident(s)", // 240
+ "(Q) accident(s). Right lane blocked",
+ "(Q) accident(s). Centre lane blocked",
+ "(Q) accident(s). Left lane blocked",
+ "(Q) accident(s). Hard shoulder blocked",
+ "(Q) accident(s). Two lanes blocked",
+ "(Q) accident(s). Three lanes blocked",
+ "accident. Delays (Q)",
+ "accident. Delays (Q) expected",
+ "accident. Long delays (Q)",
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic", // 250
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic for 1 km",
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic for 2 km",
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic for 4 km",
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic for 6 km",
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic for 10 km",
+ "vehicles slowing to look at (Q) accident(s). Danger of stationary traffic",
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic",
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic for 1 km",
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic for 2 km",
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic for 4 km", // 260
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic for 6 km",
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic for 10 km",
+ "vehicles slowing to look at (Q) accident(s). Danger of queuing traffic",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic for 1 km",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic for 2 km",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic for 4 km",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic for 6 km",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic for 10 km",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic expected", // 270
+ "vehicles slowing to look at (Q) accident(s). Heavy traffic",
+ "vehicles slowing to look at (Q) accident(s). Heavy traffic expected",
+ "..",
+ "vehicles slowing to look at (Q) accident(s). Traffic building up",
+ "vehicles slowing to look at accident. Delays (Q)",
+ "vehicles slowing to look at accident. Delays (Q) expected",
+ "vehicles slowing to look at accident. Long delays (Q)",
+ "(Q) shed load(s). Stationary traffic",
+ "(Q) shed load(s). Stationary traffic for 1 km",
+ "(Q) shed load(s). Stationary traffic for 2 km", // 280
+ "(Q) shed load(s). Stationary traffic for 4 km",
+ "(Q) shed load(s). Stationary traffic for 6 km",
+ "(Q) shed load(s). Stationary traffic for 10 km",
+ "(Q) shed load(s). Danger of stationary traffic",
+ "(Q) shed load(s). Queuing traffic",
+ "(Q) shed load(s). Queuing traffic for 1 km",
+ "(Q) shed load(s). Queuing traffic for 2 km",
+ "(Q) shed load(s). Queuing traffic for 4 km",
+ "(Q) shed load(s). Queuing traffic for 6 km",
+ "(Q) shed load(s). Queuing traffic for 10 km", // 290
+ "(Q) shed load(s). Danger of queuing traffic",
+ "(Q) shed load(s). Slow traffic",
+ "(Q) shed load(s). Slow traffic for 1 km",
+ "(Q) shed load(s). Slow traffic for 2 km",
+ "(Q) shed load(s). Slow traffic for 4 km",
+ "(Q) shed load(s). Slow traffic for 6 km",
+ "(Q) shed load(s). Slow traffic for 10 km",
+ "(Q) shed load(s). Slow traffic expected",
+ "(Q) shed load(s). Heavy traffic",
+ "(Q) shed load(s). Heavy traffic expected", // 300
+ "(Q) shed load(s). Traffic flowing freely",
+ "(Q) shed load(s). Traffic building up",
+ "blocked by (Q) shed load(s)",
+ "(Q) shed load(s). Right lane blocked",
+ "(Q) shed load(s). Centre lane blocked",
+ "(Q) shed load(s). Left lane blocked",
+ "(Q) shed load(s). Hard shoulder blocked",
+ "(Q) shed load(s). Two lanes blocked",
+ "(Q) shed load(s). Three lanes blocked",
+ "shed load. Delays (Q)", // 310
+ "shed load. Delays (Q) expected",
+ "shed load. Long delays (Q)",
+ "(Q) broken down vehicle(s). Stationary traffic",
+ "(Q) broken down vehicle(s). Danger of stationary traffic",
+ "(Q) broken down vehicle(s). Queuing traffic",
+ "(Q) broken down vehicle(s). Danger of queuing traffic",
+ "(Q) broken down vehicle(s). Slow traffic",
+ "(Q) broken down vehicle(s). Slow traffic expected",
+ "(Q) broken down vehicle(s). Heavy traffic",
+ "(Q) broken down vehicle(s). Heavy traffic expected", // 320
+ "(Q) broken down vehicle(s). Traffic flowing freely",
+ "(Q) broken down vehicle(s).Traffic building up",
+ "blocked by (Q) broken down vehicle(s).",
+ "(Q) broken down vehicle(s). Right lane blocked",
+ "(Q) broken down vehicle(s). Centre lane blocked",
+ "(Q) broken down vehicle(s). Left lane blocked",
+ "(Q) broken down vehicle(s). Hard shoulder blocked",
+ "(Q) broken down vehicle(s). Two lanes blocked",
+ "(Q) broken down vehicle(s). Three lanes blocked",
+ "broken down vehicle. Delays (Q)", // 330
+ "broken down vehicle. Delays (Q) expected",
+ "broken down vehicle. Long delays (Q)",
+ "accident cleared",
+ "message cancelled",
+ "accident involving (a/Q) bus(es)",
+ "(Q) oil spillage accident(s)",
+ "(Q) overturned vehicle(s)",
+ "(Q) overturned heavy lorr(y/ies)",
+ "(Q) jackknifed trailer(s)",
+ "(Q) jackknifed caravan(s)", // 340
+ "(Q) jackknifed articulated lorr(y/ies)",
+ "(Q) vehicle(s) spun around",
+ "(Q) earlier accident(s)",
+ "accident investigation work",
+ "(Q) secondary accident(s)",
+ "(Q) broken down bus(es)",
+ "(Q) overheight vehicle(s)",
+ "(Q) accident(s). Stationary traffic for 3 km",
+ "(Q) accident(s). Queuing traffic for 3 km",
+ "(Q) accident(s). Slow traffic for 3 km", // 350
+ "(Q) accident(s) in roadworks area",
+ "vehicles slowing to look at (Q) accident(s). Stationary traffic for 3 km",
+ "vehicles slowing to look at (Q) accident(s). Queuing traffic for 3 km",
+ "vehicles slowing to look at (Q) accident(s). Slow traffic for 3 km",
+ "vehicles slowing to look at (Q) accident(s). Danger",
+ "(Q) shed load(s). Stationary traffic for 3 km",
+ "(Q) shed load(s). Queuing traffic for 3 km",
+ "(Q) shed load(s). Slow traffic for 3 km",
+ "(Q) shed load(s). Danger",
+ "(Q) overturned vehicle(s). Stationary traffic", // 360
+ "(Q) overturned vehicle(s). Danger of stationary traffic",
+ "(Q) overturned vehicle(s). Queuing traffic",
+ "(Q) overturned vehicle(s). Danger of queuing traffic",
+ "(Q) overturned vehicle(s). Slow traffic",
+ "(Q) overturned vehicle(s). Slow traffic expected",
+ "(Q) overturned vehicle(s). Heavy traffic",
+ "(Q) overturned vehicle(s). Heavy traffic expected",
+ "(Q) overturned vehicle(s). Traffic building up",
+ "blocked by (Q) overturned vehicle(s)",
+ "(Q) overturned vehicle(s). Right lane blocked", // 370
+ "(Q) overturned vehicle(s). Centre lane blocked",
+ "(Q) overturned vehicle(s). Left lane blocked",
+ "(Q) overturned vehicle(s). Two lanes blocked",
+ "(Q) overturned vehicle(s). Three lanes blocked",
+ "overturned vehicle. Delays (Q)",
+ "overturned vehicle. Delays (Q) expected",
+ "overturned vehicle. Long delays (Q)",
+ "(Q) overturned vehicle(s). Danger",
+ "Stationary traffic due to (Q) earlier accident(s)",
+ "Danger of stationary traffic due to (Q) earlier accident(s)", // 380
+ "Queuing traffic due to (Q) earlier accident(s)",
+ "Danger of queuing traffic due to (Q) earlier accident(s)",
+ "Slow traffic due to (Q) earlier accident(s)",
+ "..",
+ "Heavy traffic due to (Q) earlier accident(s)",
+ "..",
+ "Traffic building up due to (Q) earlier accident(s)",
+ "Delays (Q) due to earlier accident",
+ "..",
+ "Long delays (Q) due to earlier accident", // 390
+ "accident investigation work. Danger",
+ "(Q) secondary accident(s). Danger",
+ "(Q) broken down vehicle(s). Danger",
+ "(Q) broken down heavy lorr(y/ies). Danger",
+ "road cleared",
+ "incident cleared",
+ "rescue and recovery work in progress",
+ "..",
+ "message cancelled",
+ "..", // 400
+ "closed",
+ "blocked",
+ "closed for heavy vehicles (over Q)",
+ "no through traffic for heavy lorries (over Q)",
+ "no through traffic",
+ "(Q th) entry slip road closed",
+ "(Q th) exit slip road closed",
+ "slip roads closed",
+ "slip road restrictions",
+ "closed ahead. Stationary traffic", // 410
+ "closed ahead. Stationary traffic for 1 km",
+ "closed ahead. Stationary traffic for 2 km",
+ "closed ahead. Stationary traffic for 4 km",
+ "closed ahead. Stationary traffic for 6 km",
+ "closed ahead. Stationary traffic for 10 km",
+ "closed ahead. Danger of stationary traffic",
+ "closed ahead. Queuing traffic",
+ "closed ahead. Queuing traffic for 1 km",
+ "closed ahead. Queuing traffic for 2 km",
+ "closed ahead. Queuing traffic for 4 km", // 420
+ "closed ahead. Queuing traffic for 6 km",
+ "closed ahead. Queuing traffic for 10 km",
+ "closed ahead. Danger of queuing traffic",
+ "closed ahead. Slow traffic",
+ "closed ahead. Slow traffic for 1 km",
+ "closed ahead. Slow traffic for 2 km",
+ "closed ahead. Slow traffic for 4 km",
+ "closed ahead. Slow traffic for 6 km",
+ "closed ahead. Slow traffic for 10 km",
+ "closed ahead. Slow traffic expected", // 430
+ "closed ahead. Heavy traffic",
+ "closed ahead. Heavy traffic expected",
+ "closed ahead. Traffic flowing freely",
+ "closed ahead. Traffic building up",
+ "closed ahead. Delays (Q)",
+ "closed ahead. Delays (Q) expected",
+ "closed ahead. Long delays (Q)",
+ "blocked ahead. Stationary traffic",
+ "blocked ahead. Stationary traffic for 1 km",
+ "blocked ahead. Stationary traffic for 2 km", // 440
+ "blocked ahead. Stationary traffic for 4 km",
+ "blocked ahead. Stationary traffic for 6 km",
+ "blocked ahead. Stationary traffic for 10 km",
+ "blocked ahead. Danger of stationary traffic",
+ "blocked ahead. Queuing traffic",
+ "blocked ahead. Queuing traffic for 1 km",
+ "blocked ahead. Queuing traffic for 2 km",
+ "blocked ahead. Queuing traffic for 4 km",
+ "blocked ahead. Queuing traffic for 6 km",
+ "blocked ahead. Queuing traffic for 10 km", // 450
+ "blocked ahead. Danger of queuing traffic",
+ "blocked ahead. Slow traffic",
+ "blocked ahead. Slow traffic for 1 km",
+ "blocked ahead. Slow traffic for 2 km",
+ "blocked ahead. Slow traffic for 4 km",
+ "blocked ahead. Slow traffic for 6 km",
+ "blocked ahead. Slow traffic for 10 km",
+ "blocked ahead. Slow traffic expected",
+ "blocked ahead. Heavy traffic",
+ "blocked ahead. Heavy traffic expected", // 460
+ "blocked ahead. Traffic flowing freely",
+ "blocked ahead. Traffic building up",
+ "blocked ahead. Delays (Q)",
+ "blocked ahead. Delays (Q) expected",
+ "blocked ahead. Long delays (Q)",
+ "slip roads reopened",
+ "reopened",
+ "message cancelled",
+ "closed ahead",
+ "blocked ahead", // 470
+ "(Q) entry slip road(s) closed",
+ "(Q th) entry slip road blocked",
+ "entry blocked",
+ "(Q) exit slip road(s) closed",
+ "(Q th) exit slip road blocked",
+ "exit blocked",
+ "slip roads blocked",
+ "connecting carriageway closed",
+ "parallel carriageway closed",
+ "right-hand parallel carriageway closed", // 480
+ "left-hand parallel carriageway closed",
+ "express lanes closed",
+ "through traffic lanes closed",
+ "local lanes closed",
+ "connecting carriageway blocked",
+ "parallel carriageway blocked",
+ "right-hand parallel carriageway blocked",
+ "left-hand parallel carriageway blocked",
+ "express lanes blocked",
+ "through traffic lanes blocked", // 490
+ "local lanes blocked",
+ "no motor vehicles",
+ "restrictions",
+ "closed for heavy lorries (over Q)",
+ "closed ahead. Stationary traffic for 3 km",
+ "closed ahead. Queuing traffic for 3 km",
+ "closed ahead. Slow traffic for 3 km",
+ "blocked ahead. Stationary traffic for 3 km",
+ "blocked ahead. Queuing traffic for 3 km",
+ "(Q) lane(s) closed", // 500
+ "(Q) right lane(s) closed",
+ "(Q) centre lane(s) closed",
+ "(Q) left lane(s) closed",
+ "hard shoulder closed",
+ "two lanes closed",
+ "three lanes closed",
+ "(Q) right lane(s) blocked",
+ "(Q) centre lane(s) blocked",
+ "(Q) left lane(s) blocked",
+ "hard shoulder blocked", // 510
+ "two lanes blocked",
+ "three lanes blocked",
+ "single alternate line traffic",
+ "carriageway reduced (from Q lanes) to one lane",
+ "carriageway reduced (from Q lanes) to two lanes",
+ "carriageway reduced (from Q lanes) to three lanes",
+ "contraflow",
+ "narrow lanes",
+ "contraflow with narrow lanes",
+ "(Q) lane(s) blocked", // 520
+ "(Q) lanes closed. Stationary traffic",
+ "(Q) lanes closed. Stationary traffic for 1 km",
+ "(Q) lanes closed. Stationary traffic for 2 km",
+ "(Q) lanes closed. Stationary traffic for 4 km",
+ "(Q) lanes closed. Stationary traffic for 6 km",
+ "(Q) lanes closed. Stationary traffic for 10 km",
+ "(Q) lanes closed. Danger of stationary traffic",
+ "(Q) lanes closed. Queuing traffic",
+ "(Q) lanes closed. Queuing traffic for 1 km",
+ "(Q) lanes closed. Queuing traffic for 2 km", // 530
+ "(Q) lanes closed. Queuing traffic for 4 km",
+ "(Q) lanes closed. Queuing traffic for 6 km",
+ "(Q) lanes closed. Queuing traffic for 10 km",
+ "(Q) lanes closed. Danger of queuing traffic",
+ "(Q) lanes closed. Slow traffic",
+ "(Q) lanes closed. Slow traffic for 1 km",
+ "(Q) lanes closed. Slow traffic for 2 km",
+ "(Q) lanes closed. Slow traffic for 4 km",
+ "(Q) lanes closed. Slow traffic for 6 km",
+ "(Q) lanes closed. Slow traffic for 10 km", // 540
+ "(Q) lanes closed. Slow traffic expected",
+ "(Q) lanes closed. Heavy traffic",
+ "(Q) lanes closed. Heavy traffic expected",
+ "(Q)lanes closed. Traffic flowing freely",
+ "(Q)lanes closed. Traffic building up",
+ "carriageway reduced (from Q lanes) to one lane. Stationary traffic",
+ "carriageway reduced (from Q lanes) to one lane. Danger of stationary traffic",
+ "carriageway reduced (from Q lanes) to one lane. Queuing traffic",
+ "carriageway reduced (from Q lanes) to one lane. Danger of queuing traffic",
+ "carriageway reduced (from Q lanes) to one lane. Slow traffic", // 550
+ "carriageway reduced (from Q lanes) to one lane. Slow traffic expected",
+ "carriageway reduced (from Q lanes) to one lane. Heavy traffic",
+ "carriageway reduced (from Q lanes) to one lane. Heavy traffic expected",
+ "carriageway reduced (from Q lanes) to one lane. Traffic flowing freely",
+ "carriageway reduced (from Q lanes) to one lane. Traffic building up",
+ "carriageway reduced (from Q lanes) to two lanes. Stationary traffic",
+ "carriageway reduced (from Q lanes) to two lanes. Danger of stationary traffic",
+ "carriageway reduced (from Q lanes) to two lanes. Queuing traffic",
+ "carriageway reduced (from Q lanes) to two lanes. Danger of queuing traffic",
+ "carriageway reduced (from Q lanes) to two lanes. Slow traffic", // 560
+ "carriageway reduced (from Q lanes) to two lanes. Slow traffic expected",
+ "carriageway reduced (from Q lanes) to two lanes. Heavy traffic",
+ "carriageway reduced (from Q lanes) to two lanes. Heavy traffic expected",
+ "carriageway reduced (from Q lanes) to two lanes. Traffic flowing freely",
+ "carriageway reduced (from Q lanes) to two lanes. Traffic building up",
+ "carriageway reduced (from Q lanes) to three lanes. Stationary traffic",
+ "carriageway reduced (from Q lanes) to three lanes. Danger of stationary traffic",
+ "carriageway reduced (from Q lanes) to three lanes. Queuing traffic",
+ "carriageway reduced (from Q lanes) to three lanes. Danger of queuing traffic",
+ "carriageway reduced (from Q lanes) to three lanes. Slow traffic", // 570
+ "carriageway reduced (from Q lanes) to three lanes. Slow traffic expected",
+ "carriageway reduced (from Q lanes) to three lanes. Heavy traffic",
+ "carriageway reduced (from Q lanes) to three lanes. Heavy traffic expected",
+ "carriageway reduced (from Q lanes) to three lanes. Traffic flowing freely",
+ "carriageway reduced (from Q lanes) to three lanes. Traffic building up",
+ "contraflow. Stationary traffic",
+ "contraflow. Stationary traffic for 1 km",
+ "contraflow. Stationary traffic for 2 km",
+ "contraflow. Stationary traffic for 4 km",
+ "contraflow. Stationary traffic for 6 km", // 580
+ "contraflow. Stationary traffic for 10 km",
+ "contraflow. Danger of stationary traffic",
+ "contraflow. Queuing traffic",
+ "contraflow. Queuing traffic for 1 km",
+ "contraflow. Queuing traffic for 2 km",
+ "contraflow. Queuing traffic for 4 km",
+ "contraflow. Queuing traffic for 6 km",
+ "contraflow. Queuing traffic for 10 km",
+ "contraflow. Danger of queuing traffic",
+ "contraflow. Slow traffic", // 590
+ "contraflow. Slow traffic for 1 km",
+ "contraflow. Slow traffic for 2 km",
+ "contraflow. Slow traffic for 4 km",
+ "contraflow. Slow traffic for 6 km",
+ "contraflow. Slow traffic for 10 km",
+ "contraflow. Slow traffic expected",
+ "contraflow. Heavy traffic",
+ "contraflow. Heavy traffic expected",
+ "contraflow. Traffic flowing freely",
+ "contraflow. Traffic building up", // 600
+ "contraflow. Carriageway reduced (from Q lanes) to one lane",
+ "contraflow. Carriageway reduced (from Q lanes) to two lanes",
+ "contraflow. Carriageway reduced (from Q lanes) to three lanes",
+ "narrow lanes. Stationary traffic",
+ "narrow lanes. Danger of stationary traffic",
+ "narrow lanes. Queuing traffic",
+ "narrow lanes. Danger of queuing traffic",
+ "narrow lanes. Slow traffic",
+ "narrow lanes. Slow traffic expected",
+ "narrow lanes. Heavy traffic", // 610
+ "narrow lanes. Heavy traffic expected",
+ "narrow lanes. Traffic flowing freely",
+ "narrow lanes. Traffic building up",
+ "contraflow with narrow lanes. Stationary traffic",
+ "contraflow with narrow lanes. Stationary traffic. Danger of stationary traffic",
+ "contraflow with narrow lanes. Queuing traffic",
+ "contraflow with narrow lanes. Danger of queuing traffic",
+ "contraflow with narrow lanes. Slow traffic",
+ "contraflow with narrow lanes. Slow traffic expected",
+ "contraflow with narrow lanes. Heavy traffic", // 620
+ "contraflow with narrow lanes. Heavy traffic expected",
+ "contraflow with narrow lanes. Traffic flowing freely",
+ "contraflow with narrow lanes. Traffic building up",
+ "lane closures removed",
+ "message cancelled",
+ "blocked ahead. Slow traffic for 3 km",
+ "no motor vehicles without catalytic converters",
+ "no motor vehicles with even-numbered registration plates",
+ "no motor vehicles with odd-numbered registration plates",
+ "open", // 630
+ "road cleared",
+ "entry reopened",
+ "exit reopened",
+ "all carriageways reopened",
+ "motor vehicle restrictions lifted",
+ "traffic restrictions lifted {reopened for all traffic}",
+ "emergency lane closed",
+ "turning lane closed",
+ "crawler lane closed",
+ "slow vehicle lane closed", // 640
+ "one lane closed",
+ "emergency lane blocked",
+ "turning lane blocked",
+ "crawler lane blocked",
+ "slow vehicle lane blocked",
+ "one lane blocked",
+ "(Q person) carpool lane in operation",
+ "(Q person) carpool lane closed",
+ "(Q person) carpool lane blocked",
+ "carpool restrictions changed (to Q persons per vehicle)", // 650
+ "(Q) lanes closed. Stationary traffic for 3 km",
+ "(Q) lanes closed. Queuing traffic for 3 km",
+ "(Q) lanes closed. Slow traffic for 3 km",
+ "contraflow. Stationary traffic for 3 km",
+ "contraflow. Queuing traffic for 3 km",
+ "contraflow. Slow traffic for 3 km",
+ "lane blockages cleared",
+ "contraflow removed",
+ "(Q person) carpool restrictions lifted",
+ "lane restrictions lifted", // 660
+ "use of hard shoulder allowed",
+ "normal lane regulations restored",
+ "all carriageways cleared",
+ "..", "..", "..", "..", "..", "..", "..", // 670
+ "bus lane available for carpools (with at least Q occupants)",
+ "message cancelled",
+ "message cancelled",
+ "..", "..",
+ "bus lane blocked",
+ "..",
+ "heavy vehicle lane closed",
+ "heavy vehicle lane blocked",
+ "reopened for through traffic", // 680
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 690
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 700
+ "(Q sets of) roadworks",
+ "(Q sets of) major roadworks",
+ "(Q sets of) maintenance work",
+ "(Q sections of) resurfacing work",
+ "(Q sets of) central reservation work",
+ "(Q sets of) road marking work",
+ "bridge maintenance work (at Q bridges)",
+ "(Q sets of) temporary traffic lights",
+ "(Q sections of) blasting work",
+ "(Q sets of) roadworks. Stationary traffic", // 710
+ "(Q sets of) roadworks. Stationary traffic for 1 km",
+ "(Q sets of) roadworks. Stationary traffic for 2 km",
+ "(Q sets of) roadworks. Stationary traffic for 4 km",
+ "(Q sets of) roadworks. Stationary traffic for 6 km",
+ "(Q sets of) roadworks. Stationary traffic for 10 km",
+ "(Q sets of) roadworks. Danger of stationary traffic",
+ "(Q sets of) roadworks. Queuing traffic",
+ "(Q sets of) roadworks. Queuing traffic for 1 km",
+ "(Q sets of) roadworks. Queuing traffic for 2 km",
+ "(Q sets of) roadworks. Queuing traffic for 4 km", // 720
+ "(Q sets of) roadworks. Queuing traffic for 6 km",
+ "(Q sets of) roadworks. Queuing traffic for 10 km",
+ "(Q sets of) roadworks. Danger of queuing traffic",
+ "(Q sets of) roadworks. Slow traffic",
+ "(Q sets of) roadworks. Slow traffic for 1 km",
+ "(Q sets of) roadworks. Slow traffic for 2 km",
+ "(Q sets of) roadworks. Slow traffic for 4 km",
+ "(Q sets of) roadworks. Slow traffic for 6 km",
+ "(Q sets of) roadworks. Slow traffic for 10 km",
+ "(Q sets of) roadworks. Slow traffic expected", // 730
+ "(Q sets of) roadworks. Heavy traffic",
+ "(Q sets of) roadworks. Heavy traffic expected",
+ "(Q sets of) roadworks. Traffic flowing freely",
+ "(Q sets of) roadworks. Traffic building up",
+ "closed due to (Q sets of) roadworks",
+ "(Q sets of) roadworks. Right lane closed",
+ "(Q sets of) roadworks. Centre lane closed",
+ "(Q sets of) roadworks. Left lane closed",
+ "(Q sets of) roadworks. Hard shoulder closed",
+ "(Q sets of) roadworks. Two lanes closed", // 740
+ "(Q sets of) roadworks. Three lanes closed",
+ "(Q sets of) roadworks. Single alternate line traffic",
+ "roadworks. Carriageway reduced (from Q lanes) to one lane",
+ "roadworks. Carriageway reduced (from Q lanes) to two lanes",
+ "roadworks. Carriageway reduced (from Q lanes) to three lanes",
+ "(Q sets of) roadworks. Contraflow",
+ "roadworks. Delays (Q)",
+ "roadworks. Delays (Q) expected",
+ "roadworks. Long delays (Q)",
+ "(Q sections of) resurfacing work. Stationary traffic", // 750
+ "(Q sections of) resurfacing work. Stationary traffic for 1 km",
+ "(Q sections of) resurfacing work. Stationary traffic for 2 km",
+ "(Q sections of) resurfacing work. Stationary traffic for 4 km",
+ "(Q sections of) resurfacing work. Stationary traffic for 6 km",
+ "(Q sections of) resurfacing work. Stationary traffic for 10 km",
+ "(Q sections of) resurfacing work. Danger of stationary traffic",
+ "(Q sections of) resurfacing work. Queuing traffic",
+ "(Q sections of) resurfacing work. Queuing traffic for 1 km",
+ "(Q sections of) resurfacing work. Queuing traffic for 2 km",
+ "(Q sections of) resurfacing work. Queuing traffic for 4 km", // 760
+ "(Q sections of) resurfacing work. Queuing traffic for 6 km",
+ "(Q sections of) resurfacing work. Queuing traffic for 10 km",
+ "(Q sections of) resurfacing work. Danger of queuing traffic",
+ "(Q sections of) resurfacing work. Slow traffic",
+ "(Q sections of) resurfacing work. Slow traffic for 1 km",
+ "(Q sections of) resurfacing work. Slow traffic for 2 km",
+ "(Q sections of) resurfacing work. Slow traffic for 4 km",
+ "(Q sections of) resurfacing work. Slow traffic for 6 km",
+ "(Q sections of) resurfacing work. Slow traffic for 10 km",
+ "(Q sections of) resurfacing work. Slow traffic expected", // 770
+ "(Q sections of) resurfacing work. Heavy traffic",
+ "(Q sections of) resurfacing work. Heavy traffic expected",
+ "(Q sections of) resurfacing work. Traffic flowing freely",
+ "(Q sections of) resurfacing work. Traffic building up",
+ "(Q sections of) resurfacing work. Single alternate line traffic",
+ "resurfacing work. Carriageway reduced (from Q lanes) to one lane",
+ "resurfacing work. Carriageway reduced (from Q lanes) to two lanes",
+ "resurfacing work. Carriageway reduced (from Q lanes) to three lanes",
+ "(Q sections of) resurfacing work. Contraflow",
+ "resurfacing work. Delays (Q)", // 780
+ "resurfacing work. Delays (Q) expected",
+ "resurfacing work. Long delays (Q)",
+ "(Q sets of) road marking work. Stationary traffic",
+ "(Q sets of) road marking work. Danger of stationary traffic",
+ "(Q sets of) road marking work. Queuing traffic",
+ "(Q sets of) road marking work. Danger of queuing traffic",
+ "(Q sets of) road marking work. Slow traffic",
+ "(Q sets of) road marking work. Slow traffic expected",
+ "(Q sets of) road marking work. Heavy traffic",
+ "(Q sets of) road marking work. Heavy traffic expected", // 790
+ "(Q sets of) road marking work. Traffic flowing freely",
+ "(Q sets of) road marking work. Traffic building up",
+ "(Q sets of) road marking work. Right lane closed",
+ "(Q sets of) road marking work. Centre lane closed",
+ "(Q sets of) road marking work. Left lane closed",
+ "(Q sets of) road marking work. Hard shoulder closed",
+ "(Q sets of) road marking work. Two lanes closed",
+ "(Q sets of) road marking work. Three lanes closed",
+ "closed for bridge demolition work (at Q bridges)",
+ "roadworks cleared", // 800
+ "message cancelled",
+ "(Q sets of) long-term roadworks",
+ "(Q sets of) construction work",
+ "(Q sets of) slow moving maintenance vehicles",
+ "bridge demolition work (at Q bridges)",
+ "(Q sets of) water main work",
+ "(Q sets of) gas main work",
+ "(Q sets of) work on buried cables",
+ "(Q sets of) work on buried services",
+ "new roadworks layout", // 810
+ "new road layout",
+ "(Q sets of) roadworks. Stationary traffic for 3 km",
+ "(Q sets of) roadworks. Queuing traffic for 3 km",
+ "(Q sets of) roadworks. Slow traffic for 3 km",
+ "(Q sets of) roadworks during the day time",
+ "(Q sets of) roadworks during off-peak periods",
+ "(Q sets of) roadworks during the night",
+ "(Q sections of) resurfacing work. Stationary traffic for 3 km",
+ "(Q sections of) resurfacing work. Queuing traffic for 3 km",
+ "(Q sections of) resurfacing work. Slow traffic for 3 km", // 820
+ "(Q sets of) resurfacing work during the day time",
+ "(Q sets of) resurfacing work during off-peak periods",
+ "(Q sets of) resurfacing work during the night",
+ "(Q sets of) road marking work. Danger",
+ "(Q sets of) slow moving maintenance vehicles. Stationary traffic",
+ "(Q sets of) slow moving maintenance vehicles. Danger of stationary traffic",
+ "(Q sets of) slow moving maintenance vehicles. Queuing traffic",
+ "(Q sets of) slow moving maintenance vehicles. Danger of queuing traffic",
+ "(Q sets of) slow moving maintenance vehicles. Slow traffic",
+ "(Q sets of) slow moving maintenance vehicles. Slow traffic expected", // 830
+ "(Q sets of) slow moving maintenance vehicles. Heavy traffic",
+ "(Q sets of) slow moving maintenance vehicles. Heavy traffic expected",
+ "(Q sets of) slow moving maintenance vehicles. Traffic flowing freely",
+ "(Q sets of) slow moving maintenance vehicles. Traffic building up",
+ "(Q sets of) slow moving maintenance vehicles. Right lane closed",
+ "(Q sets of) slow moving maintenance vehicles. Centre lane closed",
+ "(Q sets of) slow moving maintenance vehicles. Left lane closed",
+ "(Q sets of) slow moving maintenance vehicles. Two lanes closed",
+ "(Q sets of) slow moving maintenance vehicles. Three lanes closed",
+ "water main work. Delays (Q)", // 840
+ "water main work. Delays (Q) expected",
+ "water main work. Long delays (Q)",
+ "gas main work. Delays (Q)",
+ "gas main work. Delays (Q) expected",
+ "gas main work. Long delays (Q)",
+ "work on buried cables. Delays (Q)",
+ "work on buried cables. Delays (Q) expected",
+ "work on buried cables. Long delays (Q)",
+ "work on buried services. Delays (Q)",
+ "work on buried services. Delays (Q) expected", // 850
+ "work on buried services. Long delays (Q)",
+ "construction traffic merging",
+ "roadwork clearance in progress",
+ "maintenance work cleared",
+ "road layout unchanged",
+ "construction traffic merging. Danger",
+ "..", "..", "..", "..", // 860
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 870
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 880
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 890
+ "..", "..", "..", "..", "..", "..", "..",
+ "obstruction warning withdrawn",
+ "clearance work in progress, road free again",
+ "flooding expected", // 900
+ "(Q) obstruction(s) on roadway {something that does block the road or part of",
+ "(Q) obstructions on the road. Danger",
+ "spillage on the road",
+ "storm damage",
+ "(Q) fallen trees",
+ "(Q) fallen trees. Danger",
+ "flooding",
+ "flooding. Danger",
+ "flash floods",
+ "danger of flash floods", // 910
+ "avalanches",
+ "avalanche risk",
+ "rockfalls",
+ "landslips",
+ "earthquake damage",
+ "road surface in poor condition",
+ "subsidence",
+ "(Q) collapsed sewer(s)",
+ "burst water main",
+ "gas leak", // 920
+ "serious fire",
+ "animals on roadway",
+ "animals on the road. Danger",
+ "clearance work",
+ "blocked by storm damage",
+ "blocked by (Q) fallen trees",
+ "(Q) fallen tree(s). Passable with care",
+ "flooding. Stationary traffic",
+ "flooding. Danger of stationary traffic",
+ "flooding. Queuing traffic", // 930
+ "flooding. Danger of queuing traffic",
+ "flooding. Slow traffic",
+ "flooding. Slow traffic expected",
+ "flooding. Heavy traffic",
+ "flooding. Heavy traffic expected",
+ "flooding. Traffic flowing freely",
+ "flooding. Traffic building up",
+ "closed due to flooding",
+ "flooding. Delays (Q)",
+ "flooding. Delays (Q) expected", // 940
+ "flooding. Long delays (Q)",
+ "flooding. Passable with care",
+ "closed due to avalanches",
+ "avalanches. Passable with care (above Q hundred metres)",
+ "closed due to rockfalls",
+ "rockfalls. Passable with care",
+ "road closed due to landslips",
+ "landslips. Passable with care",
+ "closed due to subsidence",
+ "subsidence. Single alternate line traffic", // 950
+ "subsidence. Carriageway reduced (from Q lanes) to one lane",
+ "subsidence. Carriageway reduced (from Q lanes) to two lanes",
+ "subsidence. Carriageway reduced (from Q lanes) to three lanes",
+ "subsidence. Contraflow in operation",
+ "subsidence. Passable with care",
+ "closed due to sewer collapse",
+ "road closed due to burst water main",
+ "burst water main. Delays (Q)",
+ "burst water main. Delays (Q) expected",
+ "burst water main. Long delays (Q)", // 960
+ "closed due to gas leak",
+ "gas leak. Delays (Q)",
+ "gas leak. Delays (Q) expected",
+ "gas leak. Long delays (Q)",
+ "closed due to serious fire",
+ "serious fire. Delays (Q)",
+ "serious fire. Delays (Q) expected",
+ "serious fire. Long delays (Q)",
+ "closed for clearance work",
+ "road free again", // 970
+ "message cancelled",
+ "storm damage expected",
+ "fallen power cables",
+ "sewer overflow",
+ "ice build-up",
+ "mud slide",
+ "grass fire",
+ "air crash",
+ "rail crash",
+ "blocked by (Q) obstruction(s) on the road", // 980
+ "(Q) obstructions on the road. Passable with care",
+ "blocked due to spillage on roadway",
+ "spillage on the road. Passable with care",
+ "spillage on the road. Danger",
+ "storm damage. Passable with care",
+ "storm damage. Danger",
+ "blocked by fallen power cables",
+ "fallen power cables. Passable with care",
+ "fallen power cables. Danger",
+ "sewer overflow. Danger", // 990
+ "flash floods. Danger",
+ "avalanches. Danger",
+ "closed due to avalanche risk",
+ "avalanche risk. Danger",
+ "closed due to ice build-up",
+ "ice build-up. Passable with care (above Q hundred metres)",
+ "ice build-up. Single alternate traffic",
+ "rockfalls. Danger",
+ "landslips. Danger",
+ "earthquake damage. Danger", // 1000
+ "hazardous driving conditions (above Q hundred metres)",
+ "danger of aquaplaning",
+ "slippery road (above Q hundred metres)",
+ "mud on road",
+ "leaves on road",
+ "ice (above Q hundred metres)",
+ "danger of ice (above Q hundred metres)",
+ "black ice (above Q hundred metres)",
+ "freezing rain (above Q hundred metres)",
+ "wet and icy roads (above Q hundred metres)", // 1010
+ "slush (above Q hundred metres)",
+ "snow on the road (above Q hundred metres)",
+ "packed snow (above Q hundred metres)",
+ "fresh snow (above Q hundred metres)",
+ "deep snow (above Q hundred metres)",
+ "snow drifts (above Q hundred metres)",
+ "slippery due to spillage on roadway",
+ "slippery road (above Q hundred metres) due to snow",
+ "slippery road (above Q hundred metres) due to frost",
+ "road blocked by snow (above Q hundred metres)", // 1020
+ "snow on the road. Carriageway reduced (from Q lanes) to one lane",
+ "snow on the road. Carriageway reduced (from Q lanes) to two lanes",
+ "snow on the road. Carriageway reduced (from Q lanes) to three lanes",
+ "conditions of road surface improved",
+ "message cancelled",
+ "subsidence. Danger",
+ "sewer collapse. Delays (Q)",
+ "sewer collapse. Delays (Q) expected",
+ "sewer collapse. Long delays (Q)",
+ "sewer collapse. Danger", // 1030
+ "burst water main. Danger",
+ "gas leak. Danger",
+ "serious fire. Danger",
+ "clearance work. Danger",
+ "impassable (above Q hundred metres)",
+ "almost impassable (above Q hundred metres)",
+ "extremely hazardous driving conditions (above Q hundred metres)",
+ "difficult driving conditions (above Q hundred metres)",
+ "passable with care (up to Q hundred metres)",
+ "passable (up to Q hundred metres)", // 1040
+ "surface water hazard",
+ "loose sand on road",
+ "loose chippings",
+ "oil on road",
+ "petrol on road",
+ "icy patches (above Q hundred metres)",
+ "danger of icy patches (above Q hundred metres)",
+ "danger of black ice (above Q hundred metres)",
+ "..", "..", // 1050
+ "..", "..", "..",
+ "slippery due to loose sand on roadway",
+ "mud on road. Danger",
+ "loose chippings. Danger",
+ "oil on road. Danger",
+ "petrol on road. Danger",
+ "road surface in poor condition. Danger",
+ "icy patches (above Q hundred metres) on bridges", // 1060
+ "danger of icy patches (above Q hundred metres) on bridges",
+ "icy patches (above Q hundred metres) on bridges, in shaded areas and on s",
+ "impassable for heavy vehicles (over Q)",
+ "impassable (above Q hundred metres) for vehicles with trailers",
+ "driving conditions improved",
+ "rescue and recovery work in progress. Danger",
+ "large animals on roadway",
+ "herds of animals on roadway",
+ "skid hazard reduced",
+ "snow cleared", // 1070
+ "..", "..",
+ "extremely hazardous driving conditions expected (above Q hundred meters",
+ "freezing rain expected (above Q hundred metres)",
+ "danger of road being blocked by snow (above Q hundred metres)",
+ "..", "..", "..",
+ "temperature falling rapidly (to Q)",
+ "extreme heat (up to Q)", // 1080
+ "extreme cold (of Q)",
+ "less extreme temperatures",
+ "current temperature (Q)",
+ "..", "..", "..", "..", "..", "..", "..", // 1090
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1100
+ "heavy snowfall (Q)",
+ "heavy snowfall (Q). Visibility reduced to < ?? m",
+ "heavy snowfall (Q). Visibility reduced to < ?? m",
+ "snowfall (Q)",
+ "snowfall (Q). Visibility reduced to < ?? m",
+ "hail (visibility reduced to Q)",
+ "sleet (visibility reduced to Q)",
+ "thunderstorms (visibility reduced to Q)",
+ "heavy rain (Q)",
+ "heavy rain (Q). Visibility reduced to < ?? m", // 1110
+ "heavy rain (Q). Visibility reduced to < ?? m",
+ "rain (Q)",
+ "rain (Q). Visibility reduced to < ?? m",
+ "showers (visibility reduced to Q)",
+ "heavy frost",
+ "frost",
+ "..", "..", "..", "..", // 1120
+ "..", "..", "..", "..", "..",
+ "weather situation improved",
+ "message cancelled",
+ "winter storm (visibility reduced to Q)",
+ "..",
+ "blizzard (visibility reduced to Q)", // 1130
+ "..",
+ "damaging hail (visibility reduced to Q)",
+ "..",
+ "heavy snowfall. Visibility reduced (to Q)",
+ "snowfall. Visibility reduced (to Q)",
+ "heavy rain. Visibility reduced (to Q)",
+ "rain. Visibility reduced (to Q)",
+ "..", "..", "..", // 1140
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1150
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1160
+ "..", "..", "..", "..", "..", "..", "..", "..", "..",
+ "heavy snowfall (Q) expected", // 1170
+ "heavy rain (Q) expected",
+ "weather expected to improve",
+ "blizzard (with visibility reduced to Q) expected",
+ "damaging hail (with visibility reduced to Q) expected",
+ "reduced visibility (to Q) expected",
+ "freezing fog expected (with visibility reduced to Q). Danger of slippery roads",
+ "dense fog (with visibility reduced to Q) expected",
+ "patchy fog (with visibility reduced to Q) expected",
+ "visibility expected to improve",
+ "adverse weather warning withdrawn", // 1180
+ "..", "..", "..", "..", "..", "..", "..", "..", "..",
+ "severe smog", // 1190
+ "severe exhaust pollution",
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1200
+ "tornadoes",
+ "hurricane force winds (Q)",
+ "gales (Q)",
+ "storm force winds (Q)",
+ "strong winds (Q)",
+ "..", "..", "..",
+ "gusty winds (Q)",
+ "crosswinds (Q)", // 1210
+ "strong winds (Q) affecting high-sided vehicles",
+ "closed for high-sided vehicles due to strong winds (Q)",
+ "strong winds easing",
+ "message cancelled",
+ "restrictions for high-sided vehicles lifted",
+ "..",
+ "tornado warning ended",
+ "..", "..", "..", // 1220
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1230
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1240
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1250
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1260
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1270
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1280
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1290
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1300
+ "dense fog (visibility reduced to Q)",
+ "dense fog. Visibility reduced to < ?? m",
+ "dense fog. Visibility reduced to < ?? m",
+ "fog (visibility reduced to Q)",
+ "fog. Visibility reduced to < ?? m",
+ "..",
+ "patchy fog (visibility reduced to Q)",
+ "freezing fog (visibility reduced to Q)",
+ "smoke hazard (visibility reduced to Q)",
+ "blowing dust (visibility reduced to Q)", // 1310
+ "..",
+ "snowfall and fog (visibility reduced to Q)",
+ "visibility improved",
+ "message cancelled",
+ "..", "..", "..",
+ "visibility reduced (to Q)",
+ "visibility reduced to < ?? m",
+ "visibility reduced to < ?? m", // 1320
+ "visibility reduced to < ?? m",
+ "white out (visibility reduced to Q)",
+ "blowing snow (visibility reduced to Q)",
+ "spray hazard (visibility reduced to Q)",
+ "low sun glare",
+ "sandstorms (visibility reduced to Q)",
+ "..", "..", "..", "..", // 1330
+ "..",
+ "smog alert",
+ "..", "..", "..", "..",
+ "freezing fog (visibility reduced to Q). Slippery roads",
+ "no motor vehicles due to smog alert",
+ "..",
+ "swarms of insects (visibility reduced to Q)", // 1340
+ "..", "..", "..", "..",
+ "fog clearing",
+ "fog forecast withdrawn",
+ "..", "..", "..", "..", // 1350
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1360
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1370
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1380
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1390
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1400
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1410
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1420
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1430
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1440
+ "..", "..", "..", "..", "..", "..", "..", "..", "..",
+ "international sports meeting", // 1450
+ "match",
+ "tournament",
+ "athletics meeting",
+ "ball game",
+ "boxing tournament",
+ "bull fight",
+ "cricket match",
+ "cycle race",
+ "football match",
+ "golf tournament", // 1460
+ "marathon",
+ "race meeting",
+ "rugby match",
+ "show jumping",
+ "tennis tournament",
+ "water sports meeting",
+ "winter sports meeting",
+ "funfair",
+ "trade fair",
+ "procession", // 1470
+ "sightseers obstructing access",
+ "people on roadway",
+ "children on roadway",
+ "cyclists on roadway",
+ "strike",
+ "security incident",
+ "police checkpoint",
+ "terrorist incident",
+ "gunfire on roadway, danger",
+ "civil emergency", // 1480
+ "air raid, danger",
+ "people on roadway. Danger",
+ "children on roadway. Danger",
+ "cyclists on roadway. Danger",
+ "closed due to security incident",
+ "security incident. Delays (Q)",
+ "security incident. Delays (Q) expected",
+ "security incident. Long delays (Q)",
+ "police checkpoint. Delays (Q)",
+ "police checkpoint. Delays (Q) expected", // 1490
+ "police checkpoint. Long delays (Q)",
+ "security alert withdrawn",
+ "sports traffic cleared",
+ "evacuation",
+ "evacuation. Heavy traffic",
+ "traffic disruption cleared",
+ "..", "..", "..", "..", // 1500
+ "major event",
+ "sports event meeting",
+ "show",
+ "festival",
+ "exhibition",
+ "fair",
+ "market",
+ "ceremonial event",
+ "state occasion",
+ "parade", // 1510
+ "crowd",
+ "march",
+ "demonstration",
+ "public disturbance",
+ "security alert",
+ "bomb alert",
+ "major event. Stationary traffic",
+ "major event. Danger of stationary traffic",
+ "major event. Queuing traffic",
+ "major event. Danger of queuing traffic", // 1520
+ "major event. Slow traffic",
+ "major event. Slow traffic expected",
+ "major event. Heavy traffic",
+ "major event. Heavy traffic expected",
+ "major event. Traffic flowing freely",
+ "major event. Traffic building up",
+ "closed due to major event",
+ "major event. Delays (Q)",
+ "major event. Delays (Q) expected",
+ "major event. Long delays (Q)", // 1530
+ "sports meeting. Stationary traffic",
+ "sports meeting. Danger of stationary traffic",
+ "sports meeting. Queuing traffic",
+ "sports meeting. Danger of queuing traffic",
+ "sports meeting. Slow traffic",
+ "sports meeting. Slow traffic expected",
+ "sports meeting. Heavy traffic",
+ "sports meeting. Heavy traffic expected",
+ "sports meeting. Traffic flowing freely",
+ "sports meeting. Traffic building up", // 1540
+ "closed due to sports meeting",
+ "sports meeting. Delays (Q)",
+ "sports meeting. Delays (Q) expected",
+ "sports meeting. Long delays (Q)",
+ "fair. Stationary traffic",
+ "fair. Danger of stationary traffic",
+ "fair. Queuing traffic",
+ "fair. Danger of queuing traffic",
+ "fair. Slow traffic",
+ "fair. Slow traffic expected", // 1550
+ "fair. Heavy traffic",
+ "fair. Heavy traffic expected",
+ "fair. Traffic flowing freely",
+ "fair. Traffic building up",
+ "closed due to fair",
+ "fair. Delays (Q)",
+ "fair. Delays (Q) expected",
+ "fair. Long delays (Q)",
+ "closed due to parade",
+ "parade. Delays (Q)", // 1560
+ "parade. Delays (Q) expected",
+ "parade. Long delays (Q)",
+ "closed due to strike",
+ "strike. Delays (Q)",
+ "strike. Delays (Q) expected",
+ "strike. Long delays (Q)",
+ "closed due to demonstration",
+ "demonstration. Delays (Q)",
+ "demonstration. Delays (Q) expected",
+ "demonstration. Long delays (Q)", // 1570
+ "security alert. Stationary traffic",
+ "security alert. Danger of stationary traffic",
+ "security alert. Queuing traffic",
+ "security alert. Danger of queuing traffic",
+ "security alert. Slow traffic",
+ "security alert. Slow traffic expected",
+ "security alert. Heavy traffic",
+ "security alert. Heavy traffic expected",
+ "security alert. Traffic building up",
+ "closed due to security alert", // 1580
+ "security alert. Delays (Q)",
+ "security alert. Delays (Q) expected",
+ "security alert. Long delays (Q)",
+ "traffic has returned to normal",
+ "message cancelled",
+ "security alert. Traffic flowing freely",
+ "air raid warning cancelled",
+ "civil emergency cancelled",
+ "message cancelled",
+ "several major events", // 1590
+ "information about major event no longer valid",
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1600
+ "delays (Q)",
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to one hour",
+ "delays up to two hours",
+ "delays of several hours",
+ "delays (Q) expected",
+ "long delays (Q)",
+ "delays (Q) for heavy vehicles",
+ "delays up to ?? minutes for heavy lorr(y/ies)", // 1610
+ "delays up to ?? minutes for heavy lorr(y/ies)",
+ "delays up to one hour for heavy lorr(y/ies)",
+ "delays up to two hours for heavy lorr(y/ies)",
+ "delays of several hours for heavy lorr(y/ies)",
+ "service suspended (until Q)",
+ "(Q) service withdrawn",
+ "(Q) service(s) fully booked",
+ "(Q) service(s) fully booked for heavy vehicles",
+ "normal services resumed",
+ "message cancelled", // 1620
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to ?? minutes",
+ "delays up to three hours",
+ "delays up to four hours",
+ "delays up to five hours", // 1630
+ "very long delays (Q)",
+ "delays of uncertain duration",
+ "delayed until further notice",
+ "cancellations",
+ "park and ride service not operating (until Q)",
+ "special public transport services operating (until Q)",
+ "normal services not operating (until Q)",
+ "rail services not operating (until Q)",
+ "bus services not operating (until Q)",
+ "shuttle service operating (until Q)", // 1640
+ "free shuttle service operating (until Q)",
+ "delays (Q) for heavy lorr(y/ies)",
+ "delays (Q) for buses",
+ "(Q) service(s) fully booked for heavy lorr(y/ies)",
+ "(Q) service(s) fully booked for buses",
+ "next departure (Q) for heavy lorr(y/ies)",
+ "next departure (Q) for buses",
+ "delays cleared",
+ "rapid transit service not operating (until Q)",
+ "delays (Q) possible", // 1650
+ "underground service not operating (until Q)",
+ "cancellations expected",
+ "long delays expected",
+ "very long delays expected",
+ "all services fully booked (until Q)",
+ "next arrival (Q)",
+ "rail services irregular. Delays (Q)",
+ "bus services irregular. Delays (Q)",
+ "underground services irregular",
+ "normal public transport services resumed", // 1660
+ "ferry service not operating (until Q)",
+ "park and ride trip time (Q)",
+ "delay expected to be cleared",
+ "..", "..", "..", "..", "..", "..", "..", // 1670
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1680
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1690
+ "..", "..", "..", "..",
+ "current trip time (Q)",
+ "expected trip time (Q)",
+ "..", "..", "..",
+ "(Q) slow moving maintenance vehicle(s)", // 1700
+ "(Q) vehicle(s) on wrong carriageway",
+ "dangerous vehicle warning cleared",
+ "message cancelled",
+ "(Q) reckless driver(s)",
+ "(Q) prohibited vehicle(s) on the roadway",
+ "(Q) emergency vehicles",
+ "(Q) high-speed emergency vehicles",
+ "high-speed chase (involving Q vehicles)",
+ "spillage occurring from moving vehicle",
+ "objects falling from moving vehicle", // 1710
+ "emergency vehicle warning cleared",
+ "road cleared",
+ "..", "..", "..", "..", "..", "..", "..",
+ "rail services irregular", // 1720
+ "public transport services not operating",
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1730
+ "(Q) abnormal load(s), danger",
+ "(Q) wide load(s), danger",
+ "(Q) long load(s), danger",
+ "(Q) slow vehicle(s), danger",
+ "(Q) track-laying vehicle(s), danger",
+ "(Q) vehicle(s) carrying hazardous materials. Danger",
+ "(Q) convoy(s), danger",
+ "(Q) military convoy(s), danger",
+ "(Q) overheight load(s), danger",
+ "abnormal load causing slow traffic. Delays (Q)", // 1740
+ "convoy causing slow traffic. Delays (Q)",
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1750
+ "(Q) abnormal load(s)",
+ "(Q) wide load(s)",
+ "(Q) long load(s)",
+ "(Q) slow vehicle(s)",
+ "(Q) convoy(s)",
+ "abnormal load. Delays (Q)",
+ "abnormal load. Delays (Q) expected",
+ "abnormal load. Long delays (Q)",
+ "convoy causing delays (Q)",
+ "convoy. Delays (Q) expected", // 1760
+ "convoy causing long delays (Q)",
+ "exceptional load warning cleared",
+ "message cancelled",
+ "(Q) track-laying vehicle(s)",
+ "(Q) vehicle(s) carrying hazardous materials",
+ "(Q) military convoy(s)",
+ "(Q) abnormal load(s). No overtaking",
+ "Vehicles carrying hazardous materials have to stop at next safe place!",
+ "hazardous load warning cleared",
+ "convoy cleared", // 1770
+ "warning cleared",
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1780
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1790
+ "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1800
+ "lane control signs not working",
+ "emergency telephones not working",
+ "emergency telephone number not working",
+ "(Q sets of) traffic lights not working",
+ "(Q sets of) traffic lights working incorrectly",
+ "level crossing failure",
+ "(Q sets of) traffic lights not working. Stationary traffic",
+ "(Q sets of) traffic lights not working. Danger of stationary traffic",
+ "(Q sets of) traffic lights not working. Queuing traffic",
+ "(Q sets of) traffic lights not working. Danger of queuing traffic", // 1810
+ "(Q sets of) traffic lights not working. Slow traffic",
+ "(Q sets of) traffic lights not working. Slow traffic expected",
+ "(Q sets of) traffic lights not working. Heavy traffic",
+ "(Q sets of) traffic lights not working. Heavy traffic expected",
+ "(Q sets of) traffic lights not working. Traffic flowing freely",
+ "(Q sets of) traffic lights not working. Traffic building up",
+ "traffic lights not working. Delays (Q)",
+ "traffic lights not working. Delays (Q) expected",
+ "traffic lights not working. Long delays (Q)",
+ "level crossing failure. Stationary traffic", // 1820
+ "level crossing failure. Danger of stationary traffic",
+ "level crossing failure. Queuing traffic",
+ "level crossing failure. Danger of queuing traffic",
+ "level crossing failure. Slow traffic",
+ "level crossing failure. Slow traffic expected",
+ "level crossing failure. Heavy traffic",
+ "level crossing failure. Heavy traffic expected",
+ "level crossing failure. Traffic flowing freely",
+ "level crossing failure. Traffic building up",
+ "level crossing failure. Delays (Q)", // 1830
+ "level crossing failure. Delays (Q) expected",
+ "level crossing failure. Long delays (Q)",
+ "electronic signs repaired",
+ "emergency call facilities restored",
+ "traffic signals repaired",
+ "level crossing now working normally",
+ "message cancelled",
+ "lane control signs working incorrectly",
+ "lane control signs operating",
+ "variable message signs not working", // 1840
+ "variable message signs working incorrectly",
+ "variable message signs operating",
+ "(Q sets of) ramp control signals not working",
+ "(Q sets of) ramp control signals working incorrectly",
+ "(Q sets of) temporary traffic lights not working",
+ "(Q sets of) temporary traffic lights working incorrectly",
+ "traffic signal control computer not working",
+ "traffic signal timings changed",
+ "tunnel ventilation not working",
+ "lane control signs not working. Danger", // 1850
+ "temporary width limit (Q)",
+ "temporary width limit lifted",
+ "..",
+ "traffic regulations have been changed",
+ "less than parking spaces available",
+ "no parking information available (until Q)",
+ "message cancelled",
+ "..", "..", "..", // 1860
+ "temporary height limit (Q)",
+ "temporary height limit lifted",
+ "..",
+ "lane control signs working incorrectly. Danger",
+ "emergency telephones out of order. Extra police patrols in operation",
+ "emergency telephones out of order. In emergency, wait for police patrol",
+ "(Q sets of) traffic lights not working. Danger",
+ "traffic lights working incorrectly. Delays (Q)",
+ "traffic lights working incorrectly. Delays (Q) expected",
+ "traffic lights working incorrectly. Long delays (Q)", // 1870
+ "temporary axle load limit (Q)",
+ "temporary gross weight limit (Q)",
+ "temporary gross weight limit lifted",
+ "temporary axle weight limit lifted",
+ "(Q sets of) traffic lights working incorrectly. Danger",
+ "temporary traffic lights not working. Delays (Q)",
+ "temporary traffic lights not working. Delays (Q) expected",
+ "temporary traffic lights not working. Long delays (Q)",
+ "(Q sets of) temporary traffic lights not working. Danger",
+ "traffic signal control computer not working. Delays (Q)", // 1880
+ "temporary length limit (Q)",
+ "temporary length limit lifted",
+ "message cancelled",
+ "traffic signal control computer not working. Delays (Q) expected",
+ "traffic signal control computer not working. Long delays (Q)",
+ "normal parking restrictions lifted",
+ "special parking restrictions in force",
+ "10% full",
+ "20% full",
+ "30% full", // 1890
+ "40% full",
+ "50% full",
+ "60% full",
+ "70% full",
+ "80% full",
+ "90% full",
+ "less than ?? parking spaces available",
+ "less than ?? parking spaces available",
+ "less than ?? parking spaces available",
+ "less than ?? parking spaces available", // 1900
+ "next departure (Q)",
+ "next departure (Q) for heavy vehicles",
+ "car park (Q) full",
+ "all car parks (Q) full",
+ "less than (Q) car parking spaces available",
+ "park and ride service operating (until Q)",
+ "(null event)",
+ "switch your car radio (to Q)",
+ "alarm call: important new information on this frequency follows now in normal",
+ "alarm set: new information will be broadcast between these times in normal", // 1910
+ "message cancelled",
+ "..",
+ "switch your car radio (to Q)",
+ "no information available (until Q)",
+ "this message is for test purposes only (number Q), please ignore",
+ "no information available (until Q) due to technical problems",
+ "..",
+ "full",
+ "..",
+ "only a few parking spaces available", // 1920
+ "(Q) parking spaces available",
+ "expect car park to be full",
+ "expect no parking spaces available",
+ "multi story car parks full",
+ "no problems to report with park and ride services",
+ "no parking spaces available",
+ "no parking (until Q)",
+ "special parking restrictions lifted",
+ "urgent information will be given (at Q) on normal programme broadcasts",
+ "this TMC-service is not active (until Q)", // 1930
+ "detailed information will be given (at Q) on normal programme broadcasts",
+ "detailed information is provided by another TMC service",
+ "..",
+ "no park and ride information available (until Q)",
+ "..", "..", "..",
+ "park and ride information service resumed",
+ "..",
+ "additional regional information is provided by another TMC service", // 1940
+ "additional local information is provided by another TMC service",
+ "additional public transport information is provided by another TMC service",
+ "national traffic information is provided by another TMC service",
+ "this service provides major road information",
+ "this service provides regional travel information",
+ "this service provides local travel information",
+ "no detailed regional information provided by this service",
+ "no detailed local information provided by this service",
+ "no cross-border information provided by this service",
+ "information restricted to this area", // 1950
+ "no new traffic information available (until Q)",
+ "no public transport information available",
+ "this TMC-service is being suspended (at Q)",
+ "active TMC-service will resume (at Q)",
+ "reference to audio programmes no longer valid",
+ "reference to other TMC services no longer valid",
+ "previous announcement about this or other TMC services no longer valid",
+ "..", "..", "..", // 1960
+ "allow emergency vehicles to pass in the carpool lane",
+ "carpool lane available for all vehicles",
+ "police directing traffic via the carpool lane",
+ "..", "..", "..", "..", "..", "..", "..", // 1970
+ "police directing traffic",
+ "buslane available for all vehicles",
+ "police directing traffic via the buslane",
+ "allow emergency vehicles to pass",
+ "..", "..",
+ "allow emergency vehicles to pass in the heavy vehicle lane",
+ "heavy vehicle lane available for all vehicles",
+ "police directing traffic via the heavy vehicle lane",
+ "..", // 1980
+ "..",
+ "buslane closed",
+ "..", "..", "..", "..", "..", "..", "..", "..", // 1990
+ "..", "..", "..", "..", "..", "..", "..", "..", "..",
+ "closed due to smog alert (until Q)", // 2000
+ "..", "..", "..", "..", "..",
+ "closed for vehicles with less than three occupants {not valid for lorries}",
+ "closed for vehicles with only one occupant {not valid for lorries}",
+ "..", "..", "..", // 2010
+ "..", "..",
+ "service area busy",
+ "..", "..", "..", "..", "..", "..", "..", // 2020
+ "service not operating, substitute service available",
+ "public transport strike",
+ "..", "..", "..", "..", "..",
+ "message cancelled",
+ "message cancelled",
+ "message cancelled", // 2030
+ "..", "..",
+ "message cancelled",
+ "message cancelled",
+ "message cancelled",
+ "..", "..",
+ "message cancelled",
+ "message cancelled",
+ "message cancelled", // 2040
+ "..", "..", "..", "..", "..", "..",
+ "(null message)", // last = 2047
+};
+
+const char *tmc_mglabel[16] = {
+ "Duration",
+ "Control code",
+ "Length",
+ "Speed limit",
+ "Quantifier",
+ "Quantifier",
+ "Info code",
+ "Start time",
+ "Stop time",
+ "Event",
+ "Diversion",
+ "Location",
+ "unknown",
+ "Location",
+ "NOP",
+ "unknown",
+};
+int tmc_mgsize[16] = { 3, 3, 5, 5, 5, 8, 8, 8, 8, 11, 16, 16, 16, 16, 0, 0 };
+
+// TMC, Alert-C Coding
+void tmc_parser(unsigned char *data, int len)
+{
+ static char lastdata[6];
+
+ if (len < 6) {
+ printf("TMC Length only '%d' bytes (<6).\n", len);
+ return;
+ }
+
+ if (memcmp(data, lastdata, 6) == 0) {
+ printf("TMC Repeating.\n");
+ return;
+ }
+ memcpy(lastdata, data, 6);
+
+ // Buffer = data[0], todo or not :D
+
+ // check Encrypted-Service, TMC Pro ?
+ if ((data[1] & 0x1f) == 0x00) { // Type+DP = '00000'
+ printf("TMC Encrypted Service detected, TMC-Pro?\n");
+ return;
+ }
+
+ int type = (data[1] & 0x18)>>3; // Type = User-,TuningInformation & Multi-,Singlegroup Message
+ int dp = data[1] & 0x07; // Duration+Persistance or Continuity Index
+ int da = (data[2] & 0x80)>>7; // DiversionAdvice or GroupIndicator
+ int di = (data[2] & 0x40)>>6; // Direction (-/+) or 2.GroupIndicator
+ int ex = (data[2] & 0x38)>>3; // Extent
+ int ev = (data[2] & 0x07)<<8 | data[3]; // Event
+ int lo = data[4]<<8 | data[5]; // Location
+
+ switch (type) {
+ case 0: // Multigroup-Message
+ printf("TMC Multi-Group Message, ");
+ if (da == 1) {
+ printf("First:\n");
+ printf(" CI: '%d', Direction: %s, Extent: '%d'\n", dp, tmc_direction[di], ex);
+ printf(" Event: '%d' = %s\n", ev, tmc_event[ev]);
+ printf(" Location: '%d' > LT not available yet :-(\n", lo);
+ }
+ else {
+ int gsi = (data[2] & 0x30)>>4; // GroupSequenceIdentifier
+ printf("Subsequent:\n");
+ printf(" CI: '%d', 2.GI: '%d', GSI: '%d', Block_0x: '%02x%02x%02x%02x'\n", dp, di, gsi, data[2]&0xf, data[3], data[4], data[5]);
+ if (di == 0) {
+ printf(" SecondGroupIndicator = 0 -> todo, exit here.\n\n");
+ return;
+ }
+ unsigned int block = (data[2]&0x0f)<<24 | data[3]<<16 | data[4]<<8 | data[5];
+ int lc = 1;
+ int rbits = 28;
+ while (rbits > 0) {
+ int lb = block>>(rbits-4);
+ rbits -= 4;
+ if (lb <= 0)
+ return;
+ block = block & ((unsigned long int)(pow(2,rbits)) - 1);
+ rbits -= tmc_mgsize[lb];
+ int val = block>>(rbits);
+ printf(" #%d: Label '%02d' = %s", lc, lb, tmc_mglabel[lb]);
+ if (val > 0) {
+ switch (lb) {
+ case 0: printf(", Value '%d' min.?\n", val);
+ break;
+ case 2: printf(", Value '%d' km?\n", val);
+ break;
+ case 3: printf(", Value '%d' km/h?\n", val);
+ break;
+ case 9: printf(", Value '%d' = %s\n", val, tmc_event[val]);
+ break;
+ case 11:
+ case 13: printf(", Value '%d' > LT not available yet :-(\n", val);
+ break;
+ case 14:
+ case 15: printf(" ---\n");
+ break;
+ default: printf(", Value '%d'\n", val);
+ }
+ }
+ else {
+ if (block > 0)
+ printf(", rest block_0x '%04x'\n", (int)block);
+ else
+ printf(", ...\n");
+ }
+ block = block & ((unsigned int)(pow(2,rbits)) - 1);
+ lc++;
+ }
+ }
+ break;
+ case 1: // Singlegroup-Message
+ printf("TMC Single-Group Message:\n");
+ printf(" Duration: %s, Diversion: '%d', Direction: %s, Extent: '%d'\n", tmc_duration[dp], da, tmc_direction[di], ex);
+ printf(" Event: '%d' = %s\n", ev, tmc_event[ev]);
+ printf(" Location: '%d' > LT not available yet :-(\n", lo);
+ break;
+ case 2:
+ case 3: // System,Tuning
+ printf("TMC Tuning/System Information:\n");
+ switch (data[1] & 0x0f) {
+ case 9: printf(" LTN: '%d', MGS: '%d', SID: '%d' %04x.\n", data[2]>>2, (data[2] & 0x03)<<2 | data[3]>>6, data[3] & 0x3f, lo);
+ break;
+ default: printf(" todo, exit.\n");
+ }
+ }
+
+}
+
+
+//--------------- End -----------------------------------------------------------------
diff --git a/radiotools.h b/radiotools.h
new file mode 100644
index 0000000..b948202
--- /dev/null
+++ b/radiotools.h
@@ -0,0 +1,29 @@
+/*
+ * radiotools.h - part of radio.c, a plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef __RADIO_TOOLS_H
+#define __RADIO_TOOLS_H
+
+
+bool file_exists(const char *filename);
+
+bool enforce_directory(const char *path);
+
+unsigned short crc16_ccitt(unsigned char *daten, int len, bool skipfirst);
+
+char *rds_entitychar(char *text);
+
+char *xhtml2text(char *text);
+
+char *rtrim(char *text);
+
+char *audiobitrate(const unsigned char *data);
+
+void tmc_parser(unsigned char *data, int len); // Alert-c
+
+
+#endif //__RADIO_TOOLS_H
diff --git a/symbols/RTplus_80x80.png b/symbols/RTplus_80x80.png
new file mode 100644
index 0000000..e6efc60
--- /dev/null
+++ b/symbols/RTplus_80x80.png
Binary files differ
diff --git a/symbols/arec.xpm b/symbols/arec.xpm
new file mode 100644
index 0000000..1c68f7f
--- /dev/null
+++ b/symbols/arec.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static const char * arec_xpm[] = {
+"52 21 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"....................................................",
+"....................................................",
+"..++++++++++++++++++++++++++++++++++++++++++++++++..",
+"..++++++++++++++++++++++++++++++++++++++++++++++++..",
+"..+++......+++++.......+++++++++++++++++++++++++++..",
+"..++..++++..++++..++++..++++++++++++++++++++++++++..",
+"..++..++++..++++..++++..++++++++++++++++++++++++++..",
+"..++..++++..++++..++++..++++++++++++++++++++++++++..",
+"..++..++++..++++..++++..+++++......++++++......+++..",
+"..++..++++..++++..++++..++++..++++..++++..++++..++..",
+"..++........++++.......+++++..++++..++++..++++++++..",
+"..++..++++..++++....++++++++..++++..++++..++++++++..",
+"..++..++++..++++..+..+++++++........++++..++++++++..",
+"..++..++++..++++..++..++++++..++++++++++..++++++++..",
+"..++..++++..++++..+++..+++++..++++++++++..++++++++..",
+"..++..++++..++++..++++..++++..++++..++++..++++..++..",
+"..++..++++..++++..++++..+++++......++++++......+++..",
+"..++++++++++++++++++++++++++++++++++++++++++++++++..",
+"..++++++++++++++++++++++++++++++++++++++++++++++++..",
+"....................................................",
+"...................................................."};
diff --git a/symbols/bok.xpm b/symbols/bok.xpm
new file mode 100644
index 0000000..d3d1298
--- /dev/null
+++ b/symbols/bok.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *bok_xpm[]={
+"23 20 2 1",
+"# c #000000",
+". c #ffffff",
+".#####################.",
+"#######################",
+"##...................##",
+"##...................##",
+"##....###...##....#..##",
+"##...#####..##...##..##",
+"##..##...##.##...##..##",
+"##..##...##.##..##...##",
+"##..##...##.##.##....##",
+"##..##...##.####.....##",
+"##..##...##.####.....##",
+"##..##...##.##.##....##",
+"##..##...##.##..##...##",
+"##..##...##.##...##..##",
+"##...#####..##...##..##",
+"##....###...##....#..##",
+"##...................##",
+"##...................##",
+"#######################",
+".#####################."};
diff --git a/symbols/index.xpm b/symbols/index.xpm
new file mode 100644
index 0000000..86e23c7
--- /dev/null
+++ b/symbols/index.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * index_xpm[] = {
+"52 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++....+++++++++++++++++++..+++++++++++++++++++++++",
+"+++++..++++++++++++++++++++..+++++++++++++++++++++++",
+"+++++..++++++++++++++++++++..+++++++++++++++++++++++",
+"+++++..++++++++++++++++++++..+++++++++++++++++++++++",
+"+++++..++++.......++++.......+++......+++..++++..+++",
+"+++++..++++..++++..++..++++..++..++++..++..++++..+++",
+"+++++..++++..++++..++..++++..++..++++..+++..++..++++",
+"+++++..++++..++++..++..++++..++..++++..++++....+++++",
+"+++++..++++..++++..++..++++..++........+++++..++++++",
+"+++++..++++..++++..++..++++..++..++++++++++....+++++",
+"+++++..++++..++++..++..++++..++..+++++++++..++..++++",
+"+++++..++++..++++..++..++++..++..++++..++..++++..+++",
+"++++....+++..++++..+++.......+++......+++..++++..+++",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++++++++++++++++++++++++++++++++++++++++++++++"};
diff --git a/symbols/marker.xpm b/symbols/marker.xpm
new file mode 100644
index 0000000..f5a26fb
--- /dev/null
+++ b/symbols/marker.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * marker_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"++++++++++++++++++",
+"++++++++++++++++++",
+"++.+++++++++++++++",
+"++...+++++++++++++",
+"++.....+++++++++++",
+"++..++...+++++++++",
+"++..++++...+++++++",
+"++..++++++...+++++",
+"++..++++++++...+++",
+"++..+++++++++...++",
+"++..+++++++++...++",
+"++..++++++++...+++",
+"++..++++++...+++++",
+"++..++++...+++++++",
+"++..++...+++++++++",
+"++.....+++++++++++",
+"++...+++++++++++++",
+"++.+++++++++++++++",
+"++++++++++++++++++",
+"++++++++++++++++++"};
diff --git a/symbols/no0.xpm b/symbols/no0.xpm
new file mode 100644
index 0000000..9beddf0
--- /dev/null
+++ b/symbols/no0.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no0_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++...+++++..",
+"..+++++.....++++..",
+"..++++...+...+++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..++++...+...+++..",
+"..+++++.....++++..",
+"..++++++...+++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no1.xpm b/symbols/no1.xpm
new file mode 100644
index 0000000..96cf5c0
--- /dev/null
+++ b/symbols/no1.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no1_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++...+++++..",
+"..+++++....+++++..",
+"..++++.....+++++..",
+"..++++.+...+++++..",
+"..++++++...+++++..",
+"..++++++...+++++..",
+"..++++++...+++++..",
+"..++++++...+++++..",
+"..++++++...+++++..",
+"..++++.......+++..",
+"..++++.......+++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no2.xpm b/symbols/no2.xpm
new file mode 100644
index 0000000..669f1f8
--- /dev/null
+++ b/symbols/no2.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no2_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..+++++....+++++..",
+"..+++........+++..",
+"..+++...++...+++..",
+"..+++..+++...+++..",
+"..++++++++...+++..",
+"..+++++++...++++..",
+"..++++++...+++++..",
+"..+++++...++++++..",
+"..++++...++..+++..",
+"..+++........+++..",
+"..+++........+++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no3.xpm b/symbols/no3.xpm
new file mode 100644
index 0000000..3cc6bcc
--- /dev/null
+++ b/symbols/no3.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no3_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..+++++....+++++..",
+"..+++........+++..",
+"..+++..+++...+++..",
+"..++++++++...+++..",
+"..++++++....++++..",
+"..++++++....++++..",
+"..++++++++...+++..",
+"..++++++++...+++..",
+"..+++..+++...+++..",
+"..+++........+++..",
+"..++++.....+++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no4.xpm b/symbols/no4.xpm
new file mode 100644
index 0000000..fced9ab
--- /dev/null
+++ b/symbols/no4.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no4_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++....++++..",
+"..+++++.....++++..",
+"..++++......++++..",
+"..++++..+...++++..",
+"..+++..++...++++..",
+"..++...++...++++..",
+"..++.........+++..",
+"..++.........+++..",
+"..+++++++...++++..",
+"..+++++++...++++..",
+"..+++++++...++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no5.xpm b/symbols/no5.xpm
new file mode 100644
index 0000000..e62c7d1
--- /dev/null
+++ b/symbols/no5.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no5_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..+++........+++..",
+"..+++........+++..",
+"..+++...++++++++..",
+"..+++...++++++++..",
+"..+++.......++++..",
+"..+++........+++..",
+"..++++++++...+++..",
+"..++++++++...+++..",
+"..+++..+++...+++..",
+"..+++........+++..",
+"..++++......++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no6.xpm b/symbols/no6.xpm
new file mode 100644
index 0000000..0ebfee7
--- /dev/null
+++ b/symbols/no6.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no6_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++.....+++..",
+"..++++.......+++..",
+"..++++...+++++++..",
+"..+++...++++++++..",
+"..+++...+...++++..",
+"..+++........+++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..++++.......+++..",
+"..+++++.....++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no7.xpm b/symbols/no7.xpm
new file mode 100644
index 0000000..2266355
--- /dev/null
+++ b/symbols/no7.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no7_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..+++.........++..",
+"..+++.........++..",
+"..+++..++++...++..",
+"..++++++++...+++..",
+"..++++++++...+++..",
+"..+++++++...++++..",
+"..+++++++...++++..",
+"..++++++...+++++..",
+"..++++++...+++++..",
+"..+++++...++++++..",
+"..+++++...++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no8.xpm b/symbols/no8.xpm
new file mode 100644
index 0000000..227ba5e
--- /dev/null
+++ b/symbols/no8.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no8_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..+++++.....++++..",
+"..++++.......+++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..++++.......+++..",
+"..++++.......+++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..++++.......+++..",
+"..+++++.....++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/no9.xpm b/symbols/no9.xpm
new file mode 100644
index 0000000..b2a795a
--- /dev/null
+++ b/symbols/no9.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char * no9_xpm[] = {
+"18 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+................+",
+"..................",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..+++++.....++++..",
+"..++++.......+++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..+++...+++...++..",
+"..++++........++..",
+"..+++++...+...++..",
+"..+++++++++...++..",
+"..++++++++...+++..",
+"..++++.......+++..",
+"..++++.....+++++..",
+"..++++++++++++++..",
+"..++++++++++++++..",
+"..................",
+"+................+"};
diff --git a/symbols/page1.xpm b/symbols/page1.xpm
new file mode 100644
index 0000000..0d005a7
--- /dev/null
+++ b/symbols/page1.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *page1_xpm[]={
+"36 20 2 1",
+"# c #000000",
+". c #ffffff",
+"....................................",
+"....................................",
+"....############....................",
+"....############....................",
+"....##........##....................",
+"....##.######.##....................",
+"....##.######.##....................",
+"....##........##....................",
+"....##........##....................",
+"....##.######.##....................",
+"....##.######.##....................",
+"....##........##....................",
+"....##........##....................",
+"....##.######.##....................",
+"....##.######.##....................",
+"....##........##....................",
+"....############....................",
+"....############....................",
+"....................................",
+"...................................."};
diff --git a/symbols/pageE.xpm b/symbols/pageE.xpm
new file mode 100644
index 0000000..a47547f
--- /dev/null
+++ b/symbols/pageE.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *pageE_xpm[]={
+"36 20 2 1",
+"# c #000000",
+". c #ffffff",
+"....................................",
+"....................................",
+"....############....................",
+"....############....................",
+"....##........##....................",
+"....##........##....................",
+"....##.######.##....................",
+"....##.######.##....................",
+"....##.##..##.##....................",
+"....##.##..##.##....................",
+"....##.##..##.##....................",
+"....##.##..##.##....................",
+"....##.######.##....................",
+"....##.######.##....................",
+"....##........##....................",
+"....##........##....................",
+"....############....................",
+"....############....................",
+"....................................",
+"...................................."};
diff --git a/symbols/pages2.xpm b/symbols/pages2.xpm
new file mode 100644
index 0000000..ff63eca
--- /dev/null
+++ b/symbols/pages2.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *pages2_xpm[]={
+"36 20 2 1",
+"# c #000000",
+". c #ffffff",
+"....................................",
+"....................................",
+"....############....................",
+"....##################..............",
+"....##........########..............",
+"....##.######.##....##..............",
+"....##.######.#####.##..............",
+"....##........#####.##..............",
+"....##........##....##..............",
+"....##.######.##....##..............",
+"....##.######.#####.##..............",
+"....##........#####.##..............",
+"....##........##....##..............",
+"....##.######.##....##..............",
+"....##.######.#####.##..............",
+"....##........#####.##..............",
+"....############....##..............",
+"....##################..............",
+"..........############..............",
+"...................................."};
diff --git a/symbols/pages3.xpm b/symbols/pages3.xpm
new file mode 100644
index 0000000..b6342e8
--- /dev/null
+++ b/symbols/pages3.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *pages3_xpm[]={
+"36 20 2 1",
+"# c #000000",
+". c #ffffff",
+"....................................",
+"....############....................",
+"....##################..............",
+"....##........##############........",
+"....##.######.##....########........",
+"....##.######.#####.##....##........",
+"....##........#####.#####.##........",
+"....##........##....#####.##........",
+"....##.######.##....##....##........",
+"....##.######.#####.##....##........",
+"....##........#####.#####.##........",
+"....##........##....#####.##........",
+"....##.######.##....##....##........",
+"....##.######.#####.##....##........",
+"....##........#####.#####.##........",
+"....############....#####.##........",
+"....##################....##........",
+"..........##################........",
+"................############........",
+"...................................."};
diff --git a/symbols/pages4.xpm b/symbols/pages4.xpm
new file mode 100644
index 0000000..fa743a0
--- /dev/null
+++ b/symbols/pages4.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *pages4_xpm[]={
+"36 20 2 1",
+"# c #000000",
+". c #ffffff",
+"....................................",
+"....############....................",
+"....##################..............",
+"....##........##############........",
+"....##.######.##....##############..",
+"....##.######.#####.##....########..",
+"....##........#####.#####.##....##..",
+"....##........##....#####.#####.##..",
+"....##.######.##....##....#####.##..",
+"....##.######.#####.##....##....##..",
+"....##........#####.#####.##....##..",
+"....##........##....#####.#####.##..",
+"....##.######.##....##....#####.##..",
+"....##.######.#####.##....##....##..",
+"....##........#####.#####.##....##..",
+"....############....#####.#####.##..",
+"....##################....#####.##..",
+"..........##################....##..",
+"................##################..",
+"......................############.."};
diff --git a/symbols/radio.xpm b/symbols/radio.xpm
new file mode 100644
index 0000000..250c01e
--- /dev/null
+++ b/symbols/radio.xpm
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *radio_xpm[] = {
+"27 18 2 1",
+". c #FFFFFF",
+"+ c #000000",
+"...........................",
+"............+++++..........",
+"............+++++++++......",
+"............+++++++++++....",
+"............+++...++++++...",
+"............+++.....++++...",
+"............+++.....+++....",
+"............+++.....++.....",
+"............+++............",
+"............+++............",
+"............+++............",
+"......+++++++++............",
+"...+++++++++++++...........",
+"..+++++++++++++++..........",
+"..+++++++++++++++..........",
+"...+++++++++++++...........",
+".....++++++++++............",
+"..........................."};
diff --git a/symbols/rass.xpm b/symbols/rass.xpm
new file mode 100644
index 0000000..bc2ee5f
--- /dev/null
+++ b/symbols/rass.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *rass_xpm[]={
+"47 20 2 1",
+"# c #000000",
+". c #FFFFFF",
+"...............................................",
+"...............................................",
+".....#####......######.........................",
+".....######...#########........................",
+"........###..##########........................",
+"........########....###........................",
+"........#######.....###........................",
+".......######......####........................",
+".......#####......####.............###....###..",
+"......#####......####......###....####...###...",
+"......####.....#####....######....###...####...",
+".....#####.########....######....#####..#####..",
+".....####..######.....####......######.######..",
+"....####...####......####.##....###.#########..",
+"....###.....####.....###..###.......##....###..",
+"...####......#######.##..###.......###....###..",
+"...###........######.##########.######.######..",
+"..###..........####..#####.####.#####.######...",
+"...............................................",
+"..............................................."};
diff --git a/symbols/rds.xpm b/symbols/rds.xpm
new file mode 100644
index 0000000..52d4017
--- /dev/null
+++ b/symbols/rds.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *rds_xpm[] = {
+"80 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"++++++++.....++++++......+++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++.+++++++.+++.+++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++.+++.+++++.+.+++++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++++.++++++++.+++.++++++++.+.+++++......+++++++++++......+++++++++++++++....+++",
+"++.+.+++.....++++.++.....+++.+.++++..........+++++++.........+++++++++++.......+",
+"++..+++.......++.++.......+++++++++..........+++++++..........+++++++++........+",
+"+.+.++.......++.++.........++++.+++....++....+++++++...........++++++++.......++",
+"+.+++........+.++...........+.+++++...+++....++++++.....+++....+++++++...+++++++",
+"++++.....+++.+.++....+++......++.++...+++....++++++.....++++....++++++....++++++",
+"........++++++.++...++++.........++...++.....+....+....+++++....+..+++.......+++",
+"....+...++++++.++....+++....+....++.........++...++....+++++...++..+++........++",
+"+...++.+.+++.++++....+++++.++....++........+++...++....+++++...++..++++.......++",
+"+....+++++++++++....+++++.++....++........+++++++++....++++...++++++++++++....++",
+"+.....++.....++....+....+++.....++...+....+++++++++...++++....+++++++++++++...++",
+"++.....+++++++.....+++++++.....+++...++....++++++++...++.....++++++++..+++....++",
+"++......+++++.......+++++......+++...++....++++++++..........+++++++.........+++",
+"+++...........................+++....+++....++++++..........+++++++..........+++",
+"++++.............+...........++++....+++....+++++++.......++++++++++++....++++++",
+"++++++.........+++.........+++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++.....+++++++....++++++++++++++++++++++++++++++++++++++++++++++++++++++++"};
diff --git a/symbols/rds_20x80.xpm b/symbols/rds_20x80.xpm
new file mode 100644
index 0000000..52d4017
--- /dev/null
+++ b/symbols/rds_20x80.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *rds_xpm[] = {
+"80 20 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"++++++++.....++++++......+++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++.+++++++.+++.+++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++.+++.+++++.+.+++++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++++.++++++++.+++.++++++++.+.+++++......+++++++++++......+++++++++++++++....+++",
+"++.+.+++.....++++.++.....+++.+.++++..........+++++++.........+++++++++++.......+",
+"++..+++.......++.++.......+++++++++..........+++++++..........+++++++++........+",
+"+.+.++.......++.++.........++++.+++....++....+++++++...........++++++++.......++",
+"+.+++........+.++...........+.+++++...+++....++++++.....+++....+++++++...+++++++",
+"++++.....+++.+.++....+++......++.++...+++....++++++.....++++....++++++....++++++",
+"........++++++.++...++++.........++...++.....+....+....+++++....+..+++.......+++",
+"....+...++++++.++....+++....+....++.........++...++....+++++...++..+++........++",
+"+...++.+.+++.++++....+++++.++....++........+++...++....+++++...++..++++.......++",
+"+....+++++++++++....+++++.++....++........+++++++++....++++...++++++++++++....++",
+"+.....++.....++....+....+++.....++...+....+++++++++...++++....+++++++++++++...++",
+"++.....+++++++.....+++++++.....+++...++....++++++++...++.....++++++++..+++....++",
+"++......+++++.......+++++......+++...++....++++++++..........+++++++.........+++",
+"+++...........................+++....+++....++++++..........+++++++..........+++",
+"++++.............+...........++++....+++....+++++++.......++++++++++++....++++++",
+"++++++.........+++.........+++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++.....+++++++....++++++++++++++++++++++++++++++++++++++++++++++++++++++++"};
diff --git a/symbols/rds_24x95.xpm b/symbols/rds_24x95.xpm
new file mode 100644
index 0000000..2ff5054
--- /dev/null
+++ b/symbols/rds_24x95.xpm
@@ -0,0 +1,29 @@
+/* XPM */
+static const char * rds_xpm[] = {
+"95 24 2 1",
+". c #000000",
+"+ c #FFFFFF",
+"+++++++++.......+++++++.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++++++.+++++++++.+++.+++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++++..+++++++++++++.++++++++++++.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++.+++.+++++++.+.+++.+++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"+++.++.++++++++++.+++.++++++++++.++.++++++.......+++++++++++++.......++++++++++++++++++.....+++",
+"++.++.+++.......++++.+++......+++.++.+++++...........+++++++++..........+++++++++++++.........+",
+"++.+.+++.........++.++.........+++.+++++++............++++++++............++++++++++..........+",
+"+.++.++.........++.++...........+++++.++++............++++++++.............+++++++++.........++",
+"+.++++..........++.++............++++.++++....+++.....++++++++....+++......++++++++.....+++++++",
+"+.+.++..........+.++.............++.+++++.....+++.....+++++++.....++++.....++++++++....++++++++",
+"+++.+......+++..+.++.....+++......+.++.++.....+++.....+++++++.....+++++.....+++++++.....+++++++",
+"..........+++++.+.++....+++++.....+....++....+++.....++....++....++++++.....+...+++........++++",
+".....+....+++++.+.++.....++++....+.....++...........+++...+++....++++++....++...+++..........++",
+"+....++.++.+++.+++++.....+++.++.++.....++..........++++...++.....++++++....++...++++.........++",
+"+.....+++++...++.++.....+...+++.+.....+++........++++++...++.....+++++.....++...+++++++......++",
+"+.....+++++++++++++.....++++++.++.....++..........++++++++++.....+++++....++++++++++++++.....++",
+"+......+++.....+++.....+.....+++......++....+.....++++++++++....+++++.....+++++++++++++++....++",
+"++......+++++++++......++++++++......+++....++.....+++++++++....+++......+++++++++..++++.....++",
+"++.......+++++++......+.++++++.......+++....++.....+++++++++............+++++++++...........+++",
+"+++...................+.............+++.....+++.....+++++++............+++++++++...........++++",
+"++++.................+.............++++....++++......++++++..........++++++++++++.........+++++",
+"+++++...............+.............+++++++++++++++++++++++++++++++++++++++++++++++++.....+++++++",
+"+++++++...........+++...........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
+"++++++++++.....+++++++++.....++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"};