summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY45
-rw-r--r--channels.c106
-rw-r--r--channels.h18
-rw-r--r--device.c4
-rw-r--r--dvbdevice.c6
-rw-r--r--eit.c128
-rw-r--r--eit.h31
-rw-r--r--i18n.c18
-rw-r--r--menu.c93
-rw-r--r--osd.c22
-rw-r--r--osd.h3
-rw-r--r--remote.h4
-rw-r--r--svdrp.c43
-rw-r--r--timers.c53
-rw-r--r--timers.h5
-rw-r--r--tools.c9
-rw-r--r--tools.h4
-rw-r--r--vdr.530
18 files changed, 394 insertions, 228 deletions
diff --git a/HISTORY b/HISTORY
index 2d8c272f..07741159 100644
--- a/HISTORY
+++ b/HISTORY
@@ -249,7 +249,7 @@ Video Disk Recorder Revision History
- The EIT information is now gathered in a separate thread.
- The sytem time can now be synchronized to the time broadcast in the DVB data
stream. This can be enabled in the "Setup" menu by setting "SetSystemTime" to
- 1. Note that this works only if VDR is running under a user id that has
+ 1. Note that this works only if VDR is running under a user ID that has
permisson to set the system time.
- The new item "Schedule" in the "Main" menu opens VDR's EPG (thanks to Robert
Schneider). See the MANUAL file for a detailed description.
@@ -1722,9 +1722,46 @@ Video Disk Recorder Revision History
which can be used to disable simultaneous recording and replaying on the primary
DVB device in case there are problems with this.
-2002-11-08: Version 1.1.16
+2002-11-10: Version 1.1.16
- Fixed saving the polarization parameter of channels that have a number in the
'source' parameter (thanks to Peter Seyringer for reporting this one).
-- Updated channels.conf.terr (thanks to Andy Carter).
-- Updated channels.conf.cable (thanks to Achim Lange).
+- Updated 'channels.conf.terr' (thanks to Andy Carter).
+- Updated 'channels.conf.cable' (thanks to Achim Lange).
+- First step towards a "unique channel ID". The channel ID is a human readable
+ string, made up from several parameters of the channel's definition in the file
+ 'channels.conf' (see man vdr(5) for details).
+ In order for the "unique channel ID" to work, all channel definitions now must
+ be unique with respect to the combination of their Source, Frequency and SID
+ parameters. You may have to fix your 'channels.conf' manually if there are error
+ messages in the log file when loading it. BE SURE TO MAKE A BACKUP COPY OF YOUR
+ 'channels.conf' AND 'timers.conf' FILE BEFORE SWITCHING TO THIS VERSION, AND CHECK
+ VERY CAREFULLY WHETHER YOUR TIMERS ARE STILL SET TO THE RIGHT CHANNELS!
+ When reading an existing 'timers.conf', the channels will be identified as before
+ by their numbers. As soon as this file is written back, the channel numbers will
+ be replaced by the channel IDs. After that it is possible to manually edit the
+ 'channels.conf' file and rearrange the channels without breaking the timers.
+ Note that you can still define new timers manually by using the channel number.
+ VDR will correctly identify the 'channel' parameter in a timer definition and
+ use it as a channel number or a channel ID, respectively. Also, the SVDRP commands
+ that return timer definitions will list them with channel numbers in order to
+ stay compatible with existing applications.
+ The channel ID is also used in the 'epg.data' file to allow EPG information from
+ different sources to be stored, which would previously have been mixed up in case
+ they were using the same 'service ID'. Note that the contents of an existing
+ 'epg.data' file from a previous version will be silently ignored, since it doesn't
+ contain the new channel IDs. When inserting EPG data into VDR via SVDRP you now also
+ need to use the channel IDs.
+ Currently the EPG data received from the DVB data stream only uses the 'Source'
+ and 'Service ID' part of the channel ID. This makes it work for channels with
+ the same service IDs on different sources (like satellites, cable or terrestrial).
+ However, it doesn't work yet if the service IDs are not unique within a specific
+ source. This will be fixed later.
+- Added missing SID parameters to 'channels.conf'. Some channels have been removed
+ since they are apparently no longer broadcasted.
+- Removed dropping EPG events from "other" streams that have a duration of 86400
+ seconds or more (was introduced in version 1.1.10). This has become obsolete by
+ the modification in version 1.1.13, which fixed fetching the current/next information
+ to handle cases where the duration of an event is set wrongly and would last beyond
+ the start time of the next event. Besides, the change in 1.1.10 broke handling EPG
+ data for NVOD channels.
diff --git a/channels.c b/channels.c
index e9fe3de6..cb05e2ca 100644
--- a/channels.c
+++ b/channels.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: channels.c 1.7 2002/11/08 13:21:16 kls Exp $
+ * $Id: channels.c 1.8 2002/11/10 13:01:55 kls Exp $
*/
#include "channels.h"
@@ -126,19 +126,18 @@ char *cChannel::buffer = NULL;
cChannel::cChannel(void)
{
- *name = 0;
- frequency = 0;
+ strcpy(name, "Pro7");
+ frequency = 12480;
source = cSource::FromString("S19.2E");
- srate = 0;
- vpid = 0;
- apid1 = 0;
+ srate = 27500;
+ vpid = 255;
+ apid1 = 256;
apid2 = 0;
- dpid1 = 0;
+ dpid1 = 257;
dpid2 = 0;
- tpid = 0;
+ tpid = 32;
ca = 0;
sid = 0;
- number = 0;
groupSep = false;
polarization = 'v';
inversion = INVERSION_AUTO;
@@ -151,30 +150,44 @@ cChannel::cChannel(void)
hierarchy = HIERARCHY_AUTO;
}
-cChannel::cChannel(const cChannel *Channel)
+cChannel& cChannel::operator= (const cChannel &Channel)
{
- strcpy(name, Channel ? Channel->name : "Pro7");
- frequency = Channel ? Channel->frequency : 12480;
- source = Channel ? Channel->source : cSource::FromString("S19.2E");
- srate = Channel ? Channel->srate : 27500;
- vpid = Channel ? Channel->vpid : 255;
- apid1 = Channel ? Channel->apid1 : 256;
- apid2 = Channel ? Channel->apid2 : 0;
- dpid1 = Channel ? Channel->dpid1 : 257;
- dpid2 = Channel ? Channel->dpid2 : 0;
- tpid = Channel ? Channel->tpid : 32;
- ca = Channel ? Channel->ca : 0;
- sid = Channel ? Channel->sid : 0;
- groupSep = Channel ? Channel->groupSep : false;
- polarization = Channel ? Channel->polarization : 'v';
- inversion = Channel ? Channel->inversion : INVERSION_AUTO;
- bandwidth = Channel ? Channel->bandwidth : BANDWIDTH_AUTO;
- coderateH = Channel ? Channel->coderateH : FEC_AUTO;
- coderateL = Channel ? Channel->coderateL : FEC_AUTO;
- modulation = Channel ? Channel->modulation : QAM_AUTO;
- transmission = Channel ? Channel->transmission : TRANSMISSION_MODE_AUTO;
- guard = Channel ? Channel->guard : GUARD_INTERVAL_AUTO;
- hierarchy = Channel ? Channel->hierarchy : HIERARCHY_AUTO;
+ memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__);
+ return *this;
+}
+
+static int MHz(int frequency)
+{
+ while (frequency > 20000) {
+ frequency /= 1000;
+ }
+ return frequency;
+}
+
+uint64 cChannel::GetChannelID(void) const
+{
+ return (uint64(source) << 48) | (uint64(0) << 32) | ((MHz(frequency)) << 16) | sid;
+}
+
+const char *cChannel::GetChannelIDStr(void) const
+{
+ static char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%s-%d-%d-%d", cSource::ToString(source), 0, MHz(frequency), sid);
+ return buffer;
+}
+
+uint64 cChannel::StringToChannelID(const char *s)
+{
+ char *sourcebuf = NULL;
+ int reserved;
+ int frequency;
+ int sid;
+ if (4 == sscanf(s, "%a[^-]-%d-%d-%d", &sourcebuf, &reserved, &frequency, &sid)) {
+ int source = cSource::FromString(sourcebuf);
+ if (source >= 0)
+ return (uint64(source) << 48) | (uint64(reserved) << 32) | (frequency << 16) | sid;
+ }
+ return 0;
}
static int PrintParameter(char *p, char Name, int Value)
@@ -278,7 +291,7 @@ const char *cChannel::ToText(void)
return ToText(this);
}
-bool cChannel::Parse(const char *s)
+bool cChannel::Parse(const char *s, bool AllowNonUniqueID)
{
if (*s == ':') {
groupSep = true;
@@ -324,6 +337,10 @@ bool cChannel::Parse(const char *s)
free(sourcebuf);
free(apidbuf);
free(namebuf);
+ if (!AllowNonUniqueID && Channels.GetByChannelID(GetChannelID())) {
+ esyslog("ERROR: channel data not unique!");
+ return false;
+ }
return ok;
}
else
@@ -404,15 +421,34 @@ cChannel *cChannels::GetByNumber(int Number, int SkipGap)
return NULL;
}
-cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
+cChannel *cChannels::GetByServiceID(int Source, unsigned short ServiceID)
+{
+ for (cChannel *channel = First(); channel; channel = Next(channel)) {
+ if (!channel->GroupSep() && channel->Source() == Source && channel->Sid() == ServiceID)
+ return channel;
+ }
+ return NULL;
+}
+
+cChannel *cChannels::GetByChannelID(uint64 ChannelID)
{
for (cChannel *channel = First(); channel; channel = Next(channel)) {
- if (!channel->GroupSep() && channel->Sid() == ServiceId)
+ if (!channel->GroupSep() && channel->GetChannelID() == ChannelID)
return channel;
}
return NULL;
}
+bool cChannels::HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel)
+{
+ uint64 NewChannelID = NewChannel->GetChannelID();
+ for (cChannel *channel = First(); channel; channel = Next(channel)) {
+ if (!channel->GroupSep() && channel != OldChannel && channel->GetChannelID() == NewChannelID)
+ return false;
+ }
+ return true;
+}
+
bool cChannels::SwitchTo(int Number)
{
cChannel *channel = GetByNumber(Number);
diff --git a/channels.h b/channels.h
index 7eb818c3..52e79b4d 100644
--- a/channels.h
+++ b/channels.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: channels.h 1.3 2002/10/20 11:50:36 kls Exp $
+ * $Id: channels.h 1.4 2002/11/10 13:01:23 kls Exp $
*/
#ifndef __CHANNELS_H
@@ -41,6 +41,7 @@ private:
static char *buffer;
static const char *ToText(cChannel *Channel);
enum { MaxChannelName = 32 }; // 31 chars + terminating 0!
+ int __BeginData__;
char name[MaxChannelName];
int frequency; // MHz
int source;
@@ -53,7 +54,6 @@ private:
int sid;
int number; // Sequence number assigned on load
bool groupSep;
- //XXX
char polarization;
int inversion;
int bandwidth;
@@ -63,13 +63,14 @@ private:
int transmission;
int guard;
int hierarchy;
+ int __EndData__;
const char *ParametersToString(void);
bool StringToParameters(const char *s);
public:
cChannel(void);
- cChannel(const cChannel *Channel);
+ cChannel& operator= (const cChannel &Channel);
const char *ToText(void);
- bool Parse(const char *s);
+ bool Parse(const char *s, bool AllowNonUniqueID = false);
bool Save(FILE *f);
const char *Name(void) const { return name; }
int Frequency(void) const { return frequency; }
@@ -86,7 +87,6 @@ public:
int Number(void) const { return number; }
void SetNumber(int Number) { number = Number; }
bool GroupSep(void) const { return groupSep; }
- //XXX
char Polarization(void) const { return polarization; }
int Inversion(void) const { return inversion; }
int Bandwidth(void) const { return bandwidth; }
@@ -96,10 +96,12 @@ public:
int Transmission(void) const { return transmission; }
int Guard(void) const { return guard; }
int Hierarchy(void) const { return hierarchy; }
- //XXX
bool IsCable(void) { return (source & cSource::st_Mask) == cSource::stCable; }
bool IsSat(void) { return (source & cSource::st_Mask) == cSource::stSat; }
bool IsTerr(void) { return (source & cSource::st_Mask) == cSource::stTerr; }
+ uint64 GetChannelID(void) const;
+ const char *GetChannelIDStr(void) const;
+ static uint64 StringToChannelID(const char *s);
};
class cChannels : public cConfig<cChannel> {
@@ -113,7 +115,9 @@ public:
int GetNextNormal(int Idx); // Get next normal channel (not group)
void ReNumber(void); // Recalculate 'number' based on channel type
cChannel *GetByNumber(int Number, int SkipGap = 0);
- cChannel *GetByServiceID(unsigned short ServiceId);
+ cChannel *GetByServiceID(int Source, unsigned short ServiceID);
+ cChannel *GetByChannelID(uint64 ChannelID);
+ bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel = NULL);
bool SwitchTo(int Number);
int MaxNumber(void) { return maxNumber; }
};
diff --git a/device.c b/device.c
index 69178a9e..edbf5cae 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 1.34 2002/11/03 11:51:24 kls Exp $
+ * $Id: device.c 1.35 2002/11/10 10:17:57 kls Exp $
*/
#include "device.h"
@@ -379,7 +379,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
if (Result == scrOk) {
if (LiveView && IsPrimaryDevice()) {
- cSIProcessor::SetCurrentServiceID(Channel->Sid());
+ cSIProcessor::SetCurrentChannelID(Channel->GetChannelID());
currentChannel = Channel->Number();
}
cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull
diff --git a/dvbdevice.c b/dvbdevice.c
index 30d56586..119a28e6 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 1.34 2002/11/03 12:31:11 kls Exp $
+ * $Id: dvbdevice.c 1.35 2002/11/10 12:57:17 kls Exp $
*/
#include "dvbdevice.h"
@@ -412,7 +412,7 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
// Stop setting system time:
if (siProcessor)
- siProcessor->SetCurrentTransponder(0);
+ siProcessor->SetCurrentTransponder(0, 0);
// Turn off live PIDs if necessary:
@@ -585,7 +585,7 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
// Start setting system time:
if (siProcessor)
- siProcessor->SetCurrentTransponder(Channel->Frequency());
+ siProcessor->SetCurrentTransponder(Channel->Source(), Channel->Frequency());
return true;
}
diff --git a/eit.c b/eit.c
index 12045d63..f8b436c0 100644
--- a/eit.c
+++ b/eit.c
@@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.c 1.59 2002/11/02 12:46:53 kls Exp $
+ * $Id: eit.c 1.60 2002/11/10 15:50:21 kls Exp $
***************************************************************************/
#include "eit.h"
@@ -180,7 +180,7 @@ bool cTDT::SetSystemTime()
// --- cEventInfo ------------------------------------------------------------
-cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid)
+cEventInfo::cEventInfo(uint64 channelid, unsigned short eventid)
{
pTitle = NULL;
pSubtitle = NULL;
@@ -190,7 +190,7 @@ cEventInfo::cEventInfo(unsigned short serviceid, unsigned short eventid)
tTime = 0;
uTableID = 0;
uEventID = eventid;
- uServiceID = serviceid;
+ uChannelID = channelid;
nChannelNumber = 0;
}
@@ -325,15 +325,15 @@ void cEventInfo::SetEventID(unsigned short evid)
uEventID = evid;
}
/** */
-void cEventInfo::SetServiceID(unsigned short servid)
+void cEventInfo::SetChannelID(uint64 channelid)
{
- uServiceID = servid;
+ uChannelID = channelid;
}
/** */
-unsigned short cEventInfo::GetServiceID() const
+uint64 cEventInfo::GetChannelID() const
{
- return uServiceID;
+ return uChannelID;
}
/** */
@@ -368,7 +368,7 @@ bool cEventInfo::Read(FILE *f, cSchedule *Schedule)
if (n == 3 || n == 4) {
pEvent = (cEventInfo *)Schedule->GetEvent(uEventID, tTime);
if (!pEvent)
- pEvent = Schedule->AddEvent(new cEventInfo(Schedule->GetServiceID(), uEventID));
+ pEvent = Schedule->AddEvent(new cEventInfo(Schedule->GetChannelID(), uEventID));
if (pEvent) {
pEvent->SetTableID(uTableID);
pEvent->SetTime(tTime);
@@ -404,24 +404,24 @@ bool cEventInfo::Read(FILE *f, cSchedule *Schedule)
struct tEpgBugFixStats {
int hits;
int n;
- unsigned short serviceIDs[MAXEPGBUGFIXCHANS];
+ uint64 channelIDs[MAXEPGBUGFIXCHANS];
tEpgBugFixStats(void) { hits = n = 0; }
};
tEpgBugFixStats EpgBugFixStats[MAXEPGBUGFIXSTATS];
-static void EpgBugFixStat(int Number, unsigned int ServiceID)
+static void EpgBugFixStat(int Number, uint64 ChannelID)
{
if (0 <= Number && Number < MAXEPGBUGFIXSTATS) {
tEpgBugFixStats *p = &EpgBugFixStats[Number];
p->hits++;
int i = 0;
for (; i < p->n; i++) {
- if (p->serviceIDs[i] == ServiceID)
+ if (p->channelIDs[i] == ChannelID)
break;
}
if (i == p->n && p->n < MAXEPGBUGFIXCHANS)
- p->serviceIDs[p->n++] = ServiceID;
+ p->channelIDs[p->n++] = ChannelID;
}
}
@@ -448,7 +448,7 @@ static void ReportEpgBugFixStats(bool Reset = false)
char *q = buffer;
q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits);
for (int c = 0; c < p->n; c++) {
- cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]);
+ cChannel *channel = Channels.GetByChannelID(p->channelIDs[c]);
if (channel) {
q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->Name());
delim = ", ";
@@ -499,7 +499,7 @@ void cEventInfo::FixEpgBugs(void)
char *s = e ? strdup(e) : NULL;
free(pSubtitle);
pSubtitle = s;
- EpgBugFixStat(0, GetServiceID());
+ EpgBugFixStat(0, GetChannelID());
// now the fixes #1 and #2 below will handle the rest
}
}
@@ -524,7 +524,7 @@ void cEventInfo::FixEpgBugs(void)
free(pExtendedDescription);
pSubtitle = s;
pExtendedDescription = d;
- EpgBugFixStat(1, GetServiceID());
+ EpgBugFixStat(1, GetChannelID());
}
}
}
@@ -541,7 +541,7 @@ void cEventInfo::FixEpgBugs(void)
memmove(pSubtitle, pSubtitle + 1, strlen(pSubtitle));
pExtendedDescription = pSubtitle;
pSubtitle = NULL;
- EpgBugFixStat(2, GetServiceID());
+ EpgBugFixStat(2, GetChannelID());
}
}
@@ -553,7 +553,7 @@ void cEventInfo::FixEpgBugs(void)
if (pSubtitle && strcmp(pTitle, pSubtitle) == 0) {
free(pSubtitle);
pSubtitle = NULL;
- EpgBugFixStat(3, GetServiceID());
+ EpgBugFixStat(3, GetChannelID());
}
// ZDF.info puts the Subtitle between double quotes, which is nothing
@@ -569,7 +569,7 @@ void cEventInfo::FixEpgBugs(void)
char *p = strrchr(pSubtitle, '"');
if (p)
*p = 0;
- EpgBugFixStat(4, GetServiceID());
+ EpgBugFixStat(4, GetChannelID());
}
}
@@ -590,7 +590,7 @@ void cEventInfo::FixEpgBugs(void)
if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) {
if (!startswith(p + 2, "und ")) { // special case in German, as in "Lach- und Sachgeschichten"
memmove(p, p + 2, strlen(p + 2) + 1);
- EpgBugFixStat(5, GetServiceID());
+ EpgBugFixStat(5, GetChannelID());
}
}
p++;
@@ -608,10 +608,10 @@ void cEventInfo::FixEpgBugs(void)
// --- cSchedule -------------------------------------------------------------
-cSchedule::cSchedule(unsigned short servid)
+cSchedule::cSchedule(uint64 channelid)
{
pPresent = pFollowing = NULL;
- uServiceID = servid;
+ uChannelID = channelid;
}
@@ -645,14 +645,14 @@ const cEventInfo *cSchedule::GetFollowingEvent(void) const
return pe;
}
-void cSchedule::SetServiceID(unsigned short servid)
+void cSchedule::SetChannelID(uint64 channelid)
{
- uServiceID = servid;
+ uChannelID = channelid;
}
/** */
-unsigned short cSchedule::GetServiceID() const
+uint64 cSchedule::GetChannelID() const
{
- return uServiceID;
+ return uChannelID;
}
/** */
const cEventInfo * cSchedule::GetEvent(unsigned short uEventID, time_t tTime) const
@@ -735,10 +735,10 @@ void cSchedule::Cleanup(time_t tTime)
/** */
void cSchedule::Dump(FILE *f, const char *Prefix) const
{
- cChannel *channel = Channels.GetByServiceID(uServiceID);
+ cChannel *channel = Channels.GetByChannelID(uChannelID);
if (channel)
{
- fprintf(f, "%sC %u %s\n", Prefix, uServiceID, channel->Name());
+ fprintf(f, "%sC %s %s\n", Prefix, channel->GetChannelIDStr(), channel->Name());
for (cEventInfo *p = Events.First(); p; p = Events.Next(p))
p->Dump(f, Prefix);
fprintf(f, "%sc\n", Prefix);
@@ -751,12 +751,22 @@ bool cSchedule::Read(FILE *f, cSchedules *Schedules)
char *s;
while ((s = readline(f)) != NULL) {
if (*s == 'C') {
- unsigned int uServiceID;
- if (1 == sscanf(s + 1, "%u", &uServiceID)) {
- cSchedule *p = (cSchedule *)Schedules->AddServiceID(uServiceID);
- if (p) {
- if (!cEventInfo::Read(f, p))
- return false;
+ s = skipspace(s + 1);
+ char *p = strchr(s, ' ');
+ if (p)
+ *p = 0; // strips optional channel name
+ if (*s) {
+ uint64 uChannelID = cChannel::StringToChannelID(s);
+ if (uChannelID) {
+ cSchedule *p = (cSchedule *)Schedules->AddChannelID(uChannelID);
+ if (p) {
+ if (!cEventInfo::Read(f, p))
+ return false;
+ }
+ }
+ else {
+ esyslog("ERROR: illegal channel ID: %s", s);
+ return false;
}
}
}
@@ -775,28 +785,28 @@ bool cSchedule::Read(FILE *f, cSchedules *Schedules)
cSchedules::cSchedules()
{
pCurrentSchedule = NULL;
- uCurrentServiceID = 0;
+ uCurrentChannelID = 0;
}
cSchedules::~cSchedules()
{
}
/** */
-const cSchedule *cSchedules::AddServiceID(unsigned short servid)
+const cSchedule *cSchedules::AddChannelID(uint64 channelid)
{
- const cSchedule *p = GetSchedule(servid);
+ const cSchedule *p = GetSchedule(channelid);
if (!p) {
- Add(new cSchedule(servid));
- p = GetSchedule(servid);
+ Add(new cSchedule(channelid));
+ p = GetSchedule(channelid);
}
return p;
}
/** */
-const cSchedule *cSchedules::SetCurrentServiceID(unsigned short servid)
+const cSchedule *cSchedules::SetCurrentChannelID(uint64 channelid)
{
- pCurrentSchedule = AddServiceID(servid);
+ pCurrentSchedule = AddChannelID(channelid);
if (pCurrentSchedule)
- uCurrentServiceID = servid;
+ uCurrentChannelID = channelid;
return pCurrentSchedule;
}
/** */
@@ -805,14 +815,14 @@ const cSchedule * cSchedules::GetSchedule() const
return pCurrentSchedule;
}
/** */
-const cSchedule * cSchedules::GetSchedule(unsigned short servid) const
+const cSchedule * cSchedules::GetSchedule(uint64 channelid) const
{
cSchedule *p;
p = First();
while (p != NULL)
{
- if (p->GetServiceID() == servid)
+ if (p->GetChannelID() == channelid)
return p;
p = Next(p);
}
@@ -856,7 +866,7 @@ public:
cEIT(unsigned char *buf, int length, cSchedules *Schedules);
~cEIT();
/** */
- int ProcessEIT(unsigned char *buffer);
+ int ProcessEIT(unsigned char *buffer, int CurrentSource);
protected: // Protected methods
/** returns true if this EIT covers a
@@ -879,7 +889,7 @@ cEIT::~cEIT()
}
/** */
-int cEIT::ProcessEIT(unsigned char *buffer)
+int cEIT::ProcessEIT(unsigned char *buffer, int CurrentSource)
{
cEventInfo *pEvent, *rEvent = NULL;
cSchedule *pSchedule, *rSchedule = NULL;
@@ -893,18 +903,19 @@ int cEIT::ProcessEIT(unsigned char *buffer)
if (VdrProgramInfos) {
for (VdrProgramInfo = (struct VdrProgramInfo *) VdrProgramInfos->Head; VdrProgramInfo; VdrProgramInfo = (struct VdrProgramInfo *) xSucc (VdrProgramInfo)) {
- // Drop events that belong to an "other TS" and are very long (some stations broadcast bogus data for "other" channels):
- if (VdrProgramInfo->Duration >= 86400 && (tid == 0x4F || tid == 0x60 || tid == 0x61))
- continue;
- pSchedule = (cSchedule *)schedules->GetSchedule(VdrProgramInfo->ServiceID);
+ //XXX TODO use complete channel ID
+ cChannel *channel = Channels.GetByServiceID(CurrentSource, VdrProgramInfo->ServiceID);
+ uint64 channelID = channel ? channel->GetChannelID() : (uint64(CurrentSource) << 48) | VdrProgramInfo->ServiceID;
+ //XXX
+ pSchedule = (cSchedule *)schedules->GetSchedule(channelID);
if (!pSchedule) {
- schedules->Add(new cSchedule(VdrProgramInfo->ServiceID));
- pSchedule = (cSchedule *)schedules->GetSchedule(VdrProgramInfo->ServiceID);
+ schedules->Add(new cSchedule(channelID));
+ pSchedule = (cSchedule *)schedules->GetSchedule(channelID);
if (!pSchedule)
break;
}
if (VdrProgramInfo->ReferenceServiceID) {
- rSchedule = (cSchedule *)schedules->GetSchedule(VdrProgramInfo->ReferenceServiceID);
+ rSchedule = (cSchedule *)schedules->GetSchedule((uint64(CurrentSource) << 48) | VdrProgramInfo->ReferenceServiceID);
if (!rSchedule)
break;
rEvent = (cEventInfo *)rSchedule->GetEvent((unsigned short)VdrProgramInfo->ReferenceEventID);
@@ -915,7 +926,7 @@ int cEIT::ProcessEIT(unsigned char *buffer)
if (!pEvent) {
// If we don't have that event ID yet, we create a new one.
// Otherwise we copy the information into the existing event anyway, because the data might have changed.
- pEvent = pSchedule->AddEvent(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID));
+ pEvent = pSchedule->AddEvent(new cEventInfo(channelID, VdrProgramInfo->EventID));
if (!pEvent)
break;
pEvent->SetTableID(tid);
@@ -988,6 +999,8 @@ cSIProcessor::cSIProcessor(const char *FileName)
{
fileName = strdup(FileName);
masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master'
+ currentSource = 0;
+ currentTransponder = 0;
filters = NULL;
if (!numSIProcessors++) // the first one creates it
schedules = new cSchedules;
@@ -1167,7 +1180,7 @@ void cSIProcessor::Action()
{
cMutexLock MutexLock(&schedulesMutex);
cEIT ceit(buf, seclen, schedules);
- ceit.ProcessEIT(buf);
+ ceit.ProcessEIT(buf, currentSource);
}
else
dsyslog("Received stuffing section in EIT\n");
@@ -1250,16 +1263,17 @@ bool cSIProcessor::ShutDownFilters(void)
}
/** */
-void cSIProcessor::SetCurrentTransponder(int CurrentTransponder)
+void cSIProcessor::SetCurrentTransponder(int CurrentSource, int CurrentTransponder)
{
+ currentSource = CurrentSource;
currentTransponder = CurrentTransponder;
}
/** */
-bool cSIProcessor::SetCurrentServiceID(unsigned short servid)
+bool cSIProcessor::SetCurrentChannelID(uint64 channelid)
{
cMutexLock MutexLock(&schedulesMutex);
- return schedules ? schedules->SetCurrentServiceID(servid) : false;
+ return schedules ? schedules->SetCurrentChannelID(channelid) : false;
}
void cSIProcessor::TriggerDump(void)
diff --git a/eit.h b/eit.h
index 53740032..d906725e 100644
--- a/eit.h
+++ b/eit.h
@@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.h 1.20 2002/11/02 12:36:36 kls Exp $
+ * $Id: eit.h 1.21 2002/11/10 12:58:27 kls Exp $
***************************************************************************/
#ifndef __EIT_H
@@ -32,7 +32,7 @@ class cEventInfo : public cListObject {
friend class cEIT;
private:
unsigned char uTableID; // Table ID this event came from
- unsigned short uServiceID; // Service ID of program for that event
+ uint64 uChannelID; // Channel ID of program for that event
bool bIsFollowing; // true if this is the next event on this channel
bool bIsPresent; // true if this is the present event running
char *pExtendedDescription; // Extended description of this event
@@ -47,13 +47,13 @@ protected:
void SetFollowing(bool foll);
void SetPresent(bool pres);
void SetTitle(const char *string);
- void SetServiceID(unsigned short servid);
+ void SetChannelID(uint64 channelid);
void SetEventID(unsigned short evid);
void SetDuration(long l);
void SetTime(time_t t);
void SetExtendedDescription(const char *string);
void SetSubtitle(const char *string);
- cEventInfo(unsigned short serviceid, unsigned short eventid);
+ cEventInfo(uint64 channelid, unsigned short eventid);
public:
~cEventInfo();
const unsigned char GetTableID(void) const;
@@ -68,7 +68,7 @@ public:
unsigned short GetEventID(void) const;
long GetDuration(void) const;
time_t GetTime(void) const;
- unsigned short GetServiceID(void) const;
+ uint64 GetChannelID(void) const;
int GetChannelNumber(void) const { return nChannelNumber; }
void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
void Dump(FILE *f, const char *Prefix = "") const;
@@ -82,21 +82,21 @@ class cSchedule : public cListObject {
private:
cEventInfo *pPresent;
cEventInfo *pFollowing;
- unsigned short uServiceID;
+ uint64 uChannelID;
cList<cEventInfo> Events;
protected:
- void SetServiceID(unsigned short servid);
+ void SetChannelID(uint64 channelid);
bool SetFollowingEvent(cEventInfo *pEvent);
bool SetPresentEvent(cEventInfo *pEvent);
void Cleanup(time_t tTime);
void Cleanup(void);
- cSchedule(unsigned short servid = 0);
+ cSchedule(uint64 channelid = 0);
public:
~cSchedule();
cEventInfo *AddEvent(cEventInfo *EventInfo);
const cEventInfo *GetPresentEvent(void) const;
const cEventInfo *GetFollowingEvent(void) const;
- unsigned short GetServiceID(void) const;
+ uint64 GetChannelID(void) const;
const cEventInfo *GetEvent(unsigned short uEventID, time_t tTime = 0) const;
const cEventInfo *GetEventAround(time_t tTime) const;
const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
@@ -110,15 +110,15 @@ class cSchedules : public cList<cSchedule> {
friend class cSIProcessor;
private:
const cSchedule *pCurrentSchedule;
- unsigned short uCurrentServiceID;
+ uint64 uCurrentChannelID;
protected:
- const cSchedule *AddServiceID(unsigned short servid);
- const cSchedule *SetCurrentServiceID(unsigned short servid);
+ const cSchedule *AddChannelID(uint64 channelid);
+ const cSchedule *SetCurrentChannelID(uint64 channelid);
void Cleanup();
public:
cSchedules(void);
~cSchedules();
- const cSchedule *GetSchedule(unsigned short servid) const;
+ const cSchedule *GetSchedule(uint64 channelid) const;
const cSchedule *GetSchedule(void) const;
void Dump(FILE *f, const char *Prefix = "") const;
static bool Read(FILE *f);
@@ -141,6 +141,7 @@ private:
static const char *epgDataFileName;
static time_t lastDump;
bool masterSIProcessor;
+ int currentSource;
int currentTransponder;
SIP_FILTER *filters;
char *fileName;
@@ -160,8 +161,8 @@ public:
static bool Read(FILE *f = NULL);
static void Clear(void);
void SetStatus(bool On);
- void SetCurrentTransponder(int CurrentTransponder);
- static bool SetCurrentServiceID(unsigned short servid);
+ void SetCurrentTransponder(int CurrentSource, int CurrentTransponder);
+ static bool SetCurrentChannelID(uint64 channelid);
static void TriggerDump(void);
};
diff --git a/i18n.c b/i18n.c
index 08b27650..79fa6079 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.99 2002/10/27 14:24:00 kls Exp $
+ * $Id: i18n.c 1.100 2002/11/10 12:32:30 kls Exp $
*
* Translations provided by:
*
@@ -1468,6 +1468,22 @@ const tI18nPhrase Phrases[] = {
"",//TODO
"",//TODO
},
+ { "Channel settings are not unique!",
+ "Kanaleinstellungen sind nicht eindeutig!",
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ },
{ "Channel locked (recording)!",
"Kanal blockiert (zeichnet auf)!",
"Zaklenjen kanal (snemanje)!",
diff --git a/menu.c b/menu.c
index 47ad091b..6b773a53 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.222 2002/11/01 12:15:45 kls Exp $
+ * $Id: menu.c 1.223 2002/11/10 12:32:42 kls Exp $
*/
#include "menu.h"
@@ -546,16 +546,18 @@ private:
cChannel data;
void Setup(void);
public:
- cMenuEditChannel(int Index);
+ cMenuEditChannel(cChannel *Channel, bool New = false);
virtual eOSState ProcessKey(eKeys Key);
};
-cMenuEditChannel::cMenuEditChannel(int Index)
+cMenuEditChannel::cMenuEditChannel(cChannel *Channel, bool New)
:cOsdMenu(tr("Edit channel"), 14)
{
- channel = Channels.Get(Index);
+ channel = Channel;
if (channel) {
data = *channel;
+ if (New)
+ channel = NULL;
Setup();
}
}
@@ -603,10 +605,26 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
if (state == osUnknown) {
if (Key == kOk) {
- if (channel)
- *channel = data;
- Channels.Save();
- state = osBack;
+ if (Channels.HasUniqueChannelID(&data, channel)) {
+ if (channel) {
+ *channel = data;
+ isyslog("edited channel %d %s", channel->Number(), data.ToText());
+ state = osBack;
+ }
+ else {
+ channel = new cChannel;
+ *channel = data;
+ Channels.Add(channel);
+ Channels.ReNumber();
+ isyslog("added channel %d %s", channel->Number(), data.ToText());
+ state = osUser1;
+ }
+ Channels.Save();
+ }
+ else {
+ Interface->Error(tr("Channel settings are not unique!"));
+ state = osContinue;
+ }
}
}
if (Key != kNone && (data.source & cSource::st_Mask) != (oldSource & cSource::st_Mask))
@@ -696,10 +714,8 @@ eOSState cMenuChannels::Edit(void)
if (HasSubMenu() || Count() == 0)
return osContinue;
cChannel *ch = Channels.Get(Current());
- if (ch) {
- isyslog("editing channel %d", ch->Number());
- return AddSubMenu(new cMenuEditChannel(Current()));
- }
+ if (ch)
+ return AddSubMenu(new cMenuEditChannel(ch));
return osContinue;
}
@@ -707,13 +723,7 @@ eOSState cMenuChannels::New(void)
{
if (HasSubMenu())
return osContinue;
- cChannel *channel = new cChannel(Channels.Get(Current()));
- Channels.Add(channel);
- Channels.ReNumber();
- Add(new cMenuChannelItem(channel), true);
- Channels.Save();
- isyslog("channel %d added", channel->Number());
- return AddSubMenu(new cMenuEditChannel(Current()));
+ return AddSubMenu(new cMenuEditChannel(Channels.Get(Current()), true));
}
eOSState cMenuChannels::Del(void)
@@ -753,16 +763,27 @@ eOSState cMenuChannels::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
- if (state == osUnknown) {
- switch (Key) {
- case kOk: return Switch();
- case kRed: return Edit();
- case kGreen: return New();
- case kYellow: return Del();
- case kBlue: Mark(); break;
- default: break;
- }
- }
+ switch (state) {
+ case osUser1: {
+ cChannel *channel = Channels.Last();
+ if (channel) {
+ Add(new cMenuChannelItem(channel), true);
+ return CloseSubMenu();
+ }
+ }
+ break;
+ default:
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk: return Switch();
+ case kRed: return Edit();
+ case kGreen: return New();
+ case kYellow: return Del();
+ case kBlue: Mark(); break;
+ default: break;
+ }
+ }
+ }
return state;
}
@@ -1068,7 +1089,7 @@ cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch)
{
eventInfo = EventInfo;
if (eventInfo) {
- cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID());
+ cChannel *channel = Channels.GetByChannelID(eventInfo->GetChannelID());
if (channel) {
char *buffer;
asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->Name(), 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString());
@@ -1162,7 +1183,7 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentCha
pArray[num] = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
if (pArray[num]) {
- cChannel *channel = Channels.GetByServiceID(pArray[num]->GetServiceID());
+ cChannel *channel = Channels.GetByChannelID(pArray[num]->GetChannelID());
if (channel) {
pArray[num]->SetChannelNumber(channel->Number());
num++;
@@ -1192,7 +1213,7 @@ eOSState cMenuWhatsOn::Switch(void)
{
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
if (item) {
- cChannel *channel = Channels.GetByServiceID(item->eventInfo->GetServiceID());
+ cChannel *channel = Channels.GetByChannelID(item->eventInfo->GetChannelID());
if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
return osEnd;
}
@@ -1313,7 +1334,7 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel)
SetTitle(buffer);
free(buffer);
if (schedules) {
- const cSchedule *Schedule = Channel->Sid() ? schedules->GetSchedule(Channel->Sid()) : schedules->GetSchedule();
+ const cSchedule *Schedule = schedules->GetSchedule(Channel->GetChannelID());
int num = Schedule->NumEvents();
const cEventInfo **pArray = MALLOC(const cEventInfo *, num);
if (pArray) {
@@ -1376,7 +1397,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
if (!now && !next) {
int ChannelNr = 0;
if (Count()) {
- cChannel *channel = Channels.GetByServiceID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetServiceID());
+ cChannel *channel = Channels.GetByChannelID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetChannelID());
if (channel)
ChannelNr = channel->Number();
}
@@ -1403,7 +1424,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
now = next = false;
const cEventInfo *ei = cMenuWhatsOn::ScheduleEventInfo();
if (ei) {
- cChannel *channel = Channels.GetByServiceID(ei->GetServiceID());
+ cChannel *channel = Channels.GetByChannelID(ei->GetChannelID());
if (channel) {
PrepareSchedule(channel);
if (channel->Number() != cDevice::CurrentChannel()) {
@@ -2713,7 +2734,7 @@ bool cRecordControl::GetEventInfo(void)
cMutexLock MutexLock;
const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock);
if (Schedules) {
- const cSchedule *Schedule = Schedules->GetSchedule(channel->Sid());
+ const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
if (Schedule) {
eventInfo = Schedule->GetEventAround(Time);
if (eventInfo) {
diff --git a/osd.c b/osd.c
index acd9aec4..8324874c 100644
--- a/osd.c
+++ b/osd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.c 1.36 2002/10/13 10:31:28 kls Exp $
+ * $Id: osd.c 1.37 2002/11/10 12:30:09 kls Exp $
*/
#include "osd.h"
@@ -599,20 +599,24 @@ eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
delete subMenu;
subMenu = SubMenu;
subMenu->Display();
- return osContinue; // convenience return value (see cMenuMain)
+ return osContinue; // convenience return value
+}
+
+eOSState cOsdMenu::CloseSubMenu()
+{
+ delete subMenu;
+ subMenu = NULL;
+ RefreshCurrent();
+ Display();
+ return osContinue; // convenience return value
}
eOSState cOsdMenu::ProcessKey(eKeys Key)
{
if (subMenu) {
eOSState state = subMenu->ProcessKey(Key);
- if (state == osBack) {
- delete subMenu;
- subMenu = NULL;
- RefreshCurrent();
- Display();
- state = osContinue;
- }
+ if (state == osBack)
+ return CloseSubMenu();
return state;
}
diff --git a/osd.h b/osd.h
index ada58e40..9fb515b4 100644
--- a/osd.h
+++ b/osd.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.h 1.35 2002/11/03 18:03:55 kls Exp $
+ * $Id: osd.h 1.36 2002/11/10 12:28:57 kls Exp $
*/
#ifndef __OSD_H
@@ -147,6 +147,7 @@ protected:
void Mark(void);
eOSState HotKey(eKeys Key);
eOSState AddSubMenu(cOsdMenu *SubMenu);
+ eOSState CloseSubMenu();
bool HasSubMenu(void) { return subMenu; }
void SetStatus(const char *s);
void SetTitle(const char *Title, bool ShowDate = true);
diff --git a/remote.h b/remote.h
index 35cf62e5..b23b9335 100644
--- a/remote.h
+++ b/remote.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remote.h 1.19 2002/11/01 10:48:11 kls Exp $
+ * $Id: remote.h 1.20 2002/11/09 11:07:33 kls Exp $
*/
#ifndef __REMOTE_H
@@ -16,8 +16,6 @@
#include "thread.h"
#include "tools.h"
-typedef unsigned long long int uint64;
-
class cRemote : public cListObject {
private:
enum { MaxKeys = MAXKEYSINMACRO };
diff --git a/svdrp.c b/svdrp.c
index 2859fb9d..66b420cf 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 1.48 2002/10/20 12:45:03 kls Exp $
+ * $Id: svdrp.c 1.49 2002/11/10 12:09:56 kls Exp $
*/
#include "svdrp.h"
@@ -776,15 +776,20 @@ void cSVDRP::CmdMODC(const char *Option)
tail = skipspace(tail);
cChannel *channel = Channels.GetByNumber(n);
if (channel) {
- cChannel c = *channel;
- if (!c.Parse(tail)) {
- Reply(501, "Error in channel settings");
- return;
+ cChannel ch;
+ if (ch.Parse(tail, true)) {
+ if (Channels.HasUniqueChannelID(&ch, channel)) {
+ *channel = ch;
+ Channels.ReNumber();
+ Channels.Save();
+ isyslog("modifed channel %d %s", channel->Number(), channel->ToText());
+ Reply(250, "%d %s", channel->Number(), channel->ToText());
+ }
+ else
+ Reply(501, "Channel settings are not unique");
}
- *channel = c;
- Channels.Save();
- isyslog("channel %d modified", channel->Number());
- Reply(250, "%d %s", channel->Number(), channel->ToText());
+ else
+ Reply(501, "Error in channel settings");
}
else
Reply(501, "Channel \"%d\" not defined", n);
@@ -844,13 +849,19 @@ void cSVDRP::CmdMOVT(const char *Option)
void cSVDRP::CmdNEWC(const char *Option)
{
if (*Option) {
- cChannel *channel = new cChannel;
- if (channel->Parse(Option)) {
- Channels.Add(channel);
- Channels.ReNumber();
- Channels.Save();
- isyslog("channel %d added", channel->Number());
- Reply(250, "%d %s", channel->Number(), channel->ToText());
+ cChannel ch;
+ if (ch.Parse(Option, true)) {
+ if (Channels.HasUniqueChannelID(&ch)) {
+ cChannel *channel = new cChannel;
+ *channel = ch;
+ Channels.Add(channel);
+ Channels.ReNumber();
+ Channels.Save();
+ isyslog("new channel %d %s", channel->Number(), channel->ToText());
+ Reply(250, "%d %s", channel->Number(), channel->ToText());
+ }
+ else
+ Reply(501, "Channel settings are not unique");
}
else
Reply(501, "Error in channel settings");
diff --git a/timers.c b/timers.c
index 76f86a5e..60445222 100644
--- a/timers.c
+++ b/timers.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: timers.c 1.1 2002/10/20 12:28:55 kls Exp $
+ * $Id: timers.c 1.2 2002/11/10 10:19:12 kls Exp $
*/
#include "timers.h"
@@ -49,7 +49,7 @@ cTimer::cTimer(const cEventInfo *EventInfo)
startTime = stopTime = 0;
recording = pending = false;
active = true;
- channel = Channels.GetByServiceID(EventInfo->GetServiceID());
+ channel = Channels.GetByChannelID(EventInfo->GetChannelID());
time_t tstart = EventInfo->GetTime();
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
tstart -= Setup.MarginStart * 60;
@@ -92,22 +92,17 @@ bool cTimer::operator< (const cListObject &ListObject)
return t1 < t2 || (t1 == t2 && priority > ti->priority);
}
-const char *cTimer::ToText(cTimer *Timer)
+const char *cTimer::ToText(bool UseChannelID)
{
free(buffer);
- strreplace(Timer->file, ':', '|');
- strreplace(Timer->summary, '\n', '|');
- asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->Channel()->Number(), PrintDay(Timer->day, Timer->firstday), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : "");
- strreplace(Timer->summary, '|', '\n');
- strreplace(Timer->file, '|', ':');
+ strreplace(file, ':', '|');
+ strreplace(summary, '\n', '|');
+ asprintf(&buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s\n", active, UseChannelID ? Channel()->GetChannelIDStr() : itoa(Channel()->Number()), PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
+ strreplace(summary, '|', '\n');
+ strreplace(file, '|', ':');
return buffer;
}
-const char *cTimer::ToText(void)
-{
- return ToText(this);
-}
-
int cTimer::TimeToInt(int t)
{
return (t / 100 * 60 + t % 100) * 60;
@@ -189,8 +184,9 @@ const char *cTimer::PrintFirstDay(void)
bool cTimer::Parse(const char *s)
{
- char *buffer1 = NULL;
- char *buffer2 = NULL;
+ char *channelbuffer = NULL;
+ char *daybuffer = NULL;
+ char *filebuffer = NULL;
free(summary);
summary = NULL;
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
@@ -208,34 +204,35 @@ bool cTimer::Parse(const char *s)
strcat(strn0cpy(s2, s, l2 + 1), " \n");
s = s2;
}
- int ch = 0;
- if (8 <= sscanf(s, "%d :%d :%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &ch, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
+ bool result = false;
+ if (8 <= sscanf(s, "%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &channelbuffer, &daybuffer, &start, &stop, &priority, &lifetime, &filebuffer, &summary)) {
if (summary && !*skipspace(summary)) {
free(summary);
summary = NULL;
}
//TODO add more plausibility checks
- day = ParseDay(buffer1, &firstday);
- strn0cpy(file, buffer2, MaxFileName);
+ day = ParseDay(daybuffer, &firstday);
+ result = day != 0;
+ strn0cpy(file, filebuffer, MaxFileName);
strreplace(file, '|', ':');
strreplace(summary, '|', '\n');
- free(buffer1);
- free(buffer2);
- free(s2);
- channel = Channels.GetByNumber(ch);
+ uint64 cid = cChannel::StringToChannelID(channelbuffer);
+ channel = cid ? Channels.GetByChannelID(cid) : Channels.GetByNumber(atoi(channelbuffer));
if (!channel) {
- esyslog("ERROR: channel %d not defined", ch);
- return false;
+ esyslog("ERROR: channel %s not defined", channelbuffer);
+ result = false;
}
- return day != 0;
}
+ free(channelbuffer);
+ free(daybuffer);
+ free(filebuffer);
free(s2);
- return false;
+ return result;
}
bool cTimer::Save(FILE *f)
{
- return fprintf(f, ToText()) > 0;
+ return fprintf(f, ToText(true)) > 0;
}
bool cTimer::IsSingleEvent(void)
diff --git a/timers.h b/timers.h
index 8dc762e3..933c88e9 100644
--- a/timers.h
+++ b/timers.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: timers.h 1.1 2002/10/20 11:52:23 kls Exp $
+ * $Id: timers.h 1.2 2002/11/10 10:17:05 kls Exp $
*/
#ifndef __TIMERS_H
@@ -36,7 +36,6 @@ private:
char file[MaxFileName];
time_t firstday;
char *summary;
- static const char *ToText(cTimer *Timer);
public:
cTimer(bool Instant = false);
cTimer(const cEventInfo *EventInfo);
@@ -55,7 +54,7 @@ public:
const char *File(void) { return file; }
time_t FirstDay(void) { return firstday; }
const char *Summary(void) { return summary; }
- const char *ToText(void);
+ const char *ToText(bool UseChannelID = false);
bool Parse(const char *s);
bool Save(FILE *f);
bool IsSingleEvent(void);
diff --git a/tools.c b/tools.c
index df2d5705..68bfb7e4 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.72 2002/10/19 12:32:53 kls Exp $
+ * $Id: tools.c 1.73 2002/11/09 15:33:47 kls Exp $
*/
#include "tools.h"
@@ -243,6 +243,13 @@ bool isnumber(const char *s)
return true;
}
+const char *itoa(int n)
+{
+ static char buf[16];
+ snprintf(buf, sizeof(buf), "%d", n);
+ return buf;
+}
+
const char *AddDirectory(const char *DirName, const char *FileName)
{
static char *buf = NULL;
diff --git a/tools.h b/tools.h
index 08f2429b..efa2de6a 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 1.51 2002/10/19 12:31:50 kls Exp $
+ * $Id: tools.h 1.52 2002/11/09 15:32:36 kls Exp $
*/
#ifndef __TOOLS_H
@@ -20,6 +20,7 @@
#include <sys/types.h>
typedef unsigned char uchar;
+typedef unsigned long long int uint64;
extern int SysLogLevel;
@@ -68,6 +69,7 @@ int numdigits(int n);
int time_ms(void);
void delay_ms(int ms);
bool isnumber(const char *s);
+const char *itoa(int n); // returns a statically allocated string!
const char *AddDirectory(const char *DirName, const char *FileName); // returns a statically allocated string!
int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL);
bool DirectoryOk(const char *DirName, bool LogErrors = false);
diff --git a/vdr.5 b/vdr.5
index 2db8a7b6..9720a657 100644
--- a/vdr.5
+++ b/vdr.5
@@ -8,9 +8,9 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.5 1.11 2002/10/27 15:36:44 kls Exp $
+.\" $Id: vdr.5 1.12 2002/11/10 10:10:15 kls Exp $
.\"
-.TH vdr 5 "7 Oct 2002" "1.2.0" "Video Disk Recorder Files"
+.TH vdr 5 "10 Nov 2002" "1.2.0" "Video Disk Recorder Files"
.SH NAME
vdr file formats - the Video Disk Recorder Files
.SH DESCRIPTION
@@ -120,6 +120,18 @@ l l.
.TP
.B SID
The service ID of this channel.
+.PP
+A particular channel can be uniquely identified by its \fBchannel\ ID\fR,
+which is a string that looks like this:
+
+\fBS19.2E-0-12188-12003\fR
+
+The components of this string are the \fBSource\fR (S19.2E), \fBFrequency\fR
+(12188, MHz) and \fBSID\fR (12003) as defined above. The part that is currently
+\fB0\fR is reserved for future use.
+.br
+The \fBchannel\ ID\fR is used in the \fItimers.conf\fR and \fIepg.data\fR
+files to properly identify the channels.
.SS TIMERS
The file \fItimers.conf\fR contains the timer setup.
Each line contains one timer definition, with individual fields
@@ -143,7 +155,13 @@ Note: in order to allow future extensibility, external programs using the
and leave the lower 16 bit untouched.
.TP
.B Channel
-The number of the channel to record.
+The channel to record from. This is either the channel number as shown in the
+on-screen menus, or a complete channel ID. When reading \fItimers.conf\fR
+any channel numbers will be mapped to the respective channel ids and when
+the file is written again, there will only be channel ids. Channel numbers
+are accepted as input in order to allow easier creation of timers when
+manually editing \fItimers.conf\fR. Also, when timers are listed via SVDRP
+commands, the channels are given as numbers.
.TP
.B Day
The day when this timer shall record.
@@ -472,7 +490,7 @@ The following tag characters are defined:
.TS
tab (@);
l l.
-\fBC\fR@<service id> <channel name>
+\fBC\fR@<channel id> <channel name>
\fBE\fR@<event id> <start time> <duration> <table id>
\fBT\fR@<title>
\fBS\fR@<subtitle>
@@ -491,8 +509,8 @@ should at least have a \fBT\fR entry).
.TS
tab (@);
l l.
-<service id> @is the "program number" as defined in 'channels.conf'
-<channel name> @is the "name" as in 'channels.conf' (for information only)
+<channel id> @is the "channel ID", made up from the parameters defined in 'channels.conf'
+<channel name> @is the "name" as in 'channels.conf' (for information only, may be left out)
<start time> @is the time (as a time_t integer) in UTC when this event starts
<duration> @is the time (in seconds) that this event will take
<table id> @is a hex number that indicates the table this event is contained\