From d4eb96f725bed149762665ddee275301c9f069a6 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 3 Sep 2000 11:40:00 +0200 Subject: [PATCH] Added EIT support for current/next display --- CONTRIBUTORS | 3 + HISTORY | 15 ++ INSTALL | 3 + Makefile | 14 +- config.c | 9 +- config.h | 4 +- dvbapi.h | 4 +- eit.c | 530 +++++++++++++++++++++++++++++++++++++++++++++++++++ eit.h | 92 +++++++++ interface.c | 23 ++- 10 files changed, 683 insertions(+), 14 deletions(-) create mode 100644 eit.c create mode 100644 eit.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 74390cf9..07f9d16d 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -16,3 +16,6 @@ Heino Goldenstein Guido Fiala for implementing slow forward/back + +Robert Schneider + for implementing EIT support for displaying the current/next info diff --git a/HISTORY b/HISTORY index 04cc2d59..f5c3cb93 100644 --- a/HISTORY +++ b/HISTORY @@ -123,3 +123,18 @@ Video Disk Recorder Revision History doesn't yet exist). - New version of the 'epg2timers' tool (with a modified channel list). - Bugfix in closing window in DEBUG_OSD mode. + +2000-09-03: Version 0.62 + +- The Makefile now defines DVBDIR to easily point to where the DVB driver + source is located. +- When switching channels the current/next information is now displayed if + available (thanks to Robert Schneider). Since there is now more information + to read when switching channels, the timeout for displaying it has been + increased from 2 to 5 seconds (remember that this info can always be recalled + by pressing the "Ok" button). + For this feature to work it is necessary that the 'Pnr' parameter in the + channel setup ('channels.conf') is set to the proper value. This has been + done for some of the channels in the default 'channels.conf'. Some other + parameters in the default 'channels.conf' have also been updated, so please + make sure your timers still use the correct channels! diff --git a/INSTALL b/INSTALL index 938487c3..1ebffa1b 100644 --- a/INSTALL +++ b/INSTALL @@ -11,6 +11,9 @@ http://linuxtv.org/dvb/siemens_dvb.html for more information about that driver). For example, if the DVB driver was extracted into the directory /home/kls/vdr/DVB, then this package should be extracted into /home/kls/vdr/VDR. +If you have the DVB driver source in a different location +you will have to change the definition of DVBDIR in the +Makefile. This program requires the card driver version 0.05 or higher to work properly. diff --git a/Makefile b/Makefile index f71236b7..9868ddb8 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,12 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.6 2000/07/28 14:37:44 kls Exp $ +# $Id: Makefile 1.7 2000/09/03 09:26:24 kls Exp $ -OBJS = config.o dvbapi.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o +DVBDIR = ../DVB + +INCLUDES = -I$(DVBDIR)/driver +OBJS = config.o dvbapi.o eit.o interface.o menu.o osd.o recording.o remote.o svdrp.o tools.o vdr.o videodir.o ifndef REMOTE REMOTE = KBD @@ -19,13 +22,14 @@ DEFINES += -DDEBUG_OSD endif %.o: %.c - g++ -g -O2 -Wall -c $(DEFINES) $< + g++ -g -O2 -Wall -c $(DEFINES) $(INCLUDES) $< all: vdr -config.o : config.c config.h dvbapi.h interface.h tools.h +config.o : config.c config.h dvbapi.h eit.h interface.h tools.h dvbapi.o : dvbapi.c config.h dvbapi.h interface.h tools.h videodir.h -interface.o: interface.c config.h dvbapi.h interface.h remote.h tools.h +eit.o : eit.c eit.h +interface.o: interface.c config.h dvbapi.h eit.h interface.h remote.h tools.h menu.o : menu.c config.h dvbapi.h interface.h menu.h osd.h recording.h tools.h osd.o : osd.c config.h dvbapi.h interface.h osd.h tools.h vdr.o : vdr.c config.h dvbapi.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h diff --git a/config.c b/config.c index c144d6c0..af5be871 100644 --- a/config.c +++ b/config.c @@ -4,15 +4,18 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.17 2000/08/06 12:27:38 kls Exp $ + * $Id: config.c 1.18 2000/09/03 09:20:22 kls Exp $ */ #include "config.h" #include #include #include "dvbapi.h" +#include "eit.h" #include "interface.h" +extern cEIT EIT; + // -- cKeys ------------------------------------------------------------------ tKey keyTable[] = { // "Up" and "Down" must be the first two keys! @@ -231,8 +234,10 @@ bool cChannel::Switch(cDvbApi *DvbApi) isyslog(LOG_INFO, "switching to channel %d", Index() + 1); CurrentChannel = Index(); for (int i = 3; i--;) { - if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) + if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) { + EIT.SetProgramNumber(pnr); return true; + } esyslog(LOG_ERR, "retrying"); } return false; diff --git a/config.h b/config.h index 1b21d341..15e90501 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.14 2000/08/06 12:22:52 kls Exp $ + * $Id: config.h 1.15 2000/09/03 09:37:30 kls Exp $ */ #ifndef __CONFIG_H @@ -17,7 +17,7 @@ #include "dvbapi.h" #include "tools.h" -#define VDRVERSION "0.61" +#define VDRVERSION "0.62" #define MaxBuffer 10000 diff --git a/dvbapi.h b/dvbapi.h index 25452cfa..9f954302 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.12 2000/07/30 15:01:01 kls Exp $ + * $Id: dvbapi.h 1.13 2000/09/03 09:25:53 kls Exp $ */ #ifndef __DVBAPI_H @@ -19,7 +19,7 @@ typedef unsigned char __u8; #include #endif #include -#include "../DVB/driver/dvb.h" +#include #define MenuLines 15 #define MenuColumns 40 diff --git a/eit.c b/eit.c new file mode 100644 index 00000000..c4c12003 --- /dev/null +++ b/eit.c @@ -0,0 +1,530 @@ +/*************************************************************************** + eit.c - description + ------------------- + begin : Fri Aug 25 2000 + copyright : (C) 2000 by Robert Schneider + email : Robert.Schneider@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + * $Id: eit.c 1.1 2000/09/03 10:22:25 kls Exp $ + ***************************************************************************/ + +#include "eit.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "tools.h" + +typedef struct { + u_char table_id : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; +#else + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; +#endif + + u_char section_length_lo : 8; + + u_char service_id_hi : 8; + u_char service_id_lo : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char : 2; + u_char version_number : 5; + u_char current_next_indicator : 1; +#else + u_char current_next_indicator : 1; + u_char version_number : 5; + u_char : 2; +#endif + + u_char section_number : 8; + u_char last_section_number : 8; + u_char transport_stream_id_hi : 8; + u_char transport_stream_id_lo : 8; + u_char original_network_id_hi : 8; + u_char original_network_id_lo : 8; + u_char segment_last_section_number : 8; + u_char segment_last_table_id : 8; +} eit_t; + +#define EIT_SIZE 14 + +struct eit_loop_struct1 { + u_char event_id_hi : 8; + u_char event_id_lo : 8; + + u_char date_hi : 8; + u_char date_lo : 8; + u_char time_hour : 4; + u_char time_hour_ten : 4; + u_char time_minute : 4; + u_char time_minute_ten : 4; + u_char time_second : 4; + u_char time_second_ten : 4; + + u_char dur_hour_ten : 4; + u_char dur_hour : 4; + u_char dur_minute_ten : 4; + u_char dur_minute : 4; + u_char dur_second_ten : 4; + u_char dur_second : 4; + +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status : 3; + u_char free_ca_mode : 1; + u_char descriptors_loop_length_hi : 4; +#else + u_char descriptors_loop_length_hi : 4; + u_char free_ca_mode : 1; + u_char running_status : 3; +#endif + + u_char descriptors_loop_length_lo : 8; +}; + +#define EIT_SHORT_EVENT_DESCRIPTOR 0x4d +#define EIT_SHORT_EVENT_DESCRIPTOR_SIZE 6 + +struct eit_short_event_descriptor_struct { + u_char descriptor_tag : 8; + u_char descriptor_length : 8; + + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; + + u_char event_name_length : 8; +}; + +#define EIT_EXTENDED_EVENT_DESCRIPOR 0x4e + +#define EIT_DESCRIPTOR_SIZE + +typedef struct eit_event_struct { + u_char event_id_hi : 8; + u_char event_id_lo : 8; + + u_char start_time_1 : 8; + u_char start_time_2 : 8; + u_char start_time_3 : 8; + u_char start_time_4 : 8; + u_char start_time_5 : 8; + + u_char duration_1 : 8; + u_char duration_2 : 8; + u_char duration_3 : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status : 3; + u_char free_CA_mode : 1; + u_char descriptors_loop_length_hi : 4; +#else + u_char descriptors_loop_length_hi : 4; + u_char free_CA_mode : 1; + u_char running_status : 3; +#endif + + u_char descriptors_loop_length_lo : 8; + +} eit_event_t; +#define EIT_LOOP_SIZE 12 + + +typedef struct tot_t { + u_char table_id : 8; + +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator : 1; + u_char : 3; + u_char section_length_hi : 4; +#else + u_char section_length_hi : 4; + u_char : 3; + u_char section_syntax_indicator : 1; +#endif + + u_char date_hi : 8; + u_char date_lo : 8; + u_char time_hour : 4; + u_char time_hour_ten : 4; + u_char time_minute : 4; + u_char time_minute_ten : 4; + u_char time_second : 4; + u_char time_second_ten : 4; + +#if BYTE_ORDER == BIG_ENDIAN + u_char : 4; + u_char descriptor_loop_length_hi : 4; +#else + u_char descriptor_loop_length_hi : 4; + u_char : 4; +#endif + + u_char descriptor_loop_length_lo : 8; +} tot_t; + +typedef struct local_time_offset { + + u_char descriptor_tag : 8; + u_char descriptor_length : 8; + + u_char language_code_1 : 8; + u_char language_code_2 : 8; + u_char language_code_3 : 8; + + u_char : 8; + + u_char offset_hour : 4; + u_char offset_hour_ten : 4; + u_char offset_minute : 4; + u_char offset_minute_ten : 4; + + u_char change_date_hi : 8; + u_char change_date_lo : 8; + u_char change_time_hour : 4; + u_char change_time_hour_ten : 4; + u_char change_time_minute : 4; + u_char change_time_minute_ten : 4; + u_char change_time_second : 4; + u_char change_time_second_ten : 4; + + u_char next_offset_hour : 4; + u_char next_offset_hour_ten : 4; + u_char next_offset_minute : 4; + u_char next_offset_minute_ten : 4; +} local_time_offset; + +cEIT::cEIT() +{ + cszBitFilter = "/dev/vbi"; + if((fsvbi = open(cszBitFilter, O_RDWR))<0) + { + fsvbi = 0; + esyslog(LOG_ERR, "Failed to open DVB bitfilter device: %s", cszBitFilter); + return; + } +} + +cEIT::~cEIT() +{ + if (fsvbi != 0) + close(fsvbi); + fsvbi = 0; +} + +/** Set the bitfilter in vbi device to return +correct tables */ +int cEIT::SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode) +{ + struct bitfilter filt = { + pid, + { section, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + mode,0, + FILTER_MEM, + {}, + }; + + if (ioctl(fsvbi, VIDIOCSBITFILTER, &filt) < 0) + return 0xffff; + return 0; +} +/** */ +int cEIT::GetSection(unsigned char *buf, ushort PID, unsigned char sec) +{ + int seclen=0; + unsigned short handle, pid; + unsigned char section, sectionnum=0xff, maxsec=0; + struct pollfd pfd; + + if ((handle = SetBitFilter(PID, (sec<<8)|0x00ff, SECTION_CONTINUOS))==0xffff) + return -1; + + seclen=0; + pfd.fd=fsvbi; + pfd.events=POLLIN; + if (poll(&pfd, 1, 20000)==0) + { + //cerr << "Timeout\n"; + return -1; + } + + read(fsvbi, buf, 8); + seclen=(buf[6]<<8)|buf[7]; + pid=(buf[4]<<8)|buf[5]; + + read(fsvbi, buf, seclen); + section=buf[0]; + sectionnum=buf[6]; + maxsec=buf[7]; + + //cerr << "secnum: " << HEX(2) << (int)sectionnum + // << ", secmax: " << HEX(2) << (int) msecnum << "\n"; + + CloseFilter(handle); + + return seclen; +} + +/** */ +int cEIT::CloseFilter(unsigned short handle) +{ + if (ioctl(fsvbi, VIDIOCSSHUTDOWNFILTER, &handle)<0) + return -1; + return 0; +} + +/** */ +char * cEIT::mjd2string(unsigned short mjd) +{ + int y, m, d, k; + static char buf[20]; + + y = (int) ((mjd - 15078.2) / 365.25); + m = (int) ((mjd - 14956.1 - (int)(y * 365.25)) / 30.6001); + d = (int) (mjd - 14956 - (int)(y * 365.25) - (int)(m * 30.6001)); + k = (m == 14 || m == 15) ? 1 : 0; + y = y + k; + m = m - 1 - k * 12; + sprintf(buf, "%d.%d.%4d", d, m, y + 1900); + + return(buf); +} + +/** */ +int cEIT::GetEIT() +{ + unsigned char buf[1024]; + eit_t *eit; + struct eit_loop_struct1 *eitloop; + struct eit_short_event_descriptor_struct *eitevt; + int seclen; + unsigned short handle, pid; + struct pollfd pfd; + eit_event * pevt = (eit_event *)0; + time_t tstart; + + if ((handle = SetBitFilter(0x12, (0x4e << 8) | 0x00ff, SECTION_CONTINUOS))==0xffff) + { + return -1; + } +/* + pid_t process = fork(); + if (process < 0) + { + cerr << "GetEIT -1" << endl; + return -1; + } + + if (process != 0) + { + cerr << "GetEIT 0" << endl; + return 0; + } +*/ + int nReceivedEITs = 0; + tstart = time(NULL); + while ((!evtRunning.bIsValid || !evtNext.bIsValid) && nReceivedEITs < 20 && difftime(time(NULL), tstart) < 4) + { + pfd.fd=fsvbi; + pfd.events=POLLIN; + if (poll(&pfd, 1, 5000)==0) + { + //cerr << "Timeout\n"; + CloseFilter(handle); + return -1; + } + + read(fsvbi, buf, 8); + seclen=(buf[6]<<8)|buf[7]; + pid=(buf[4]<<8)|buf[5]; + + read(fsvbi, buf, seclen); + + if (seclen < (int)(sizeof(eit_t) + + sizeof(struct eit_loop_struct1) + + sizeof(struct eit_short_event_descriptor_struct))) + continue; + + eit = (eit_t *)buf; + eitloop = (struct eit_loop_struct1 *)&eit[1]; + eitevt = (struct eit_short_event_descriptor_struct *)&eitloop[1]; + + if (eitevt->descriptor_tag != EIT_SHORT_EVENT_DESCRIPTOR) + { + // printf("Tag = '%c'\n", eitevt->descriptor_tag); + continue; + } + + if (((eit->service_id_hi << 8) | eit->service_id_lo) != uProgramNumber) + { + // printf("Wrong program %04x need %04x\n", (eit->service_id_hi << 8) | eit->service_id_lo, uProgramNumber); + continue; + } + + nReceivedEITs++; + + pevt = (eit_event *)0; + if (eitloop->running_status == 4 | eitloop->running_status == 3) + pevt = (eit_event *)&evtRunning; + else if (eitloop->running_status == 1 || eitloop->running_status == 2 || eitloop->running_status == 0) + pevt = (eit_event *)&evtNext; + + if (pevt) + { + unsigned char *p = (unsigned char *)&eitevt[1]; + strdvbcpy((unsigned char *)pevt->szTitle, p, eitevt->event_name_length); + pevt->szSubTitle[0] = 0; + strdvbcpy((unsigned char *)pevt->szSubTitle, &p[eitevt->event_name_length+1], (int)p[eitevt->event_name_length]); + strcpy(pevt->szDate, mjd2string((eitloop->date_hi << 8) + eitloop->date_lo)); + int hr = eitloop->time_hour + (eitloop->time_hour_ten * 10); + hr += 2; + if (hr >=24) + { + hr -= 24; + // need to switch date one day ahead here + } + sprintf(pevt->szTime, "%d:%c%c", hr, + eitloop->time_minute_ten + '0', + eitloop->time_minute + '0'); + pevt->bIsValid = true; + } + } + + CloseFilter(handle); + + return 1; +} + +/** */ +int cEIT::SetProgramNumber(unsigned short pnr) +{ + if (pnr == 0) + { + evtRunning.bIsValid = false; + evtNext.bIsValid = false; + return -1; + } + + if (pnr != uProgramNumber) + { + evtRunning.bIsValid = false; + evtNext.bIsValid = false; + uProgramNumber = pnr; + return GetEIT(); + } + return (IsValid() ? 1 : -1); +} + +/** retrieves the string for the running title */ +char * cEIT::GetRunningTitle() +{ + if (evtRunning.bIsValid) + return evtRunning.szTitle; + else + return "---"; +} +/** Retrieves the string for the running subtitle */ +char * cEIT::GetRunningSubtitle() +{ + if (evtRunning.bIsValid) + return evtRunning.szSubTitle; + else + return "---"; +} +/** Retrieves the string representing the +date of the current event + */ +char * cEIT::GetRunningDate() +{ + if (evtRunning.bIsValid) + return evtRunning.szDate; + else + return "---"; +} +/** Retrieves the string representing the +time of the current event */ +char * cEIT::GetRunningTime() +{ + if (evtRunning.bIsValid) + return evtRunning.szTime; + else + return "---"; +} +/** retrieves the string for the running title */ +char * cEIT::GetNextTitle() +{ + if (evtNext.bIsValid) + return evtNext.szTitle; + else + return "---"; +} +/** Retrieves the string for the running subtitle */ +char * cEIT::GetNextSubtitle() +{ + if (evtNext.bIsValid) + return evtNext.szSubTitle; + else + return "---"; +} +/** Retrieves the string representing the +date of the current event + */ +char * cEIT::GetNextDate() +{ + if (evtNext.bIsValid) + return evtNext.szDate; + else + return "---"; +} +/** Retrieves the string representing the +time of the current event */ +char * cEIT::GetNextTime() +{ + if (evtNext.bIsValid) + return evtNext.szTime; + else + return "---"; +} + +/** */ +bool cEIT::IsValid() +{ + return (evtRunning.bIsValid && evtNext.bIsValid); +} + +/** */ +int cEIT::strdvbcpy(unsigned char *dst, unsigned char *src, int max) +{ + int a; + for (a = 0; a < max; a++) + { + if (*src == 0) + break; + + if ((*src >= ' ' && *src <= '~') || (*src >= 0xa0 && *src <= 0xff)) + *dst++ = *src++; + else + src++; + } + *dst = 0; + return a; +} diff --git a/eit.h b/eit.h new file mode 100644 index 00000000..28329f42 --- /dev/null +++ b/eit.h @@ -0,0 +1,92 @@ +/*************************************************************************** + eit.h - description + ------------------- + begin : Fri Aug 25 2000 + copyright : (C) 2000 by Robert Schneider + email : Robert.Schneider@web.de + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + * $Id: eit.h 1.1 2000/09/03 10:23:24 kls Exp $ + ***************************************************************************/ + +#ifndef __EIT_H +#define __EIT_H + +#include + +typedef struct eit_event { + + bool bIsValid; + char szTitle[512]; + char szSubTitle[512]; + char szDate[12]; + char szTime[12]; + +}eit_event; + +/** + *@author Robert Schneider + */ + +class cEIT { +public: + cEIT(); + ~cEIT(); + /** */ + int GetEIT(); + /** */ + int SetProgramNumber(unsigned short pnr); + /** Retrieves the string representing the time of the current event */ + char * GetRunningTime(); + /** Retrieves the string representing the date of the current event */ + char * GetRunningDate(); + /** Retrieves the string for the running subtitle */ + char * GetRunningSubtitle(); + /** retrieves the string for the running title */ + char * GetRunningTitle(); + /** Retrieves the string representing the time of the next event */ + char * GetNextTime(); + /** Retrieves the string representing the date of the next event */ + char * GetNextDate(); + /** Retrieves the string for the next subtitle */ + char * GetNextSubtitle(); + /** retrieves the string for the next title */ + char * GetNextTitle(); + /** */ + bool IsValid(); + +protected: // Protected attributes + /** Device name of VBI device */ + const char * cszBitFilter; +protected: // Protected attributes + /** handle to VBI device (usually /dev/vbi) */ + int fsvbi; + /** Describes the event next on */ + eit_event evtNext; + /** Describes the running event */ + eit_event evtRunning; +protected: // Protected methods + /** Set the bitfilter in vbi device to return +correct tables */ + int SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode); + /** */ + int GetSection(unsigned char *buf, ushort PID, unsigned char sec); + /** */ + int CloseFilter(unsigned short handle); + /** */ + char * mjd2string(unsigned short mjd); + /** */ + int strdvbcpy(unsigned char *dst, unsigned char *src, int max); +public: // Public attributes + /** */ + unsigned short uProgramNumber; +}; + +#endif diff --git a/interface.c b/interface.c index 244488aa..2ae49c33 100644 --- a/interface.c +++ b/interface.c @@ -4,13 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.10 2000/07/15 12:39:20 kls Exp $ + * $Id: interface.c 1.11 2000/09/03 10:17:21 kls Exp $ */ #include "interface.h" #include +#include "eit.h" #include "remote.h" +cEIT EIT; + #if defined(REMOTE_RCU) cRcIoRCU RcIo("/dev/ttyS1"); #elif defined(REMOTE_LIRC) @@ -316,7 +319,7 @@ void cInterface::DisplayChannel(int Number, const char *Name) { RcIo.Number(Number); if (Name && !Recording()) { - Open(MenuColumns, 1); + Open(MenuColumns, EIT.IsValid() ? 5 : 1); char buffer[MenuColumns + 1]; snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : ""); Write(0, 0, buffer); @@ -324,7 +327,21 @@ void cInterface::DisplayChannel(int Number, const char *Name) struct tm *now = localtime(&t); snprintf(buffer, sizeof(buffer), "%02d:%02d", now->tm_hour, now->tm_min); Write(-5, 0, buffer); - if (Wait(2, true) == kOk) + if (EIT.IsValid()) { + const int t = 7; + int w = MenuColumns - t; + Write(0, 1, EIT.GetRunningTime(), clrYellow, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningTitle()); + Write(t, 1, buffer, clrCyan, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetRunningSubtitle()); + Write(t, 2, buffer, clrCyan, clrBackground); + Write(0, 3, EIT.GetNextTime(), clrYellow, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextTitle()); + Write(t, 3, buffer, clrCyan, clrBackground); + snprintf(buffer, sizeof(buffer), "%.*s", w, EIT.GetNextSubtitle()); + Write(t, 4, buffer, clrCyan, clrBackground); + } + if (Wait(5, true) == kOk) GetKey(); Close(); }