Version 1.3.6

- Completed the Finnish OSD texts (thanks to Rolf Ahrenberg).
- Fixed some descriptor handling in 'libsi' (thanks to Stéphane Esté-Gracias).
- Fixed handling the current menu item (thanks to Marc Hoppe).
- Fixed assigning events to timers (they no longer get "stuck").
- Added log entries whenever the running status of an event changes (currently
  only logging the first 30 channels).
- Fixed handling timers in VPS margin if the EPG scan is turned on (the EPG scan
  switched the device away from the channel, so it wouldn't see the change of
  the running status).
- Fixed handling "itemized" texts in EPG data (thanks to Stéphane Esté-Gracias
  for pointing out this problem, and Marcel Wiesweg for improving 'libsi').
- Fixed handling VPS times at year boundaries.
- Avoiding too many consecutive "ring buffer overflow" messages (which only
  slowed down performance even more).
- Taking the Sid into account when detecting version changes in processing the
  PMT (thanks to Stéphane Esté-Gracias for pointing out this problem).
- Completed the Russian OSD texts (thanks to Vyacheslav Dikonov).
- Any newline characters in the 'description' of EPG events are now preserved
  to allow texts to be displayed the way the tv stations have formatted them.
  This was also necessary to better display itemized texts.
- Fixed detecting the running status in case an empty EPG event is broadcast (thanks
  to Michael Pennewiß for pointing this out).
- Improved performance when paging through very long menu lists.
- Removed cSchedule::GetEventNumber() and cSchedule::NumEvents(). There is now
  cSchedule::Events() that returns the list of events directly.
- Avoiding occasional bad responsiveness to user interaction caused by assigning
  events to timers.
- Now explicitly turning on the LNB power at startup, because newer drivers don't
  do this any more (thanks to Oliver Endriss for pointing this out).
This commit is contained in:
Klaus Schmidinger 2004-03-14 18:00:00 +01:00
parent 5a4eb3f104
commit 9384e56566
35 changed files with 557 additions and 229 deletions

View File

@ -514,6 +514,8 @@ Oliver Endriss <o.endriss@gmx.de>
for suggesting to add 'repeat' function keys '7' and '9' for suggesting to add 'repeat' function keys '7' and '9'
for fixing handling rc key learning in case cRemote::Initialize() returns 'false' for fixing handling rc key learning in case cRemote::Initialize() returns 'false'
for suggesting to change the default "Lifetime" to 99 for suggesting to change the default "Lifetime" to 99
for pointing out that the LNB power needs to be explicitly turned on at startup,
because newer drivers don't do this any more
Reinhard Walter Buchner <rw.buchner@freenet.de> Reinhard Walter Buchner <rw.buchner@freenet.de>
for adding some satellites to 'sources.conf' for adding some satellites to 'sources.conf'
@ -943,3 +945,13 @@ Thomas Bergwinkl <Thomas.Bergwinkl@t-online.de>
Stéphane Esté-Gracias <sestegra@free.fr> Stéphane Esté-Gracias <sestegra@free.fr>
for fixing a typo in libsi/si.h for fixing a typo in libsi/si.h
for fixing some descriptor handling in 'libsi'
for pointing out a problem with "itemized" texts in EPG data
for pointing out a problem with taking the Sid into account when detecting version
changes in processing the PMT
Marc Hoppe <MarcHoppe@gmx.de>
for fixing handling the current menu item
Michael Pennewiß <M.Pennewiss@ARD-Digital.de>
for pointing out that an empty EPG event means there is currently no running event

32
HISTORY
View File

@ -2713,3 +2713,35 @@ Video Disk Recorder Revision History
whether an event has a VPS time that's different than its start time, and whether an event has a VPS time that's different than its start time, and
whether an event is currently running (see MANUAL under "The "Schedule" Menu" whether an event is currently running (see MANUAL under "The "Schedule" Menu"
for details). for details).
2004-03-14: Version 1.3.6
- Completed the Finnish OSD texts (thanks to Rolf Ahrenberg).
- Fixed some descriptor handling in 'libsi' (thanks to Stéphane Esté-Gracias).
- Fixed handling the current menu item (thanks to Marc Hoppe).
- Fixed assigning events to timers (they no longer get "stuck").
- Added log entries whenever the running status of an event changes (currently
only logging the first 30 channels).
- Fixed handling timers in VPS margin if the EPG scan is turned on (the EPG scan
switched the device away from the channel, so it wouldn't see the change of
the running status).
- Fixed handling "itemized" texts in EPG data (thanks to Stéphane Esté-Gracias
for pointing out this problem, and Marcel Wiesweg for improving 'libsi').
- Fixed handling VPS times at year boundaries.
- Avoiding too many consecutive "ring buffer overflow" messages (which only
slowed down performance even more).
- Taking the Sid into account when detecting version changes in processing the
PMT (thanks to Stéphane Esté-Gracias for pointing out this problem).
- Completed the Russian OSD texts (thanks to Vyacheslav Dikonov).
- Any newline characters in the 'description' of EPG events are now preserved
to allow texts to be displayed the way the tv stations have formatted them.
This was also necessary to better display itemized texts.
- Fixed detecting the running status in case an empty EPG event is broadcast (thanks
to Michael Pennewiß for pointing this out).
- Improved performance when paging through very long menu lists.
- Removed cSchedule::GetEventNumber() and cSchedule::NumEvents(). There is now
cSchedule::Events() that returns the list of events directly.
- Avoiding occasional bad responsiveness to user interaction caused by assigning
events to timers.
- Now explicitly turning on the LNB power at startup, because newer drivers don't
do this any more (thanks to Oliver Endriss for pointing this out).

View File

@ -128,3 +128,9 @@ stations:
information to control recording would not see the end of that programme. information to control recording would not see the end of that programme.
... more following as it comes up... ... more following as it comes up...
Contact:
--------
ARD Digital: http://www.ard-digital.de/home/index.php?id=16&languageid=1
ZDF vision: http://www.zdf.de/ZDFde/inhalt/1/0,1872,1021601,00.html (select "zdfvision")

View File

@ -24,9 +24,10 @@ VOX:12187:hC34:S19.2E:27500:167:136=deu:71:0:12060:1:1089:0
KABEL1:12480:vC34:S19.2E:27500:511:512:33:0:899:133:33:0 KABEL1:12480:vC34:S19.2E:27500:511:512:33:0:899:133:33:0
NEUN LIVE,NEUN LIVE Television:12480:vC34:S19.2E:27500:767:768:35:0:897:133:33:0 NEUN LIVE,NEUN LIVE Television:12480:vC34:S19.2E:27500:767:768:35:0:897:133:33:0
DSF:12480:vC34:S19.2E:27500:1023:1024=deu:0:0:900:133:33:0 DSF:12480:vC34:S19.2E:27500:1023:1024=deu:0:0:900:133:33:0
HSEurope,Home Shopping Europe:12480:vC34:S19.2E:27500:1279:1280:37:0:40:133:33:0 HSE24:12480:vC34:S19.2E:27500:1279:1280:37:0:40:133:33:0
Bloomberg TV Germany:12551:vC56:S19.2E:22000:162:99=deu:0:0:12160:1:1108:0 Bloomberg TV Germany:12551:vC56:S19.2E:22000:162:99=deu:0:0:12160:1:1108:0
EURONEWS:11817:vC34:S19.2E:27500:163:92=fra,93=eng,94=ita,95=esl,91=rus,98=por,99=deu:0:0:8004:1:1070:0 EURONEWS:11817:vC34:S19.2E:27500:163:92=fra,93=eng,94=ita,95=esl,91=rus,98=por,99=deu:0:0:8004:1:1070:0
rbb Brandenburg:12109:hC34:S19.2E:27500:501:502=deu:504:0:28205:1:1073:0
Sky News Intl:11597:vC56:S19.2E:22000:305+131:306=eng:0:0:28707:1:1026:0 Sky News Intl:11597:vC56:S19.2E:22000:305+131:306=eng:0:0:28707:1:1026:0
Veronica/FoxKids:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,602,100:5020:53:1109:0 Veronica/FoxKids:12574:hC56:S19.2E:22000:518+8190:92=dut:38:622,602,100:5020:53:1109:0
BVN:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0 BVN:12574:hC56:S19.2E:22000:515+8190:96=dut:36:0:5025:53:1109:0
@ -38,20 +39,19 @@ Eurosport:11953:hC34:S19.2E:27500:410:420=deu:430:0:28009:1:1079:0
EinsExtra:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0 EinsExtra:12109:hC34:S19.2E:27500:101:102=deu:0:0:28201:1:1073:0
EinsFestival:12109:hC34:S19.2E:27500:201:202=deu:0:0:28202:1:1073:0 EinsFestival:12109:hC34:S19.2E:27500:201:202=deu:0:0:28202:1:1073:0
EinsMuXx:12109:hC34:S19.2E:27500:301:302=deu:0:0:28203:1:1073:0 EinsMuXx:12109:hC34:S19.2E:27500:301:302=deu:0:0:28203:1:1073:0
ZDFtheaterkanal:11953:hC34:S19.2E:27500:1110:1120:130:0:28016:1:1079:0 ZDFtheaterkanal:11953:hC34:S19.2E:27500:1110:1120=deu:130:0:28016:1:1079:0
ZDFdokukanal:11953:hC34:S19.2E:27500:660:670=deu:130:0:28014:1:1079:0 ZDFdokukanal:11953:hC34:S19.2E:27500:660:670=deu:130:0:28014:1:1079:0
MDR FERNSEHEN:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0 MDR FERNSEHEN:12109:hC34:S19.2E:27500:401:402=deu:404:0:28204:1:1073:0
RBB Brandenburg:12109:hC34:S19.2E:27500:501:502=deu:504:0:28205:1:1073:0 rbb Berlin:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0
RBB Berlin:12109:hC34:S19.2E:27500:601:602=deu:604:0:28206:1:1073:0
:Premiere World :Premiere World
START,PREMIERE START:11797:hC34:S19.2E:27500:255:256=deu:32:1702,1722,1801:8:133:2:0 START,PREMIERE START:11797:hC34:S19.2E:27500:255:256=deu:32:1722,1801,1702:8:133:2:0
PREM 1,PREMIERE 1:11797:hC34:S19.2E:27500:511:512=deu,513=deu;515=deu:0:1702,1722,1801:10:133:2:0 PREM 1,PREMIERE 1:11797:hC34:S19.2E:27500:511:512=deu;515=deu:0:1702,1801,1722:10:133:2:0
PREM 2,PREMIERE 2:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:0:1702,1722,1801:11:133:2:0 PREM 2,PREMIERE 2:11797:hC34:S19.2E:27500:1791:1792=deu,1793=deu;1795=deu:0:1702,1722,1801:11:133:2:0
PREM 3,PREMIERE 3:11797:hC34:S19.2E:27500:2303:2304=deu:0:1702,1722,1801:43:133:2:0 PREM 3,PREMIERE 3:11797:hC34:S19.2E:27500:2303:2304=deu:0:1722,1702,1801:43:133:2:0
PREM 4,PREMIERE 4:11797:hC34:S19.2E:27500:767:768=deu:0:1702,1722,1801:9:133:2:0 PREM 4,PREMIERE 4:11797:hC34:S19.2E:27500:767:768=deu:0:1801,1722,1702:9:133:2:0
PREM 5,PREMIERE 5:11797:hC34:S19.2E:27500:1279:1280=deu,1281=deu:0:1702,1722,1801:29:133:2:0 PREM 5,PREMIERE 5:11797:hC34:S19.2E:27500:1279:1280=deu:0:1801,1702,1722:29:133:2:0
PREM 6,PREMIERE 6:11797:hC34:S19.2E:27500:1535:1536=deu:0:1702,1722,1801:41:133:2:0 PREM 6,PREMIERE 6:11797:hC34:S19.2E:27500:1535:1536=deu:0:1722,1801,1702:41:133:2:0
PREM 7,PREMIERE 7:11797:hC34:S19.2E:27500:1023:1024=deu:0:1702,1722,1801:20:133:2:0 PREM 7,PREMIERE 7:11797:hC34:S19.2E:27500:1023:1024=deu:0:1722,1702,1801:20:133:2:0
DISNEY,DISNEY CHANNEL:11758:hC34:S19.2E:27500:2559:2560=deu:0:1702,1722,1801:34:133:17:0 DISNEY,DISNEY CHANNEL:11758:hC34:S19.2E:27500:2559:2560=deu:0:1702,1722,1801:34:133:17:0
:Premiere Direkt :Premiere Direkt
DIREKT,PREMIERE DIREKT:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2819=deu:0:0:18:133:4:0 DIREKT,PREMIERE DIREKT:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2819=deu:0:0:18:133:4:0
@ -59,7 +59,7 @@ DIREKT,PREMIERE DIREKT:12031:hC34:S19.2E:27500:2815:2816=deu,2817=deu;2819=deu:0
B-UHSE,BEATE-UHSE.TV:12070:hC34:S19.2E:27500:1023:1024=deu:0:1702,1722,1801:21:133:1:0 B-UHSE,BEATE-UHSE.TV:12070:hC34:S19.2E:27500:1023:1024=deu:0:1702,1722,1801:21:133:1:0
EROTIK,PREMIERE EROTIK:12031:hC34:S19.2E:27500:1279:0:0:1702,1722,1801:513:133:4:0 EROTIK,PREMIERE EROTIK:12031:hC34:S19.2E:27500:1279:0:0:1702,1722,1801:513:133:4:0
:Sportsworld :Sportsworld
Konferenz:11719:hC34:S19.2E:27500:255:256=deu:0:1702,1722,1801:17:133:3:0 SPORT 1,PREMIERE SPORT 1:11719:hC34:S19.2E:27500:255:256=deu,257=deu:0:1702,1722,1801:17:133:3:0
SPORT 2,PREMIERE SPORT 2:12031:hC34:S19.2E:27500:3839:3840=deu,3841=deu:0:1702,1722,1801:27:133:4:0 SPORT 2,PREMIERE SPORT 2:12031:hC34:S19.2E:27500:3839:3840=deu,3841=deu:0:1702,1722,1801:27:133:4:0
:Beta Digital :Beta Digital
N24:12480:vC34:S19.2E:27500:2047:2048:36:0:47:133:33:0 N24:12480:vC34:S19.2E:27500:2047:2048:36:0:47:133:33:0
@ -114,6 +114,6 @@ Animal Plnt+:12070:hC23:S28.2E:27500:2315+2307:2316=eng:0:960,961:50002:2:2019:0
S1T:12285:vC23:S28.2E:27500:2311+2304:2312=eng,2313=NAR:2307:960,961:4409:2:2030:0 S1T:12285:vC23:S28.2E:27500:2311+2304:2312=eng,2313=NAR:2307:960,961:4409:2:2030:0
CNN:12051:vC23:S28.2E:27500:2309:2311=eng:2310:0:7140:2:2018:0 CNN:12051:vC23:S28.2E:27500:2309:2311=eng:2310:0:7140:2:2018:0
BBC PARL'MNT:12129:vC23:S28.2E:27500:2306:2308=eng,2309=eng:2307:0:7300:2:2022:0 BBC PARL'MNT:12129:vC23:S28.2E:27500:2306:2308=eng,2309=eng:2307:0:7300:2:2022:0
AL HAYAT:11200:vC56:S13.0E:27500:413:414:0:0:4733:318:13400:0 AL HAYAT:11200:vC56:S13.0E:27500:413:414=eng:0:0:4733:318:13400:0
EURO1080:12168:vC34:S19.2E:27500:308:256:0:FF:21100:1:1088:0 EURO1080:12168:vC34:S19.2E:27500:308:256:0:FF:21100:1:1088:0
:@1000 New channels :@1000 New channels

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.124 2004/02/21 15:05:40 kls Exp kls $ * $Id: config.c 1.125 2004/02/28 11:12:20 kls Exp $
*/ */
#include "config.h" #include "config.h"

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.h 1.188 2004/02/21 15:04:53 kls Exp kls $ * $Id: config.h 1.190 2004/03/05 14:35:15 kls Exp $
*/ */
#ifndef __CONFIG_H #ifndef __CONFIG_H
@ -20,8 +20,8 @@
#include "i18n.h" #include "i18n.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "1.3.5" #define VDRVERSION "1.3.6"
#define VDRVERSNUM 10305 // Version * 10000 + Major * 100 + Minor #define VDRVERSNUM 10306 // Version * 10000 + Major * 100 + Minor
#define MAXPRIORITY 99 #define MAXPRIORITY 99
#define MAXLIFETIME 99 #define MAXLIFETIME 99

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: device.h 1.40 2004/02/14 11:29:57 kls Exp $ * $Id: device.h 1.41 2004/03/14 10:47:01 kls Exp $
*/ */
#ifndef __DEVICE_H #ifndef __DEVICE_H
@ -382,7 +382,7 @@ public:
virtual int PlayVideo(const uchar *Data, int Length); virtual int PlayVideo(const uchar *Data, int Length);
///< Actually plays the given data block as video. The data must be ///< Actually plays the given data block as video. The data must be
///< part of a PES (Packetized Elementary Stream) which can contain ///< part of a PES (Packetized Elementary Stream) which can contain
///< one video and one audio strem. ///< one video and one audio stream.
virtual void PlayAudio(const uchar *Data, int Length); virtual void PlayAudio(const uchar *Data, int Length);
///< Plays additional audio streams, like Dolby Digital. ///< Plays additional audio streams, like Dolby Digital.
///< A derived class must call the base class function to make sure data ///< A derived class must call the base class function to make sure data

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbdevice.c 1.82 2004/02/24 10:12:13 kls Exp $ * $Id: dvbdevice.c 1.83 2004/03/14 14:47:46 kls Exp $
*/ */
#include "dvbdevice.h" #include "dvbdevice.h"
@ -101,6 +101,7 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType, cCi
useCa = false; useCa = false;
tunerStatus = tsIdle; tunerStatus = tsIdle;
startTime = time(NULL); startTime = time(NULL);
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
SetDescription("tuner on device %d", cardIndex + 1); SetDescription("tuner on device %d", cardIndex + 1);
Start(); Start();
} }

22
eit.c
View File

@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>. * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
* *
* $Id: eit.c 1.89 2004/02/22 13:17:52 kls Exp kls $ * $Id: eit.c 1.93 2004/03/13 13:54:20 kls Exp $
*/ */
#include "eit.h" #include "eit.h"
@ -43,10 +43,12 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
Schedules->Add(pSchedule); Schedules->Add(pSchedule);
} }
bool Empty = true;
bool Modified = false; bool Modified = false;
SI::EIT::Event SiEitEvent; SI::EIT::Event SiEitEvent;
for (SI::Loop::Iterator it; eventLoop.hasNext(it); ) { for (SI::Loop::Iterator it; eventLoop.hasNext(it); ) {
Empty = false;
SiEitEvent = eventLoop.getNext(it); SiEitEvent = eventLoop.getNext(it);
cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime()); cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime());
@ -82,10 +84,6 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
pEvent->SetVersion(getVersionNumber()); pEvent->SetVersion(getVersionNumber());
pEvent->SetStartTime(SiEitEvent.getStartTime()); pEvent->SetStartTime(SiEitEvent.getStartTime());
pEvent->SetDuration(SiEitEvent.getDuration()); pEvent->SetDuration(SiEitEvent.getDuration());
if (isPresentFollowing()) {
if (SiEitEvent.getRunningStatus() > SI::RunningStatusNotRunning)
pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus());
}
int LanguagePreferenceShort = -1; int LanguagePreferenceShort = -1;
int LanguagePreferenceExt = -1; int LanguagePreferenceExt = -1;
@ -130,11 +128,16 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
struct tm tm_r; struct tm tm_r;
struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't' struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't'
t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
int month = t.tm_mon;
t.tm_mon = pd->getMonth() - 1; t.tm_mon = pd->getMonth() - 1;
t.tm_mday = pd->getDay(); t.tm_mday = pd->getDay();
t.tm_hour = pd->getHour(); t.tm_hour = pd->getHour();
t.tm_min = pd->getMinute(); t.tm_min = pd->getMinute();
t.tm_sec = 0; t.tm_sec = 0;
if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
t.tm_year++;
else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
t.tm_year--;
time_t vps = mktime(&t); time_t vps = mktime(&t);
pEvent->SetVps(vps); pEvent->SetVps(vps);
} }
@ -195,7 +198,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
} }
if (ExtendedEventDescriptors) { if (ExtendedEventDescriptors) {
char buffer[ExtendedEventDescriptors->getMaximumTextLength()]; char buffer[ExtendedEventDescriptors->getMaximumTextLength()];
pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer)); pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, ": "));
} }
} }
delete ExtendedEventDescriptors; delete ExtendedEventDescriptors;
@ -205,8 +208,15 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
if (LinkChannels) if (LinkChannels)
channel->SetLinkChannels(LinkChannels); channel->SetLinkChannels(LinkChannels);
if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
if (SiEitEvent.getRunningStatus() >= SI::RunningStatusNotRunning)
pSchedule->SetRunningStatus(pEvent, SiEitEvent.getRunningStatus(), channel);
}
Modified = true; Modified = true;
} }
if (Empty && Tid == 0x4E && getSectionNumber() == 0)
// ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
pSchedule->ClrRunningStatus(channel);
if (Modified) if (Modified)
pSchedule->Sort(); pSchedule->Sort();
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: eitscan.c 1.21 2004/02/14 13:44:31 kls Exp kls $ * $Id: eitscan.c 1.21 2004/02/14 13:44:31 kls Exp $
*/ */
#include "eitscan.h" #include "eitscan.h"

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: eitscan.h 1.8 2004/01/17 15:36:24 kls Exp kls $ * $Id: eitscan.h 1.8 2004/01/17 15:36:24 kls Exp $
*/ */
#ifndef __EITSCAN_H #ifndef __EITSCAN_H

52
epg.c
View File

@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by * Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* *
* $Id: epg.c 1.13 2004/02/22 14:41:37 kls Exp kls $ * $Id: epg.c 1.18 2004/03/13 15:01:05 kls Exp $
*/ */
#include "epg.h" #include "epg.h"
@ -61,8 +61,11 @@ void cEvent::SetVersion(uchar Version)
version = Version; version = Version;
} }
void cEvent::SetRunningStatus(int RunningStatus) void cEvent::SetRunningStatus(int RunningStatus, cChannel *Channel)
{ {
if (Channel && runningStatus != RunningStatus && (RunningStatus > SI::RunningStatusNotRunning || runningStatus > SI::RunningStatusUndefined))
if (Channel->Number() <= 30)//XXX maybe log only those that have timers???
isyslog("channel %d (%s) event %s '%s' status %d", Channel->Number(), Channel->Name(), GetTimeString(), Title(), RunningStatus);
runningStatus = RunningStatus; runningStatus = RunningStatus;
} }
@ -105,6 +108,11 @@ bool cEvent::HasTimer(void) const
return false; return false;
} }
bool cEvent::IsRunning(bool OrAboutToStart) const
{
return runningStatus >= (OrAboutToStart ? SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusPausing);
}
const char *cEvent::GetDateString(void) const const char *cEvent::GetDateString(void) const
{ {
static char buf[25]; static char buf[25];
@ -146,8 +154,11 @@ void cEvent::Dump(FILE *f, const char *Prefix) const
fprintf(f, "%sT %s\n", Prefix, title); fprintf(f, "%sT %s\n", Prefix, title);
if (!isempty(shortText)) if (!isempty(shortText))
fprintf(f, "%sS %s\n", Prefix, shortText); fprintf(f, "%sS %s\n", Prefix, shortText);
if (!isempty(description)) if (!isempty(description)) {
strreplace(description, '\n', '|');
fprintf(f, "%sD %s\n", Prefix, description); fprintf(f, "%sD %s\n", Prefix, description);
strreplace(description, '|', '\n');
}
if (vps) if (vps)
fprintf(f, "%sV %ld\n", Prefix, vps); fprintf(f, "%sV %ld\n", Prefix, vps);
fprintf(f, "%se\n", Prefix); fprintf(f, "%se\n", Prefix);
@ -186,8 +197,10 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
case 'S': if (Event) case 'S': if (Event)
Event->SetShortText(t); Event->SetShortText(t);
break; break;
case 'D': if (Event) case 'D': if (Event) {
strreplace(t, '|', '\n');
Event->SetDescription(t); Event->SetDescription(t);
}
break; break;
case 'V': if (Event) case 'V': if (Event)
Event->SetVps(atoi(t)); Event->SetVps(atoi(t));
@ -282,11 +295,10 @@ void ReportEpgBugFixStats(bool Reset)
void cEvent::FixEpgBugs(void) void cEvent::FixEpgBugs(void)
{ {
// VDR can't usefully handle newline characters in the EPG data, so let's // VDR can't usefully handle newline characters in the title and shortText of EPG
// always convert them to blanks (independent of the setting of EPGBugfixLevel): // data, so let's always convert them to blanks (independent of the setting of EPGBugfixLevel):
strreplace(title, '\n', ' '); strreplace(title, '\n', ' ');
strreplace(shortText, '\n', ' '); strreplace(shortText, '\n', ' ');
strreplace(description, '\n', ' ');
// Same for control characters: // Same for control characters:
strreplace(title, '\x86', ' '); strreplace(title, '\x86', ' ');
strreplace(title, '\x87', ' '); strreplace(title, '\x87', ' ');
@ -462,6 +474,7 @@ void cEvent::FixEpgBugs(void)
cSchedule::cSchedule(tChannelID ChannelID) cSchedule::cSchedule(tChannelID ChannelID)
{ {
channelID = ChannelID; channelID = ChannelID;
hasRunning = false;;
} }
cEvent *cSchedule::AddEvent(cEvent *Event) cEvent *cSchedule::AddEvent(cEvent *Event)
@ -475,7 +488,7 @@ const cEvent *cSchedule::GetPresentEvent(bool CheckRunningStatus) const
const cEvent *pe = NULL; const cEvent *pe = NULL;
time_t now = time(NULL); time_t now = time(NULL);
for (cEvent *p = events.First(); p; p = events.Next(p)) { for (cEvent *p = events.First(); p; p = events.Next(p)) {
if (p->StartTime() <= now && now < p->StartTime() + p->Duration()) { if (p->StartTime() <= now && now < p->EndTime()) {
pe = p; pe = p;
if (!CheckRunningStatus) if (!CheckRunningStatus)
break; break;
@ -514,7 +527,7 @@ const cEvent *cSchedule::GetEventAround(time_t Time) const
time_t delta = INT_MAX; time_t delta = INT_MAX;
for (cEvent *p = events.First(); p; p = events.Next(p)) { for (cEvent *p = events.First(); p; p = events.Next(p)) {
time_t dt = Time - p->StartTime(); time_t dt = Time - p->StartTime();
if (dt >= 0 && dt < delta && p->StartTime() + p->Duration() >= Time) { if (dt >= 0 && dt < delta && p->EndTime() >= Time) {
delta = dt; delta = dt;
pe = p; pe = p;
} }
@ -522,14 +535,29 @@ const cEvent *cSchedule::GetEventAround(time_t Time) const
return pe; return pe;
} }
void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus) void cSchedule::SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel)
{ {
for (cEvent *p = events.First(); p; p = events.Next(p)) { for (cEvent *p = events.First(); p; p = events.Next(p)) {
if (p == Event) if (p == Event)
p->SetRunningStatus(RunningStatus); p->SetRunningStatus(RunningStatus, Channel);
else if (RunningStatus >= SI::RunningStatusPausing && p->RunningStatus() > SI::RunningStatusNotRunning) else if (RunningStatus >= SI::RunningStatusPausing && p->RunningStatus() > SI::RunningStatusNotRunning)
p->SetRunningStatus(SI::RunningStatusNotRunning); p->SetRunningStatus(SI::RunningStatusNotRunning);
} }
if (RunningStatus >= SI::RunningStatusPausing)
hasRunning = true;
}
void cSchedule::ClrRunningStatus(cChannel *Channel)
{
if (hasRunning) {
for (cEvent *p = events.First(); p; p = events.Next(p)) {
if (p->RunningStatus() >= SI::RunningStatusPausing) {
p->SetRunningStatus(SI::RunningStatusNotRunning, Channel);
hasRunning = false;
break;
}
}
}
} }
void cSchedule::ResetVersions(void) void cSchedule::ResetVersions(void)
@ -555,7 +583,7 @@ void cSchedule::Cleanup(time_t Time)
Event = events.Get(a); Event = events.Get(a);
if (!Event) if (!Event)
break; break;
if (!Event->HasTimer() && Event->StartTime() + Event->Duration() + Setup.EPGLinger * 60 + 3600 < Time) { // adding one hour for safety if (!Event->HasTimer() && Event->EndTime() + Setup.EPGLinger * 60 + 3600 < Time) { // adding one hour for safety
events.Del(Event); events.Del(Event);
a--; a--;
} }

13
epg.h
View File

@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by * Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>. * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* *
* $Id: epg.h 1.10 2004/02/22 14:34:04 kls Exp kls $ * $Id: epg.h 1.15 2004/03/14 13:25:39 kls Exp $
*/ */
#ifndef __EPG_H #ifndef __EPG_H
@ -49,9 +49,11 @@ public:
const char *ShortText(void) const { return shortText; } const char *ShortText(void) const { return shortText; }
const char *Description(void) const { return description; } const char *Description(void) const { return description; }
time_t StartTime(void) const { return startTime; } time_t StartTime(void) const { return startTime; }
time_t EndTime(void) const { return startTime + duration; }
int Duration(void) const { return duration; } int Duration(void) const { return duration; }
time_t Vps(void) const { return vps; } time_t Vps(void) const { return vps; }
bool HasTimer(void) const; bool HasTimer(void) const;
bool IsRunning(bool OrAboutToStart = false) const;
const char *GetDateString(void) const; const char *GetDateString(void) const;
const char *GetTimeString(void) const; const char *GetTimeString(void) const;
const char *GetEndTimeString(void) const; const char *GetEndTimeString(void) const;
@ -59,7 +61,7 @@ public:
void SetEventID(u_int16_t EventID); void SetEventID(u_int16_t EventID);
void SetTableID(uchar TableID); void SetTableID(uchar TableID);
void SetVersion(uchar Version); void SetVersion(uchar Version);
void SetRunningStatus(int RunningStatus); void SetRunningStatus(int RunningStatus, cChannel *Channel = NULL);
void SetTitle(const char *Title); void SetTitle(const char *Title);
void SetShortText(const char *ShortText); void SetShortText(const char *ShortText);
void SetDescription(const char *Description); void SetDescription(const char *Description);
@ -77,21 +79,22 @@ class cSchedule : public cListObject {
private: private:
tChannelID channelID; tChannelID channelID;
cList<cEvent> events; cList<cEvent> events;
bool hasRunning;
public: public:
cSchedule(tChannelID ChannelID); cSchedule(tChannelID ChannelID);
tChannelID ChannelID(void) const { return channelID; } tChannelID ChannelID(void) const { return channelID; }
void SetRunningStatus(cEvent *Event, int RunningStatus); void SetRunningStatus(cEvent *Event, int RunningStatus, cChannel *Channel = NULL);
void ClrRunningStatus(cChannel *Channel = NULL);
void ResetVersions(void); void ResetVersions(void);
void Sort(void); void Sort(void);
void Cleanup(time_t Time); void Cleanup(time_t Time);
void Cleanup(void); void Cleanup(void);
cEvent *AddEvent(cEvent *Event); cEvent *AddEvent(cEvent *Event);
const cList<cEvent> *Events(void) const { return &events; }
const cEvent *GetPresentEvent(bool CheckRunningStatus = false) const; const cEvent *GetPresentEvent(bool CheckRunningStatus = false) const;
const cEvent *GetFollowingEvent(bool CheckRunningStatus = false) const; const cEvent *GetFollowingEvent(bool CheckRunningStatus = false) const;
const cEvent *GetEvent(u_int16_t EventID, time_t StartTime = 0) const; const cEvent *GetEvent(u_int16_t EventID, time_t StartTime = 0) const;
const cEvent *GetEventAround(time_t Time) const; const cEvent *GetEventAround(time_t Time) const;
const cEvent *GetEventNumber(int n) const { return events.Get(n); }
int NumEvents(void) const { return events.Count(); }
void Dump(FILE *f, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0) const; void Dump(FILE *f, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0) const;
static bool Read(FILE *f, cSchedules *Schedules); static bool Read(FILE *f, cSchedules *Schedules);
}; };

28
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: i18n.c 1.148 2004/02/21 15:14:36 kls Exp kls $ * $Id: i18n.c 1.152 2004/03/13 10:59:23 kls Exp $
* *
* Translations provided by: * Translations provided by:
* *
@ -1550,6 +1550,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"VPS",
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -1557,8 +1558,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "VPS ßÞßàÐÒÚÐ",
"",// TODO
}, },
{ "Priority", { "Priority",
"Priorität", "Priorität",
@ -1839,9 +1839,9 @@ const tI18nPhrase Phrases[] = {
"",//TODO "",//TODO
"Pas de marques d'édition définies!", "Pas de marques d'édition définies!",
"",//TODO "",//TODO
"",//TODO "Muokkausmerkinnät puuttuvat!",
"Brak znakow montazowych!", "Brak znakow montazowych!",
"Muokkausmerkinnät puuttuvat", "",//TODO
"ÄÝí Ý÷ïõí ïñéóôåß óçìåßá åðåîåñãáóßáò", "ÄÝí Ý÷ïõí ïñéóôåß óçìåßá åðåîåñãáóßáò",
"Det finns inga redigeringsmärken",//TODO "Det finns inga redigeringsmärken",//TODO
"",//TODO "",//TODO
@ -2389,7 +2389,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "ÅàÐÝÕÝØÕ ãáâÐàÕÒèØå ÔÐÝÝëå (ÜØÝ)",
}, },
{ "Setup.EPG$Set system time", { "Setup.EPG$Set system time",
"Systemzeit stellen", "Systemzeit stellen",
@ -2777,7 +2777,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"Priorité des pauses", "Priorité des pauses",
"",// TODO "",// TODO
"Keskeytyksen prioriteetti", "Taukotallenteen prioriteetti",
"Priorytet przerwy", "Priorytet przerwy",
"",// TODO "",// TODO
"Ðñïôåñáéüôçôá äéáëåßììáôïò", "Ðñïôåñáéüôçôá äéáëåßììáôïò",
@ -2795,7 +2795,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"Durée de vie des pauses (j)", "Durée de vie des pauses (j)",
"",// TODO "",// TODO
"Keskeytyksen elinikä (d)", "Taukotallenteen elinikä (d)",
"Okres trwania przerwy (d)", "Okres trwania przerwy (d)",
"",// TODO "",// TODO
"ÄéÜñêåéá äéáëåßìáôïò", "ÄéÜñêåéá äéáëåßìáôïò",
@ -2831,6 +2831,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"Käytä VPS-toimintoa",
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2838,8 +2839,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "¸áßÞÛì×ÞÒÐâì áØÓÝÐÛë VPS",
"",// TODO
}, },
{ "Setup.Recording$VPS margin (s)", { "Setup.Recording$VPS margin (s)",
"Zeitpuffer bei VPS (s)", "Zeitpuffer bei VPS (s)",
@ -2849,6 +2849,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"VPS-toiminnon aloitusmarginaali (s)",
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
@ -2856,8 +2857,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "",// TODO
"",// TODO "±ãäÕàÝÞÕ ÒàÕÜï VPS (áÕÚ)",
"",// TODO
}, },
{ "Setup.Recording$Mark instant recording", { "Setup.Recording$Mark instant recording",
"Direktaufzeichnung markieren", "Direktaufzeichnung markieren",
@ -3627,7 +3627,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"Pause", "Pause",
"",// TODO "",// TODO
"Keskeytä", "Tauko",
"Przerwa", "Przerwa",
"Pausa", "Pausa",
"ÄéÜëåéììá", "ÄéÜëåéììá",
@ -4186,7 +4186,7 @@ const tI18nPhrase Phrases[] = {
"",// TODO "",// TODO
"Pause de l'émission en direct...", "Pause de l'émission en direct...",
"",// TODO "",// TODO
"Keskeytetään lähetys...", "Pysäytetään lähetys...",
"Zatrzymany program biezacy...", "Zatrzymany program biezacy...",
"Emisión en directo parada...", "Emisión en directo parada...",
"ÄéÜëåéììá æùíôáíïý óÞìáôïò", "ÄéÜëåéììá æùíôáíïý óÞìáôïò",

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* $Id: descriptor.c 1.6 2004/02/22 11:11:36 kls Exp $ * $Id: descriptor.c 1.10 2004/03/13 15:08:12 kls Exp $
* * * *
***************************************************************************/ ***************************************************************************/
@ -60,13 +60,13 @@ void ExtendedEventDescriptor::Item::Parse() {
item.setData(data+offset, mid->item_length); item.setData(data+offset, mid->item_length);
} }
int ExtendedEventDescriptors::getTextLength() { /*int ExtendedEventDescriptors::getTextLength() {
int ret=0; int ret=0;
for (int i=0;i<length;i++) { for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i]; ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d) if (!d)
continue; continue;
ret+=d->text.getLength()+1; //plus a blank ret+=d->text.getLength();
ExtendedEventDescriptor::Item item; ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) { for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it); item=d->itemLoop.getNext(it);
@ -76,28 +76,18 @@ int ExtendedEventDescriptors::getTextLength() {
} }
} }
return ret; return ret;
} }*/
//is there a case where this function does not return the same as getTextLength?
int ExtendedEventDescriptors::getMaximumTextLength() { int ExtendedEventDescriptors::getMaximumTextLength() {
int ret=0; return getMaximumTextPlainLength()+getMaximumTextItemizedLength();
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength()+1; //plus a blank
ret+=d->itemLoop.getLength();
}
return ret;
} }
char *ExtendedEventDescriptors::getText() { char *ExtendedEventDescriptors::getText(const char *separation1, const char *separation2) {
char *text=new char[getMaximumTextLength()]; char *text=new char[getMaximumTextLength()+strlen(separation1)+strlen(separation2)];
return getText(text); return getText(text, separation1, separation2);
} }
//appends the Strings of every Descriptor in the group char *ExtendedEventDescriptors::getText(char *buffer, const char *separation1, const char *separation2) {
char *ExtendedEventDescriptors::getText(char *buffer) {
int index=0, len; int index=0, len;
char tempbuf[256]; char tempbuf[256];
for (int i=0;i<length;i++) { for (int i=0;i<length;i++) {
@ -110,30 +100,164 @@ char *ExtendedEventDescriptors::getText(char *buffer) {
memcpy(buffer+index, tempbuf, len); memcpy(buffer+index, tempbuf, len);
index+=len; index+=len;
} }
}
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
strcpy(buffer+index, separation2); // let's have a separator between the long text and the items
index += strlen(separation2);
ExtendedEventDescriptor::Item item; ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) { for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it); item=d->itemLoop.getNext(it);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
item.itemDescription.getText(tempbuf); item.itemDescription.getText(tempbuf);
len=strlen(tempbuf); len=strlen(tempbuf);
if (len) { if (len) {
memcpy(buffer+index, tempbuf, len); memcpy(buffer+index, tempbuf, len);
index+=len; index+=len;
} }
strcpy(buffer+index, separation1);
index += strlen(separation1);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation2);
index += strlen(separation2);
}
}
buffer[index]='\0';
return buffer;
}
int ExtendedEventDescriptors::getMaximumTextPlainLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ret+=d->text.getLength();
}
return ret;
}
char *ExtendedEventDescriptors::getTextPlain() {
char *text=new char[getMaximumTextPlainLength()];
return getTextPlain(text);
}
char *ExtendedEventDescriptors::getTextPlain(char *buffer) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
d->text.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
} }
} }
buffer[index]='\0'; buffer[index]='\0';
return buffer; return buffer;
} }
int ExtendedEventDescriptors::getMaximumTextItemizedLength() {
int ret=0;
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
//the size for the two separating characters is included ;-)
ret+=d->itemLoop.getLength();
}
return ret;
}
char *ExtendedEventDescriptors::getTextItemized(const char *separation1, const char *separation2) {
char *text=new char[getMaximumTextItemizedLength()+strlen(separation1)+strlen(separation2)];
return getTextItemized(text, separation1, separation2);
}
char *ExtendedEventDescriptors::getTextItemized(char *buffer, const char *separation1, const char *separation2) {
int index=0, len;
char tempbuf[256];
for (int i=0;i<length;i++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[i];
if (!d)
continue;
ExtendedEventDescriptor::Item item;
for (Loop::Iterator it; d->itemLoop.hasNext(it); ) {
item=d->itemLoop.getNext(it);
item.itemDescription.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation1);
index += strlen(separation1);
item.item.getText(tempbuf);
len=strlen(tempbuf);
if (len) {
memcpy(buffer+index, tempbuf, len);
index+=len;
}
strcpy(buffer+index, separation2);
index += strlen(separation2);
}
}
buffer[index]='\0';
return buffer;
}
//returns the itemized text pair by pair. Maximum length for buffers is 256.
//Return value is false if and only if the end of the list is reached.
bool ExtendedEventDescriptors::getTextItemized(Loop::Iterator &it, bool &valid, char *itemDescription, char *itemText) {
//The iterator has to store two values: The descriptor index (4bit)
//and the item loop index (max overall length 256, min item length 16 => max number 128 => 7bit)
valid=false;
int index=(it.i & 0x780) >> 7; // 0x780 == 1111 000 0000
it.i &= 0x7F; //0x7F == 111 1111
for (;index<length;index++) {
ExtendedEventDescriptor *d=(ExtendedEventDescriptor *)array[index];
if (!d)
continue;
ExtendedEventDescriptor::Item item;
if (d->itemLoop.hasNext(it)) {
item=d->itemLoop.getNext(it);
item.item.getText(itemDescription);
item.itemDescription.getText(itemText);
valid=true;
break;
} else {
it.reset();
continue;
}
}
it.i &= 0x7F;
it.i |= (index & 0xF) << 7; //0xF == 1111
return index<length;
}
int TimeShiftedEventDescriptor::getReferenceServiceId() const { int TimeShiftedEventDescriptor::getReferenceServiceId() const {
return HILO(s->reference_service_id); return HILO(s->reference_service_id);
} }
@ -148,7 +272,7 @@ void TimeShiftedEventDescriptor::Parse() {
void ContentDescriptor::Parse() { void ContentDescriptor::Parse() {
//this descriptor is only a header and a loop //this descriptor is only a header and a loop
nibbleLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader)); nibbleLoop.setData(data+sizeof(descr_content), getLength()-sizeof(descr_content));
} }
int ContentDescriptor::Nibble::getContentNibbleLevel1() const { int ContentDescriptor::Nibble::getContentNibbleLevel1() const {
@ -173,7 +297,7 @@ void ContentDescriptor::Nibble::Parse() {
void ParentalRatingDescriptor::Parse() { void ParentalRatingDescriptor::Parse() {
//this descriptor is only a header and a loop //this descriptor is only a header and a loop
ratingLoop.setData(data+sizeof(SectionHeader), getLength()-sizeof(SectionHeader)); ratingLoop.setData(data+sizeof(descr_parental_rating), getLength()-sizeof(descr_parental_rating));
} }
int ParentalRatingDescriptor::Rating::getRating() const { int ParentalRatingDescriptor::Rating::getRating() const {

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* $Id: descriptor.h 1.6 2004/02/22 10:16:47 kls Exp $ * $Id: descriptor.h 1.7 2004/03/07 11:13:54 kls Exp $
* * * *
***************************************************************************/ ***************************************************************************/
@ -50,14 +50,29 @@ private:
class ExtendedEventDescriptors : public DescriptorGroup { class ExtendedEventDescriptors : public DescriptorGroup {
public: public:
//don't use
int getTextLength();
//really fast
int getMaximumTextLength(); int getMaximumTextLength();
//Returns a concatenated version of first the non-itemized and then the itemized text
//same semantics as with SI::String //same semantics as with SI::String
char *getText(); char *getText(const char *separation1="\t", const char *separation2="\n");
//buffer must at least be getTextLength(), getMaximumTextLength() is a good choice //buffer must at least be getTextLength(), getMaximumTextLength() is a good choice
char *getText(char *buffer); char *getText(char *buffer, const char *separation1="\t", const char *separation2="\n");
//these only return the non-itemized text fields in concatenated form
int getMaximumTextPlainLength();
char *getTextPlain();
char *getTextPlain(char *buffer);
//these only return the itemized text fields in concatenated form.
//Between the description and the text the separation1 character is used,
//separation2 used between two pairs. Example:
//Director\tSteven Spielberg\nActor\tMichael Mendl\n
int getMaximumTextItemizedLength();
char *getTextItemized(const char *separation1="\t", const char *separation2="\n");
char *getTextItemized(char *buffer, const char *separation1="\t", const char *separation2="\n");
//returns the itemized text pair by pair. Maximum length for buffers is 256.
//Return value is false if and only if the end of the list is reached.
//The argument valid indicates whether the buffers contain valid content.
bool getTextItemized(Loop::Iterator &it, bool &valid, char *itemDescription, char *itemText);
}; };
class TimeShiftedEventDescriptor : public Descriptor { class TimeShiftedEventDescriptor : public Descriptor {

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* $Id: si.c 1.8 2004/02/22 10:14:12 kls Exp $ * $Id: si.c 1.9 2004/03/07 10:50:09 kls Exp $
* * * *
***************************************************************************/ ***************************************************************************/
@ -103,7 +103,7 @@ DescriptorTag Descriptor::getDescriptorTag(const unsigned char *d) {
Descriptor *DescriptorLoop::getNext(Iterator &it) { Descriptor *DescriptorLoop::getNext(Iterator &it) {
if (it.i<getLength()) { if (it.i<getLength()) {
return createDescriptor(it.i); return createDescriptor(it.i, true);
} }
return 0; return 0;
} }
@ -115,19 +115,18 @@ Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag tag, bool return
const unsigned char *end=p+getLength(); const unsigned char *end=p+getLength();
while (p < end) { while (p < end) {
if (Descriptor::getDescriptorTag(p) == tag) { if (Descriptor::getDescriptorTag(p) == tag) {
d=createDescriptor(it.i); d=createDescriptor(it.i, returnUnimplemetedDescriptor);
if (d)
break; break;
} }
it.i+=Descriptor::getLength(p); it.i+=Descriptor::getLength(p);
p+=Descriptor::getLength(p); p+=Descriptor::getLength(p);
} }
} }
if (d && d->getDescriptorTag()==UnimplementedDescriptorTag)
return returnUnimplemetedDescriptor ? d : 0;
return d; return d;
} }
Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor) { Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplementedDescriptor) {
Descriptor *d=0; Descriptor *d=0;
if (it.i<getLength()) { if (it.i<getLength()) {
const unsigned char *p=data.getData(it.i); const unsigned char *p=data.getData(it.i);
@ -135,27 +134,38 @@ Descriptor *DescriptorLoop::getNext(Iterator &it, DescriptorTag *tags, int array
while (p < end) { while (p < end) {
for (int u=0; u<arrayLength;u++) for (int u=0; u<arrayLength;u++)
if (Descriptor::getDescriptorTag(p) == tags[u]) { if (Descriptor::getDescriptorTag(p) == tags[u]) {
d=createDescriptor(it.i); d=createDescriptor(it.i, returnUnimplementedDescriptor);
break; break;
} }
if (d) if (d)
break; break; //length is added to it.i by createDescriptor, break here
it.i+=Descriptor::getLength(p); it.i+=Descriptor::getLength(p);
p+=Descriptor::getLength(p); p+=Descriptor::getLength(p);
} }
} }
if (d && d->getDescriptorTag()==UnimplementedDescriptorTag)
return returnUnimplemetedDescriptor ? d : 0;
return d; return d;
} }
Descriptor *DescriptorLoop::createDescriptor(int &i) { Descriptor *DescriptorLoop::createDescriptor(int &i, bool returnUnimplemetedDescriptor) {
Descriptor *d=Descriptor::getDescriptor(data+i, domain); Descriptor *d=Descriptor::getDescriptor(data+i, domain, returnUnimplemetedDescriptor);
if (!d)
return 0;
i+=d->getLength(); i+=d->getLength();
d->CheckParse(); d->CheckParse();
return d; return d;
} }
int DescriptorLoop::getNumberOfDescriptors() {
const unsigned char *p=data.getData();
const unsigned char *end=p+getLength();
int count=0;
while (p < end) {
count++;
p+=Descriptor::getLength(p);
}
return count;
}
DescriptorGroup::DescriptorGroup(bool del) { DescriptorGroup::DescriptorGroup(bool del) {
array=0; array=0;
length=0; length=0;
@ -211,6 +221,16 @@ char *String::getText(char *buffer) {
return buffer; return buffer;
} }
//taken from VDR, Copyright Klaus Schmidinger <kls@cadsoft.de>
char *String::getText(char *buffer, char *shortVersion) {
if (getLength() < 0 || getLength() >4095) {
strncpy(buffer, "text error", getLength()+1);
return buffer;
}
decodeText(buffer, shortVersion);
return buffer;
}
//taken from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de> //taken from libdtv, Copyright Rolf Hakenes <hakenes@hippomi.de>
void String::decodeText(char *buffer) { void String::decodeText(char *buffer) {
const unsigned char *from=data.getData(0); const unsigned char *from=data.getData(0);
@ -228,18 +248,47 @@ void String::decodeText(char *buffer) {
if ( ((' ' <= *from) && (*from <= '~')) if ( ((' ' <= *from) && (*from <= '~'))
|| (*from == '\n') || (*from == '\n')
|| (0xA0 <= *from) || (0xA0 <= *from)
|| (*from == 0x86 || *from == 0x87)
) )
*to++ = *from; *to++ = *from;
else if (*from == 0x8A) else if (*from == 0x8A)
*to++ = '\n'; *to++ = '\n';
else if (*from == 0x86 || *from == 0x87) //&& !(GDT_NAME_DESCRIPTOR & type))
*to++ = *from;
from++; from++;
} }
*to = '\0'; *to = '\0';
} }
Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain) { void String::decodeText(char *buffer, char *shortVersion) {
const unsigned char *from=data.getData(0);
char *to=buffer;
char *toShort=shortVersion;
int IsShortName=0;
for (int i = 0; i < getLength(); i++) {
if (*from == 0)
break;
if ( ((' ' <= *from) && (*from <= '~'))
|| (*from == '\n')
|| (0xA0 <= *from)
)
{
*to++ = *from;
if (IsShortName)
*toShort++ = *from;
}
else if (*from == 0x8A)
*to++ = '\n';
else if (*from == 0x86)
IsShortName++;
else if (*from == 0x87)
IsShortName--;
from++;
}
*to = '\0';
*toShort = '\0';
}
Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor) {
Descriptor *d=0; Descriptor *d=0;
switch (domain) { switch (domain) {
case SI: case SI:
@ -383,6 +432,8 @@ Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain)
case AdaptationFieldDataDescriptorTag: case AdaptationFieldDataDescriptorTag:
case TransportStreamDescriptorTag: case TransportStreamDescriptorTag:
default: default:
if (!returnUnimplemetedDescriptor)
return 0;
d=new UnimplementedDescriptor(); d=new UnimplementedDescriptor();
break; break;
} }
@ -417,6 +468,8 @@ Descriptor *Descriptor::getDescriptor(CharArray da, DescriptorTagDomain domain)
case MHP_DelegatedApplicationDescriptorTag: case MHP_DelegatedApplicationDescriptorTag:
case MHP_ApplicationStorageDescriptorTag: case MHP_ApplicationStorageDescriptorTag:
default: default:
if (!returnUnimplemetedDescriptor)
return 0;
d=new UnimplementedDescriptor(); d=new UnimplementedDescriptor();
break; break;
} }

View File

@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
* * * *
* $Id: si.h 1.8 2004/02/23 17:02:33 kls Exp $ * $Id: si.h 1.9 2004/03/07 10:09:49 kls Exp $
* * * *
***************************************************************************/ ***************************************************************************/
@ -252,8 +252,11 @@ protected:
//returns a subclass of descriptor according to the data given. //returns a subclass of descriptor according to the data given.
//The object is allocated with new and must be delete'd. //The object is allocated with new and must be delete'd.
//setData() will have been called, CheckParse() not. //setData() will have been called, CheckParse() not.
//if returnUnimplemetedDescriptor==true:
// Never returns null - maybe the UnimplementedDescriptor. // Never returns null - maybe the UnimplementedDescriptor.
static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain); //if returnUnimplemetedDescriptor==false:
// Never returns the UnimplementedDescriptor - maybe null
static Descriptor *getDescriptor(CharArray d, DescriptorTagDomain domain, bool returnUnimplemetedDescriptor);
}; };
class Loop : public VariableLengthPart { class Loop : public VariableLengthPart {
@ -266,6 +269,7 @@ public:
template <class T> friend class StructureLoop; template <class T> friend class StructureLoop;
friend class DescriptorLoop; friend class DescriptorLoop;
template <class T> friend class TypeLoop; template <class T> friend class TypeLoop;
friend class ExtendedEventDescriptors;
int i; int i;
}; };
protected: protected:
@ -311,14 +315,46 @@ public:
//returns null if no more descriptors available //returns null if no more descriptors available
Descriptor *getNext(Iterator &it); Descriptor *getNext(Iterator &it);
//return the next descriptor with given tag, or 0 if not available. //return the next descriptor with given tag, or 0 if not available.
//if the descriptor found is not implemented, //if returnUnimplemetedDescriptor==true:
// an UnimplementedDescriptor will be returned if returnUnimplemetedDescriptor==true, // an UnimplementedDescriptor may be returned if the next matching descriptor is unimplemented,
// 0 will be returned if returnUnimplemetedDescriptor==false // 0 will be returned if and only if no matching descriptor is found.
//if returnUnimplemetedDescriptor==false:
// if 0 is returned, either no descriptor with the given tag was found,
// or descriptors were found, but the descriptor type is not implemented
//In either case, a return value of 0 indicates that no further calls to this method
//with the iterator shall be made.
Descriptor *getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor=false); Descriptor *getNext(Iterator &it, DescriptorTag tag, bool returnUnimplemetedDescriptor=false);
//return the next descriptor with one of the given tags, or 0 if not available. //return the next descriptor with one of the given tags, or 0 if not available.
//if returnUnimplemetedDescriptor==true:
// returns 0 if and only if no descriptor with one of the given tags was found.
// The UnimplementedDescriptor may be returned.
//if returnUnimplemetedDescriptor==false:
// if 0 is returned, either no descriptor with one of the given tags was found,
// or descriptors were found, but none of them are implemented.
// The UnimplementedDescriptor will never be returned.
//In either case, a return value of 0 indicates that no further calls to this method
//with the iterator shall be made.
Descriptor *getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor=false); Descriptor *getNext(Iterator &it, DescriptorTag *tags, int arrayLength, bool returnUnimplemetedDescriptor=false);
//returns the number of descriptors in this loop
int getNumberOfDescriptors();
//writes the tags of the descriptors in this loop in the array,
// which must at least have the size getNumberOfDescriptors().
//The number of descriptors, i.e. getNumberOfDescriptors(), is returned.
// You can specify the array type (Descriptor tags are 8 Bit,
// you might e.g. choose a char, short, int or DescriptorTag array)
template <typename T> int getDescriptorTags(T *tags)
{
const unsigned char *p=data.getData();
const unsigned char *end=p+getLength();
int count=0;
while (p < end) {
tags[count++]=(T)Descriptor::getDescriptorTag(p);
p+=Descriptor::getLength(p);
}
return count;
}
protected: protected:
Descriptor *createDescriptor(int &i); Descriptor *createDescriptor(int &i, bool returnUnimplemetedDescriptor);
DescriptorTagDomain domain; DescriptorTagDomain domain;
}; };
@ -385,7 +421,7 @@ class String : public VariableLengthPart {
public: public:
//A note to the length: getLength() returns the length of the raw data. //A note to the length: getLength() returns the length of the raw data.
//The text may be shorter. Its length can be obtained with one of the //The text may be shorter. Its length can be obtained with one of the
//above functions and strlen. //getText functions and strlen.
//returns text. Data is allocated with new and must be delete'd by the user. //returns text. Data is allocated with new and must be delete'd by the user.
char *getText(); char *getText();
@ -394,10 +430,19 @@ public:
//In most descriptors the string length is an 8-bit field, //In most descriptors the string length is an 8-bit field,
//so the maximum there is 256. //so the maximum there is 256.
//returns the given buffer for convenience. //returns the given buffer for convenience.
//The emphasis marks 0x86 and 0x87 are still available.
char *getText(char *buffer); char *getText(char *buffer);
//The same semantics as for getText(char*) apply.
//The short version of the text according to ETSI TR 101 211 (chapter 4.6)
//will be written into the shortVersion buffer (which should, therefore, have the same
//length as buffer). If no shortVersion is available, shortVersion will contain
//an empty string.
//The emphasis marks 0x86 and 0x87 are still available in buffer, but not in shortVersion.
char *getText(char *buffer, char *shortVersion);
protected: protected:
virtual void Parse() {} virtual void Parse() {}
void decodeText(char *buffer); void decodeText(char *buffer);
void decodeText(char *buffer, char *shortVersion);
}; };
} //end of namespace } //end of namespace

28
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.292 2004/02/22 14:14:55 kls Exp kls $ * $Id: menu.c 1.297 2004/03/14 13:24:02 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -18,7 +18,6 @@
#include "cutter.h" #include "cutter.h"
#include "eitscan.h" #include "eitscan.h"
#include "i18n.h" #include "i18n.h"
#include "libsi/si.h"
#include "menuitems.h" #include "menuitems.h"
#include "plugin.h" #include "plugin.h"
#include "recording.h" #include "recording.h"
@ -1009,13 +1008,8 @@ public:
cMenuTimers::cMenuTimers(void) cMenuTimers::cMenuTimers(void)
:cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6) :cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6)
{ {
int i = 0; for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer))
cTimer *timer;
while ((timer = Timers.Get(i)) != NULL) {
Add(new cMenuTimerItem(timer)); Add(new cMenuTimerItem(timer));
i++;
}
if (Setup.SortTimers) if (Setup.SortTimers)
Sort(); Sort();
SetHelp(tr("Edit"), tr("New"), tr("Delete"), Setup.SortTimers ? tr("On/Off") : tr("Mark")); SetHelp(tr("Edit"), tr("New"), tr("Delete"), Setup.SortTimers ? tr("On/Off") : tr("Mark"));
@ -1216,7 +1210,7 @@ cMenuWhatsOnItem::cMenuWhatsOnItem(const cEvent *Event, cChannel *Channel)
int TimerMatch; int TimerMatch;
char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' '; char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' ';
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
char r = event->RunningStatus() > SI::RunningStatusNotRunning ? '*' : ' '; char r = event->IsRunning() ? '*' : ' ';
asprintf(&buffer, "%d\t%.*s\t%.*s\t%c%c%c\t%s", channel->Number(), 6, channel->Name(), 5, event->GetTimeString(), t, v, r, event->Title()); asprintf(&buffer, "%d\t%.*s\t%.*s\t%c%c%c\t%s", channel->Number(), 6, channel->Name(), 5, event->GetTimeString(), t, v, r, event->Title());
SetText(buffer, false); SetText(buffer, false);
} }
@ -1334,7 +1328,7 @@ cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event)
int TimerMatch; int TimerMatch;
char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' '; char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' ';
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' '; char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
char r = event->RunningStatus() > SI::RunningStatusNotRunning ? '*' : ' '; char r = event->IsRunning() ? '*' : ' ';
asprintf(&buffer, "%.*s\t%.*s\t%c%c%c\t%s", 5, event->GetDateString(), 5, event->GetTimeString(), t, v, r, event->Title()); asprintf(&buffer, "%.*s\t%.*s\t%c%c%c\t%s", 5, event->GetDateString(), 5, event->GetTimeString(), t, v, r, event->Title());
SetText(buffer, false); SetText(buffer, false);
} }
@ -1386,11 +1380,9 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel)
const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID()); const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
if (Schedule) { if (Schedule) {
const cEvent *PresentEvent = Schedule->GetPresentEvent(Channel->Number() == cDevice::CurrentChannel()); const cEvent *PresentEvent = Schedule->GetPresentEvent(Channel->Number() == cDevice::CurrentChannel());
int num = Schedule->NumEvents();
time_t now = time(NULL) - Setup.EPGLinger * 60; time_t now = time(NULL) - Setup.EPGLinger * 60;
for (int a = 0; a < num; a++) { for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event)) {
const cEvent *Event = Schedule->GetEventNumber(a); if (Event->EndTime() > now || Event == PresentEvent)
if (Event->StartTime() + Event->Duration() > now || Event == PresentEvent)
Add(new cMenuScheduleItem(Event), Event == PresentEvent); Add(new cMenuScheduleItem(Event), Event == PresentEvent);
} }
} }
@ -1494,13 +1486,8 @@ cMenuCommands::cMenuCommands(const char *Title, cCommands *Commands, const char
SetHasHotkeys(); SetHasHotkeys();
commands = Commands; commands = Commands;
parameters = Parameters ? strdup(Parameters) : NULL; parameters = Parameters ? strdup(Parameters) : NULL;
int i = 0; for (cCommand *command = commands->First(); command; command = commands->Next(command))
cCommand *command;
while ((command = commands->Get(i)) != NULL) {
Add(new cOsdItem(hk(command->Title()))); Add(new cOsdItem(hk(command->Title())));
i++;
}
} }
cMenuCommands::~cMenuCommands() cMenuCommands::~cMenuCommands()
@ -3196,6 +3183,7 @@ bool cRecordControls::Start(cTimer *Timer, bool Pause)
if (device == cTransferControl::ReceiverDevice()) if (device == cTransferControl::ReceiverDevice())
cControl::Shutdown(); // in case this device was used for Transfer Mode cControl::Shutdown(); // in case this device was used for Transfer Mode
} }
dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number());
if (!device->SwitchChannel(channel, false)) { if (!device->SwitchChannel(channel, false)) {
cThread::EmergencyExit(true); cThread::EmergencyExit(true);
return false; return false;

2
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.h 1.60 2004/02/15 14:11:28 kls Exp kls $ * $Id: menu.h 1.60 2004/02/15 14:11:28 kls Exp $
*/ */
#ifndef __MENU_H #ifndef __MENU_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menuitems.c 1.14 2004/01/25 15:40:55 kls Exp kls $ * $Id: menuitems.c 1.15 2004/02/24 12:38:43 kls Exp $
*/ */
#include "menuitems.h" #include "menuitems.h"

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menuitems.h 1.5 2003/01/12 15:06:23 kls Exp kls $ * $Id: menuitems.h 1.6 2004/02/24 11:55:14 kls Exp $
*/ */
#ifndef __MENUITEMS_H #ifndef __MENUITEMS_H

30
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: osd.c 1.43 2003/06/04 16:13:00 kls Exp $ * $Id: osd.c 1.45 2004/03/14 10:33:20 kls Exp $
*/ */
#include "osd.h" #include "osd.h"
@ -429,30 +429,27 @@ void cOsdMenu::Display(void)
Interface->Help(helpRed, helpGreen, helpYellow, helpBlue); Interface->Help(helpRed, helpGreen, helpYellow, helpBlue);
int count = Count(); int count = Count();
if (count > 0) { if (count > 0) {
for (int i = 0; i < count; i++) { int ni = 0;
cOsdItem *item = Get(i); for (cOsdItem *item = First(); item; item = Next(item))
if (item) cStatus::MsgOsdItem(item->Text(), ni++);
cStatus::MsgOsdItem(item->Text(), i);
}
if (current < 0) if (current < 0)
current = 0; // just for safety - there HAS to be a current item! current = 0; // just for safety - there HAS to be a current item!
int n = 0; if (current - first >= MAXOSDITEMS || current < first) {
if (current - first >= MAXOSDITEMS) {
first = current - MAXOSDITEMS / 2; first = current - MAXOSDITEMS / 2;
if (first + MAXOSDITEMS > count) if (first + MAXOSDITEMS > count)
first = count - MAXOSDITEMS; first = count - MAXOSDITEMS;
if (first < 0) if (first < 0)
first = 0; first = 0;
} }
for (int i = first; i < count; i++) { int i = first;
cOsdItem *item = Get(i); int n = 0;
if (item) { for (cOsdItem *item = Get(first); item; item = Next(item)) {
item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground); item->Display(i - first, i == current ? clrBlack : clrWhite, i == current ? clrCyan : clrBackground);
if (i == current) if (i == current)
cStatus::MsgOsdCurrentItem(item->Text()); cStatus::MsgOsdCurrentItem(item->Text());
}
if (++n == MAXOSDITEMS) //TODO get this from Interface!!! if (++n == MAXOSDITEMS) //TODO get this from Interface!!!
break; break;
i++;
} }
} }
if (!isempty(status)) if (!isempty(status))
@ -562,12 +559,13 @@ void cOsdMenu::PageDown(void)
{ {
current += MAXOSDITEMS; current += MAXOSDITEMS;
first += MAXOSDITEMS; first += MAXOSDITEMS;
if (current > Count() - 1) { int count = Count();
current = Count() - 1; if (current > count - 1) {
first = max(0, Count() - MAXOSDITEMS); current = count - 1;
first = max(0, count - MAXOSDITEMS);
} }
if (SpecialItem(current)) { if (SpecialItem(current)) {
current += (current < Count() - 1) ? 1 : -1; current += (current < count - 1) ? 1 : -1;
first = max(first, current - MAXOSDITEMS); first = max(first, current - MAXOSDITEMS);
} }
Display(); Display();

18
pat.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: pat.c 1.7 2004/01/25 15:12:53 kls Exp $ * $Id: pat.c 1.8 2004/03/07 16:59:00 kls Exp $
*/ */
#include "pat.h" #include "pat.h"
@ -250,19 +250,21 @@ void cPatFilter::Trigger(void)
numPmtEntries = 0; numPmtEntries = 0;
} }
bool cPatFilter::PmtVersionChanged(int PmtPid, int Version) bool cPatFilter::PmtVersionChanged(int PmtPid, int Sid, int Version)
{ {
Version <<= 16; uint64_t v = Version;
v <<= 32;
uint64_t id = (PmtPid | (Sid << 16)) & 0x00000000FFFFFFFFLL;
for (int i = 0; i < numPmtEntries; i++) { for (int i = 0; i < numPmtEntries; i++) {
if ((pmtVersion[i] & 0x0000FFFF) == PmtPid) { if ((pmtVersion[i] & 0x00000000FFFFFFFFLL) == id) {
bool Changed = (pmtVersion[i] & 0x00FF0000) != Version; bool Changed = (pmtVersion[i] & 0x000000FF00000000LL) != v;
if (Changed) if (Changed)
pmtVersion[i] = PmtPid | Version; pmtVersion[i] = id | v;
return Changed; return Changed;
} }
} }
if (numPmtEntries < MAXPMTENTRIES) if (numPmtEntries < MAXPMTENTRIES)
pmtVersion[numPmtEntries++] = PmtPid | Version; pmtVersion[numPmtEntries++] = id | v;
return true; return true;
} }
@ -301,7 +303,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
SI::PMT pmt(Data, false); SI::PMT pmt(Data, false);
if (!pmt.CheckCRCAndParse()) if (!pmt.CheckCRCAndParse())
return; return;
if (!PmtVersionChanged(pmtPid, pmt.getVersionNumber())) { if (!PmtVersionChanged(pmtPid, pmt.getTableIdExtension(), pmt.getVersionNumber())) {
lastPmtScan = 0; // this triggers the next scan lastPmtScan = 0; // this triggers the next scan
return; return;
} }

7
pat.h
View File

@ -4,13 +4,14 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: pat.h 1.3 2004/01/03 13:47:54 kls Exp $ * $Id: pat.h 1.4 2004/03/07 16:22:01 kls Exp $
*/ */
#ifndef __PAT_H #ifndef __PAT_H
#define __PAT_H #define __PAT_H
#include "filter.h" #include "filter.h"
#include <stdint.h>
#define MAXPMTENTRIES 64 #define MAXPMTENTRIES 64
@ -19,9 +20,9 @@ private:
time_t lastPmtScan; time_t lastPmtScan;
int pmtIndex; int pmtIndex;
int pmtPid; int pmtPid;
int pmtVersion[MAXPMTENTRIES]; uint64_t pmtVersion[MAXPMTENTRIES];
int numPmtEntries; int numPmtEntries;
bool PmtVersionChanged(int PmtPid, int Version); bool PmtVersionChanged(int PmtPid, int Sid, int Version);
protected: protected:
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
public: public:

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: recorder.c 1.8 2003/10/18 11:35:02 kls Exp $ * $Id: recorder.c 1.9 2004/03/07 14:39:25 kls Exp $
*/ */
#include <stdarg.h> #include <stdarg.h>
@ -102,7 +102,7 @@ void cRecorder::Receive(uchar *Data, int Length)
{ {
int p = ringBuffer->Put(Data, Length); int p = ringBuffer->Put(Data, Length);
if (p != Length && active) if (p != Length && active)
esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p); ringBuffer->ReportOverflow(Length - p);
} }
void cRecorder::Action(void) void cRecorder::Action(void)

View File

@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the * Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org). * LinuxDVB driver (see linuxtv.org).
* *
* $Id: ringbuffer.c 1.18 2003/10/12 14:25:09 kls Exp $ * $Id: ringbuffer.c 1.19 2004/03/07 13:46:51 kls Exp $
*/ */
#include "ringbuffer.h" #include "ringbuffer.h"
@ -17,6 +17,8 @@
// --- cRingBuffer ----------------------------------------------------------- // --- cRingBuffer -----------------------------------------------------------
#define OVERFLOWREPORTDELTA 5 // seconds between reports
cRingBuffer::cRingBuffer(int Size, bool Statistics) cRingBuffer::cRingBuffer(int Size, bool Statistics)
{ {
size = Size; size = Size;
@ -24,6 +26,8 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
maxFill = 0; maxFill = 0;
lastPercent = 0; lastPercent = 0;
putTimeout = getTimeout = 0; putTimeout = getTimeout = 0;
lastOverflowReport = 0;
overflowCount = overflowBytes = 0;
} }
cRingBuffer::~cRingBuffer() cRingBuffer::~cRingBuffer()
@ -68,6 +72,17 @@ void cRingBuffer::SetTimeouts(int PutTimeout, int GetTimeout)
getTimeout = GetTimeout; getTimeout = GetTimeout;
} }
void cRingBuffer::ReportOverflow(int Bytes)
{
overflowCount++;
overflowBytes += Bytes;
if (time(NULL) - lastOverflowReport > OVERFLOWREPORTDELTA) {
esyslog("ERROR: %d ring buffer overflow%s (%d bytes dropped)", overflowCount, overflowCount > 1 ? "s" : "", overflowBytes);
overflowCount = overflowBytes = 0;
lastOverflowReport = time(NULL);
}
}
// --- cRingBufferLinear ----------------------------------------------------- // --- cRingBufferLinear -----------------------------------------------------
cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics) cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics)

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: ringbuffer.h 1.13 2003/10/12 13:57:56 kls Exp $ * $Id: ringbuffer.h 1.14 2004/03/07 13:40:45 kls Exp $
*/ */
#ifndef __RINGBUFFER_H #ifndef __RINGBUFFER_H
@ -21,6 +21,9 @@ private:
int putTimeout; int putTimeout;
int getTimeout; int getTimeout;
int size; int size;
time_t lastOverflowReport;
int overflowCount;
int overflowBytes;
protected: protected:
int maxFill;//XXX int maxFill;//XXX
int lastPercent; int lastPercent;
@ -39,6 +42,7 @@ public:
cRingBuffer(int Size, bool Statistics = false); cRingBuffer(int Size, bool Statistics = false);
virtual ~cRingBuffer(); virtual ~cRingBuffer();
void SetTimeouts(int PutTimeout, int GetTimeout); void SetTimeouts(int PutTimeout, int GetTimeout);
void ReportOverflow(int Bytes);
}; };
class cRingBufferLinear : public cRingBuffer { class cRingBufferLinear : public cRingBuffer {

27
sdt.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: sdt.c 1.7 2004/01/17 17:27:49 kls Exp $ * $Id: sdt.c 1.8 2004/03/07 10:46:08 kls Exp $
*/ */
#include "sdt.h" #include "sdt.h"
@ -57,34 +57,17 @@ void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
//XXX TODO case 0x04: // NVOD reference service //XXX TODO case 0x04: // NVOD reference service
//XXX TODO case 0x05: // NVOD time-shifted service //XXX TODO case 0x05: // NVOD time-shifted service
{ {
char buffer[1024];
char *p = sd->serviceName.getText(buffer);
char NameBuf[1024]; char NameBuf[1024];
char ShortNameBuf[1024]; char ShortNameBuf[1024];
char *pn = NameBuf; sd->serviceName.getText(NameBuf, ShortNameBuf);
char *ps = ShortNameBuf; char *pn = compactspace(NameBuf);
int IsShortName = 0; char *ps = compactspace(ShortNameBuf);
while (*p) {
if ((uchar)*p == 0x86)
IsShortName++;
else if ((uchar)*p == 0x87)
IsShortName--;
else {
*pn++ = *p;
if (IsShortName)
*ps++ = *p;
}
p++;
}
*pn = *ps = 0;
pn = NameBuf;
if (*NameBuf && *ShortNameBuf && strcmp(NameBuf, ShortNameBuf) != 0) { if (*NameBuf && *ShortNameBuf && strcmp(NameBuf, ShortNameBuf) != 0) {
ps = ShortNameBuf + strlen(ShortNameBuf);
*ps++ = ','; *ps++ = ',';
strcpy(ps, NameBuf); strcpy(ps, NameBuf);
pn = ShortNameBuf; pn = ShortNameBuf;
} }
pn = compactspace(pn);
ps = compactspace(ps);
if (channel) { if (channel) {
channel->SetId(sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId()); channel->SetId(sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
if (Setup.UpdateChannels >= 1) if (Setup.UpdateChannels >= 1)

View File

@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured * and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection. * graphical interface that sits on top of an SVDRP connection.
* *
* $Id: svdrp.c 1.60 2004/02/22 15:31:23 kls Exp kls $ * $Id: svdrp.c 1.61 2004/02/24 12:24:43 kls Exp $
*/ */
#include "svdrp.h" #include "svdrp.h"

View File

@ -4,14 +4,13 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: timers.c 1.9 2004/02/13 15:37:49 kls Exp kls $ * $Id: timers.c 1.12 2004/03/14 13:27:57 kls Exp $
*/ */
#include "timers.h" #include "timers.h"
#include <ctype.h> #include <ctype.h>
#include "channels.h" #include "channels.h"
#include "i18n.h" #include "i18n.h"
#include "libsi/si.h"
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d' // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
// format characters in order to allow any number of blanks after a numeric // format characters in order to allow any number of blanks after a numeric
@ -333,8 +332,8 @@ bool cTimer::Matches(time_t t, bool Directly)
if (HasFlags(tfActive)) { if (HasFlags(tfActive)) {
if (HasFlags(tfVps) && !Directly && event && event->Vps()) { if (HasFlags(tfVps) && !Directly && event && event->Vps()) {
startTime = event->StartTime(); startTime = event->StartTime();
stopTime = startTime + event->Duration(); stopTime = event->EndTime();
return event->RunningStatus() > SI::RunningStatusNotRunning; return event->IsRunning(true);
} }
return startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers return startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers
} }
@ -350,9 +349,14 @@ int cTimer::Matches(const cEvent *Event)
bool m1 = Matches(t1, true); bool m1 = Matches(t1, true);
bool m2 = UseVps ? m1 : Matches(t2, true); bool m2 = UseVps ? m1 : Matches(t2, true);
startTime = stopTime = 0; startTime = stopTime = 0;
if (m1 && m2) if (m1 && m2) {
if (UseVps && Event->IsRunning(true))
return tmFull; return tmFull;
if (m1 || m2) if (time(NULL) > Event->EndTime())
return tmNone;
return tmFull;
}
if ((m1 || m2) && time(NULL) <= Event->EndTime())
return tmPartial; return tmPartial;
} }
return tmNone; return tmNone;
@ -381,6 +385,8 @@ void cTimer::SetEvent(const cEvent *Event)
sprintf(vpsbuf, "(VPS: %s) ", Event->GetVpsString()); sprintf(vpsbuf, "(VPS: %s) ", Event->GetVpsString());
isyslog("timer %d (%d %04d-%04d '%s') set to event %s %s-%s %s'%s'", Index() + 1, Channel()->Number(), start, stop, file, Event->GetDateString(), Event->GetTimeString(), Event->GetEndTimeString(), vpsbuf, Event->Title()); isyslog("timer %d (%d %04d-%04d '%s') set to event %s %s-%s %s'%s'", Index() + 1, Channel()->Number(), start, stop, file, Event->GetDateString(), Event->GetTimeString(), Event->GetEndTimeString(), vpsbuf, Event->Title());
} }
else
isyslog("timer %d (%d %04d-%04d '%s') set to no event", Index() + 1, Channel()->Number(), start, stop, file);
event = Event; event = Event;
} }
} }
@ -500,7 +506,7 @@ cTimer *cTimers::GetNextActiveTimer(void)
void cTimers::SetEvents(void) void cTimers::SetEvents(void)
{ {
cSchedulesLock SchedulesLock; cSchedulesLock SchedulesLock(false, 100);
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock); const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
if (Schedules) { if (Schedules) {
for (cTimer *ti = First(); ti; ti = Next(ti)) { for (cTimer *ti = First(); ti; ti = Next(ti)) {
@ -508,10 +514,8 @@ void cTimers::SetEvents(void)
const cEvent *Event = NULL; const cEvent *Event = NULL;
if (Schedule) { if (Schedule) {
//XXX what if the Schedule doesn't have any VPS??? //XXX what if the Schedule doesn't have any VPS???
const cEvent *e;
int Match = tmNone; int Match = tmNone;
int i = 0; for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) {
while ((e = Schedule->GetEventNumber(i++)) != NULL) {
int m = ti->Matches(e); int m = ti->Matches(e);
if (m > Match) { if (m > Match) {
Match = m; Match = m;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: timers.h 1.6 2003/12/13 13:04:21 kls Exp kls $ * $Id: timers.h 1.7 2004/02/29 14:18:17 kls Exp $
*/ */
#ifndef __TIMERS_H #ifndef __TIMERS_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: transfer.c 1.15 2003/10/18 11:36:03 kls Exp $ * $Id: transfer.c 1.16 2004/03/07 14:40:15 kls Exp $
*/ */
#include "transfer.h" #include "transfer.h"
@ -55,7 +55,7 @@ void cTransfer::Receive(uchar *Data, int Length)
int i = 0; int i = 0;
while (active && Length > 0) { while (active && Length > 0) {
if (i++ > 10) { if (i++ > 10) {
esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length); ringBuffer->ReportOverflow(Length);
break; break;
} }
int p = ringBuffer->Put(Data, Length); int p = ringBuffer->Put(Data, Length);

2
vdr.5
View File

@ -8,7 +8,7 @@
.\" License as specified in the file COPYING that comes with the .\" License as specified in the file COPYING that comes with the
.\" vdr distribution. .\" vdr distribution.
.\" .\"
.\" $Id: vdr.5 1.25 2004/02/22 13:18:48 kls Exp kls $ .\" $Id: vdr.5 1.26 2004/02/24 12:36:35 kls Exp $
.\" .\"
.TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files" .TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files"
.SH NAME .SH NAME

10
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/vdr * The project's page is at http://www.cadsoft.de/vdr
* *
* $Id: vdr.c 1.177 2004/02/15 14:29:30 kls Exp kls $ * $Id: vdr.c 1.180 2004/03/14 14:25:02 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -549,11 +549,14 @@ int main(int argc, char *argv[])
PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel; PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
// Timers and Recordings: // Timers and Recordings:
if (!Timers.BeingEdited()) { if (!Timers.BeingEdited()) {
// Assign events to timers:
if (time(NULL) - LastActivity > 10) {
static time_t LastSetEvents = 0;//XXX trigger by actual EPG data modification??? static time_t LastSetEvents = 0;//XXX trigger by actual EPG data modification???
if (!Menu && time(NULL) - LastSetEvents > 5) { if (time(NULL) - LastSetEvents > 5) {
Timers.SetEvents(); Timers.SetEvents();
LastSetEvents = time(NULL); LastSetEvents = time(NULL);
} }
}
time_t Now = time(NULL); // must do all following calls with the exact same time! time_t Now = time(NULL); // must do all following calls with the exact same time!
// Process ongoing recordings: // Process ongoing recordings:
cRecordControls::Process(Now); cRecordControls::Process(Now);
@ -571,7 +574,6 @@ int main(int argc, char *argv[])
if (Timer->HasFlags(tfActive | tfVps) && !Timer->Recording() && !Timer->Pending() && Timer->Matches(Now + Setup.VpsMargin, true)) { if (Timer->HasFlags(tfActive | tfVps) && !Timer->Recording() && !Timer->Pending() && Timer->Matches(Now + Setup.VpsMargin, true)) {
if (!Timer->InVpsMargin()) { if (!Timer->InVpsMargin()) {
Timer->SetInVpsMargin(true); Timer->SetInVpsMargin(true);
TimerInVpsMargin = true;
//XXX if not primary device has TP??? //XXX if not primary device has TP???
LastTimerChannel = Timer->Channel()->Number(); LastTimerChannel = Timer->Channel()->Number();
cRecordControls::Start(Timer); // will only switch the device cRecordControls::Start(Timer); // will only switch the device
@ -579,6 +581,8 @@ int main(int argc, char *argv[])
} }
else else
Timer->SetInVpsMargin(false); Timer->SetInVpsMargin(false);
if (Timer->InVpsMargin())
TimerInVpsMargin = true;
} }
} }
// CAM control: // CAM control: