From 962596f4abc3790ac0f3f317079a3362210fff8f Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 6 Oct 2002 10:25:42 +0200 Subject: [PATCH] Modified channel handling; full DiSEqC support --- CONTRIBUTORS | 8 + HISTORY | 33 +++- Makefile | 11 +- PLUGINS.html | 31 ++-- channels.c | 433 +++++++++++++++++++++++++++++++++++++++++++++++++++ channels.h | 124 +++++++++++++++ config.c | 202 +----------------------- config.h | 50 +----- device.c | 20 ++- device.h | 4 +- diseqc.c | 136 ++++++++++++++++ diseqc.conf | 30 ++++ diseqc.h | 60 +++++++ dvbdevice.c | 278 +++++++++++++++++++++------------ dvbdevice.h | 6 +- eit.c | 7 +- eitscan.c | 9 +- i18n.c | 238 ++++++++++++++++++++++++---- menu.c | 271 ++++++++++++++++++++++++++------ recording.c | 3 +- sources.c | 104 +++++++++++++ sources.conf | 50 ++++++ sources.h | 45 ++++++ svdrp.c | 27 ++-- vdr.5 | 115 ++++++++++++-- vdr.c | 9 +- 26 files changed, 1818 insertions(+), 486 deletions(-) create mode 100644 channels.c create mode 100644 channels.h create mode 100644 diseqc.c create mode 100644 diseqc.conf create mode 100644 diseqc.h create mode 100644 sources.c create mode 100644 sources.conf create mode 100644 sources.h diff --git a/CONTRIBUTORS b/CONTRIBUTORS index dd25ca60..d7669a27 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -185,6 +185,7 @@ Wolfgang Henselmann-Weiss Uwe Scheffler for his help in keeping 'channels.conf.cable' up to date + for helping to test new DVB-T handling Matjaz Thaler for improving AC3 decoding when replaying DVDs @@ -407,3 +408,10 @@ Jeremy Hall Oliver Endriss for fixing a missing Flush() call in the remote control learning procedure + for helping to test and debug the new channel source and DiSEqC handling + +Reinhard Walter Buchner + for adding some satellites to 'sources.conf' + +Lauri Tischler + for helping to test and debug the new channel source and DiSEqC handling diff --git a/HISTORY b/HISTORY index a264ac2f..c4f43fc8 100644 --- a/HISTORY +++ b/HISTORY @@ -1536,7 +1536,38 @@ Video Disk Recorder Revision History - Avoiding restarts due to 'panic level' when switching channels on the primary device during EPG scan. -2002-09-30: Version 1.1.12 +2002-10-06: Version 1.1.12 - Fixed a missing Flush() call in the remote control learning procedure (thanks to Oliver Endriss). +- Modified channel handling to cover all parameters necessary for DVB-C and DVB-T + (see man vdr(5) for the meaning of the additional parameters stored in the field + previously named 'polarisation'). Thanks to Uwe Scheffler for testing. + If you have a system with different kinds of DVB cards, like DVB-T and DVB-C, + for instance, there is no more need to distinguish the channels through the + 'Ca' parameter in order to assign them to the various DVB cards. This is now + taken care of by the "source" parameter. So a channel marked as "terrestrial", + for example, will only be received on DVB-T cards. + Note that the cChannel class has been moved into a separate file (channels.[ch]), + and that all data members have been made private and are now only accessible + through member functions. You may have to change any plugin code that accesses + cChannel data accordingly. +- The new configuration file 'sources.conf' contains the various signal sources + (satellites, cable and terrestrial) which are used in 'channels.conf' and + 'diseqc.conf' (thanks to Reinhard Walter Buchner for adding some satellites to + 'sources.conf' and Oliver Endriss and Lauri Tischler for testing and debugging). +- The 'diseqc' parameter in the channel definitions has been redefined to hold the + "source" of the given channel (which can be either a satellite, cable or terrestrial). + For compatibility with channels.conf files from older versions, numeric values in + this parameter will be tolerated, but they have no meaning. If you want to use + DiSEqC you will need to replace these old values with the proper source identifiers + defined in the new configuration file 'sources.conf'. See how this is done in the + 'channels.conf' file that comes with the VDR package. +- The new configuration file 'diseqc.conf' can be used to set up the individual + diseqc configuration (see man vdr(5) for a description of the file format). +- The "Edit channel" menu has a new entry "Source:" in which the source of this + channel can be selected (either a satellite, cable or terrestrial). The set of + parameters at the end of this menu will change according to the type of source. +- The "Use DiSEqC" parameter in the "Setup/LNB" menu has been moved to the beginning + of the list and disables the rest of the parameters when set to "yes", since these + are now only meaningful if DiSEqC is _not_ used. diff --git a/Makefile b/Makefile index 9eae7264..7e45d5c6 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # See the main source file 'vdr.c' for copyright information and # how to reach the author. # -# $Id: Makefile 1.47 2002/09/28 14:12:43 kls Exp $ +# $Id: Makefile 1.48 2002/10/04 14:29:14 kls Exp $ .DELETE_ON_ERROR: @@ -32,10 +32,11 @@ endif DTVLIB = $(DTVDIR)/libdtv.a -OBJS = audio.o config.o cutter.o device.o dvbdevice.o dvbosd.o dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o\ - interface.o keys.o lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o receiver.o\ - recorder.o recording.o remote.o remux.o ringbuffer.o spu.o status.o svdrp.o thread.o\ - tools.o transfer.o vdr.o videodir.o +OBJS = audio.o channels.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd.o\ + dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\ + lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\ + receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\ + spu.o status.o svdrp.o thread.o tools.o transfer.o vdr.o videodir.o OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1 FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1 diff --git a/PLUGINS.html b/PLUGINS.html index 71f66abc..106bcc74 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -21,18 +21,18 @@ VDR program and present itself to the user. The inside interface provides the plugin code access to VDR's internal data structures and allows it to hook itself into specific areas to perform special actions.

-
  -Important modifications introduced in version 1.1.7 are marked like this. -
-
  +
  Important modifications introduced in version 1.1.8 are marked like this.
-
  +
  Important modifications introduced in version 1.1.9 are marked like this.
-
  +
  Important modifications introduced in version 1.1.11 are marked like this.
+
  +Important modifications introduced in version 1.1.12 are marked like this. +

Part I - The Outside Interface

@@ -957,7 +957,6 @@ stream. There are no prerequisites regarding the length or alignment of an individual block of data. The sum of all blocks must simply result in the desired video data stream, and it must be delivered fast enough so that the DVB device doesn't run out of data. -
  To avoid busy loops the player should call its member function


@@ -965,7 +964,6 @@ bool DevicePoll(cPoller &Poller, int TimeoutMs = 0);

to determine whether the device is ready for further data. -

TODO: PlayAudio()???

@@ -1184,14 +1182,17 @@ the cDvbDevice, which is used to access the DVB PCI cards. If the new device can receive, it most likely needs to provide a way of selecting which channel it shall tune to: -
  +
 


+
  +virtual bool ProvidesSource(int Source) const; +
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL); virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);

-These functions will be called with the desired channel and shall return whether -this device can provide the requested channel and whether tuning to it was successful, +These functions will be called with the desired source or channel and shall return whether +this device can provide the requested source or channel and whether tuning to it was successful, repectively.

@@ -1203,7 +1204,7 @@ A device that can be used for recording must implement the functions virtual bool SetPid(cPidHandle *Handle, int Type, bool On); virtual bool OpenDvr(void); virtual void CloseDvr(void); -
  +
  virtual bool GetTSPacket(uchar *&Data);

@@ -1227,7 +1228,6 @@ to indicate this to VDR.

The functions to implement replaying capabilites are -
 


virtual bool HasDecoder(void) const; virtual bool SetPlayMode(ePlayMode PlayMode); @@ -1240,7 +1240,6 @@ virtual void StillPicture(const uchar *Data, int Length); virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); virtual int PlayVideo(const uchar *Data, int Length);

-

In addition, the following functions may be implemented to provide further functionality: @@ -1251,7 +1250,7 @@ virtual void SetVideoFormat(bool VideoFormat16_9); virtual void SetVolumeDevice(int Volume);

-
  +
 

On Screen Display

@@ -1292,7 +1291,7 @@ shut down (delete) all devices when the program terminates. It is therefore important that the devices are created on the heap, using the new operator! -
  +
 

Remote Control

The joy of zapping!

diff --git a/channels.c b/channels.c new file mode 100644 index 00000000..dc5c1580 --- /dev/null +++ b/channels.c @@ -0,0 +1,433 @@ +/* + * channels.c: Channel handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: channels.c 1.1 2002/10/05 13:22:28 kls Exp $ + */ + +#include "channels.h" +#ifdef NEWSTRUCT +#include +#else +#include +#endif +#include + +// 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 +// value! + +// -- Channel Parameter Maps ------------------------------------------------- + +const tChannelParameterMap InversionValues[] = { + { 0, INVERSION_OFF }, + { 1, INVERSION_ON }, + { 999, INVERSION_AUTO }, + { -1 } + }; + +const tChannelParameterMap BandwidthValues[] = { + { 6, BANDWIDTH_6_MHZ }, + { 7, BANDWIDTH_7_MHZ }, + { 8, BANDWIDTH_8_MHZ }, +#ifdef NEWSTRUCT + { 999, BANDWIDTH_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap CoderateValues[] = { + { 0, FEC_NONE }, + { 12, FEC_1_2 }, + { 23, FEC_2_3 }, + { 34, FEC_3_4 }, +#ifdef NEWSTRUCT + { 45, FEC_4_5 }, +#endif + { 56, FEC_5_6 }, +#ifdef NEWSTRUCT + { 67, FEC_6_7 }, +#endif + { 78, FEC_7_8 }, +#ifdef NEWSTRUCT + { 89, FEC_8_9 }, +#endif + { 999, FEC_AUTO }, + { -1 } + }; + +const tChannelParameterMap ModulationValues[] = { + { 0, QPSK }, + { 16, QAM_16 }, + { 32, QAM_32 }, + { 64, QAM_64 }, + { 128, QAM_128 }, + { 256, QAM_256 }, +#ifdef NEWSTRUCT + { 999, QAM_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap TransmissionValues[] = { + { 2, TRANSMISSION_MODE_2K }, + { 8, TRANSMISSION_MODE_8K }, +#ifdef NEWSTRUCT + { 999, TRANSMISSION_MODE_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap GuardValues[] = { + { 4, GUARD_INTERVAL_1_4 }, + { 8, GUARD_INTERVAL_1_8 }, + { 16, GUARD_INTERVAL_1_16 }, + { 32, GUARD_INTERVAL_1_32 }, +#ifdef NEWSTRUCT + { 999, GUARD_INTERVAL_AUTO }, +#endif + { -1 } + }; + +const tChannelParameterMap HierarchyValues[] = { + { 0, HIERARCHY_NONE }, + { 1, HIERARCHY_1 }, + { 2, HIERARCHY_2 }, + { 4, HIERARCHY_4 }, +#ifdef NEWSTRUCT + { 999, HIERARCHY_AUTO }, +#endif + { -1 } + }; + +int UserIndex(int Value, const tChannelParameterMap *Map) +{ + const tChannelParameterMap *map = Map; + while (map && map->userValue != -1) { + if (map->userValue == Value) + return map - Map; + map++; + } + return -1; +} + +int DriverIndex(int Value, const tChannelParameterMap *Map) +{ + const tChannelParameterMap *map = Map; + while (map && map->userValue != -1) { + if (map->driverValue == Value) + return map - Map; + map++; + } + return -1; +} + +int MapToUser(int Value, const tChannelParameterMap *Map) +{ + int n = DriverIndex(Value, Map); + if (n >= 0) + return Map[n].userValue; + return -1; +} + +int MapToDriver(int Value, const tChannelParameterMap *Map) +{ + int n = UserIndex(Value, Map); + if (n >= 0) + return Map[n].driverValue; + return -1; +} + +// -- cChannel --------------------------------------------------------------- + +char *cChannel::buffer = NULL; + +cChannel::cChannel(void) +{ + *name = 0; + frequency = 0; + source = 0; + srate = 0; + vpid = 0; + apid1 = 0; + apid2 = 0; + dpid1 = 0; + dpid2 = 0; + tpid = 0; + ca = 0; + sid = 0; + groupSep = false; + //XXX + polarization = 'v'; + inversion = INVERSION_AUTO; + bandwidth = BANDWIDTH_8_MHZ; + coderateH = FEC_AUTO;//XXX FEC_2_3 + coderateL = FEC_1_2;//XXX + modulation = QAM_64; + transmission = TRANSMISSION_MODE_2K; + guard = GUARD_INTERVAL_1_32; + hierarchy = HIERARCHY_NONE; +} + +cChannel::cChannel(const cChannel *Channel) +{ + strcpy(name, Channel ? Channel->name : "Pro7"); + frequency = Channel ? Channel->frequency : 12480; + source = Channel ? Channel->source : 0; + 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; + //XXX + polarization = Channel ? Channel->polarization : 'v'; + inversion = Channel ? Channel->inversion : INVERSION_AUTO; + bandwidth = Channel ? Channel->bandwidth : BANDWIDTH_8_MHZ; + coderateH = Channel ? Channel->coderateH : FEC_AUTO;//XXX FEC_2_3 + coderateL = Channel ? Channel->coderateL : FEC_1_2;//XXX + modulation = Channel ? Channel->modulation : QAM_64; + transmission = Channel ? Channel->transmission : TRANSMISSION_MODE_2K; + guard = Channel ? Channel->guard : GUARD_INTERVAL_1_32; + hierarchy = Channel ? Channel->hierarchy : HIERARCHY_NONE; +} + +static int PrintParameter(char *p, char Name, int Value) +{ + return Value > 0 && Value != 999 ? sprintf(p, "%c%d", Name, Value) : 0; +} + +const char *cChannel::ParametersToString(void) +{ + char type = *cSource::ToString(source); +#define ST(s) if (strchr(s, type)) + static char buffer[64]; + char *q = buffer; + *q = 0; + ST(" S ") q += sprintf(q, "%c", polarization); + ST("CST") q += PrintParameter(q, 'I', MapToUser(inversion, InversionValues)); + ST("CST") q += PrintParameter(q, 'C', MapToUser(coderateH, CoderateValues)); + ST(" T") q += PrintParameter(q, 'D', MapToUser(coderateL, CoderateValues)); + ST("C T") q += PrintParameter(q, 'M', MapToUser(modulation, ModulationValues)); + ST(" T") q += PrintParameter(q, 'B', MapToUser(bandwidth, BandwidthValues)); + ST(" T") q += PrintParameter(q, 'T', MapToUser(transmission, TransmissionValues)); + ST(" T") q += PrintParameter(q, 'G', MapToUser(guard, GuardValues)); + ST(" T") q += PrintParameter(q, 'Y', MapToUser(hierarchy, HierarchyValues)); + return buffer; +} + +static const char *ParseParameter(const char *s, int &Value, const tChannelParameterMap *Map) +{ + if (*++s) { + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s) { + Value = MapToDriver(n, Map); + if (Value >= 0) + return p; + } + } + esyslog("ERROR: illegal value for parameter '%c'", *(s - 1)); + return NULL; +} + +bool cChannel::StringToParameters(const char *s) +{ + while (s && *s) { + switch (toupper(*s)) { + case 'B': s = ParseParameter(s, bandwidth, BandwidthValues); break; + case 'C': s = ParseParameter(s, coderateH, CoderateValues); break; + case 'D': s = ParseParameter(s, coderateL, CoderateValues); break; + case 'G': s = ParseParameter(s, guard, GuardValues); break; + case 'H': polarization = *s++; break; + case 'I': s = ParseParameter(s, inversion, InversionValues); break; + // 'L' reserved for possible circular polarization + case 'M': s = ParseParameter(s, modulation, ModulationValues); break; + // 'R' reserved for possible circular polarization + case 'T': s = ParseParameter(s, transmission, TransmissionValues); break; + case 'V': polarization = *s++; break; + case 'Y': s = ParseParameter(s, hierarchy, HierarchyValues); break; + default: esyslog("ERROR: unknown parameter key '%c'", *s); + return false; + } + } + return true; +} + +const char *cChannel::ToText(cChannel *Channel) +{ + char buf[MaxChannelName * 2]; + char *s = Channel->name; + if (strchr(s, ':')) { + s = strcpy(buf, s); + strreplace(s, ':', '|'); + } + free(buffer); + if (Channel->groupSep) + asprintf(&buffer, ":%s\n", s); + else { + char apidbuf[32]; + char *q = apidbuf; + q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); + if (Channel->apid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2); + if (Channel->dpid1 || Channel->dpid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ";%d", Channel->dpid1); + if (Channel->dpid2) + q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2); + *q = 0; + asprintf(&buffer, "%s:%d:%s:%s:%d:%d:%s:%d:%d:%d\n", s, Channel->frequency, Channel->ParametersToString(), cSource::ToString(Channel->source), Channel->srate, Channel->vpid, apidbuf, Channel->tpid, Channel->ca, Channel->sid); + } + return buffer; +} + +const char *cChannel::ToText(void) +{ + return ToText(this); +} + +bool cChannel::Parse(const char *s) +{ + if (*s == ':') { + if (*++s) { + strn0cpy(name, s, MaxChannelName); + groupSep = true; + number = 0; + } + else + return false; + } + else { + groupSep = false; + char *namebuf = NULL; + char *sourcebuf = NULL; + char *parambuf = NULL; + char *apidbuf = NULL; + int fields = sscanf(s, "%a[^:]:%d :%a[^:]:%a[^:] :%d :%d :%a[^:]:%d :%d :%d ", &namebuf, &frequency, ¶mbuf, &sourcebuf, &srate, &vpid, &apidbuf, &tpid, &ca, &sid); + if (fields >= 9) { + if (fields == 9) { + // allow reading of old format + sid = ca; + ca = tpid; + tpid = 0; + } + apid1 = apid2 = 0; + dpid1 = dpid2 = 0; + bool ok = false; + if (parambuf && sourcebuf && apidbuf) { + ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0; + char *p = strchr(apidbuf, ';'); + if (p) + *p++ = 0; + sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); + if (p) + sscanf(p, "%d ,%d ", &dpid1, &dpid2); + } + strn0cpy(name, namebuf, MaxChannelName); + free(parambuf); + free(sourcebuf); + free(apidbuf); + free(namebuf); + return ok; + } + else + return false; + } + strreplace(name, '|', ':'); + return true; +} + +bool cChannel::Save(FILE *f) +{ + return fprintf(f, ToText()) > 0; +} + +// -- cChannels -------------------------------------------------------------- + +cChannels Channels; + +bool cChannels::Load(const char *FileName, bool AllowComments) +{ + if (cConfig::Load(FileName, AllowComments)) { + ReNumber(); + return true; + } + return false; +} + +int cChannels::GetNextGroup(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && !channel->GroupSep()) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +int cChannels::GetPrevGroup(int Idx) +{ + cChannel *channel = Get(--Idx); + while (channel && !channel->GroupSep()) + channel = Get(--Idx); + return channel ? Idx : -1; +} + +int cChannels::GetNextNormal(int Idx) +{ + cChannel *channel = Get(++Idx); + while (channel && channel->GroupSep()) + channel = Get(++Idx); + return channel ? Idx : -1; +} + +void cChannels::ReNumber( void ) +{ + int Number = 0; + cChannel *ch = (cChannel *)First(); + while (ch) { + if (!ch->GroupSep()) + ch->SetNumber(++Number); + ch = (cChannel *)ch->Next(); + } + maxNumber = Number; +} + +cChannel *cChannels::GetByNumber(int Number) +{ + cChannel *channel = (cChannel *)First(); + while (channel) { + if (!channel->GroupSep() && channel->Number() == Number) + return channel; + channel = (cChannel *)channel->Next(); + } + return NULL; +} + +cChannel *cChannels::GetByServiceID(unsigned short ServiceId) +{ + cChannel *channel = (cChannel *)First(); + while (channel) { + if (!channel->GroupSep() && channel->Sid() == ServiceId) + return channel; + channel = (cChannel *)channel->Next(); + } + return NULL; +} + +bool cChannels::SwitchTo(int Number) +{ + cChannel *channel = GetByNumber(Number); + return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true); +} + +const char *cChannels::GetChannelNameByNumber(int Number) +{ + cChannel *channel = GetByNumber(Number); + return channel ? channel->Name() : NULL; +} diff --git a/channels.h b/channels.h new file mode 100644 index 00000000..8a784f75 --- /dev/null +++ b/channels.h @@ -0,0 +1,124 @@ +/* + * channels.h: Channel handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: channels.h 1.1 2002/10/05 13:53:15 kls Exp $ + */ + +#ifndef __CHANNELS_H +#define __CHANNELS_H + +#include "config.h" +#include "sources.h" +#include "tools.h" + +#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) //XXX + +struct tChannelParameterMap { + int userValue; + int driverValue; + }; + +//XXX into cChannel??? +int MapToUser(int Value, const tChannelParameterMap *Map); +int MapToDriver(int Value, const tChannelParameterMap *Map); +int UserIndex(int Value, const tChannelParameterMap *Map); +int DriverIndex(int Value, const tChannelParameterMap *Map); + +extern const tChannelParameterMap InversionValues[]; +extern const tChannelParameterMap BandwidthValues[]; +extern const tChannelParameterMap CoderateValues[]; +extern const tChannelParameterMap ModulationValues[]; +extern const tChannelParameterMap TransmissionValues[]; +extern const tChannelParameterMap GuardValues[]; +extern const tChannelParameterMap HierarchyValues[]; + +class cChannel : public cListObject { + friend class cMenuEditChannel; +private: + static char *buffer; + static const char *ToText(cChannel *Channel); + enum { MaxChannelName = 32 }; // 31 chars + terminating 0! + char name[MaxChannelName]; + int frequency; // MHz + int source; + int srate; + int vpid; + int apid1, apid2; + int dpid1, dpid2; + int tpid; + int ca; + int sid; + int number; // Sequence number assigned on load + bool groupSep; + //XXX + char polarization; + int inversion; + int bandwidth; + int coderateH; + int coderateL; + int modulation; + int transmission; + int guard; + int hierarchy; + const char *ParametersToString(void); + bool StringToParameters(const char *s); +public: + cChannel(void); + cChannel(const cChannel *Channel); + const char *ToText(void); + bool Parse(const char *s); + bool Save(FILE *f); + const char *Name(void) const { return name; } + int Frequency(void) const { return frequency; } + int Source(void) const { return source; } + int Srate(void) const { return srate; } + int Vpid(void) const { return vpid; } + int Apid1(void) const { return apid1; } + int Apid2(void) const { return apid2; } + int Dpid1(void) const { return dpid1; } + int Dpid2(void) const { return dpid2; } + int Tpid(void) const { return tpid; } + int Ca(void) const { return ca; } + int Sid(void) const { return sid; } + 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; } + int CoderateH(void) const { return coderateH; } + int CoderateL(void) const { return coderateL; } + int Modulation(void) const { return modulation; } + 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; } + }; + +class cChannels : public cConfig { +protected: + int maxNumber; +public: + cChannels(void) { maxNumber = 0; } + virtual bool Load(const char *FileName, bool AllowComments = false); + int GetNextGroup(int Idx); // Get next channel group + int GetPrevGroup(int Idx); // Get previous channel group + int GetNextNormal(int Idx); // Get next normal channel (not group) + void ReNumber(void); // Recalculate 'number' based on channel type + cChannel *GetByNumber(int Number); + cChannel *GetByServiceID(unsigned short ServiceId); + const char *GetChannelNameByNumber(int Number); + bool SwitchTo(int Number); + int MaxNumber(void) { return maxNumber; } + }; + +extern cChannels Channels; + +#endif //__CHANNELS_H diff --git a/config.c b/config.c index e5a56090..24c14389 100644 --- a/config.c +++ b/config.c @@ -4,12 +4,13 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.106 2002/09/28 09:43:41 kls Exp $ + * $Id: config.c 1.107 2002/10/03 10:06:55 kls Exp $ */ #include "config.h" #include #include +#include "channels.h" //XXX timers! #include "i18n.h" #include "interface.h" #include "plugin.h" @@ -19,116 +20,6 @@ // format characters in order to allow any number of blanks after a numeric // value! -// -- cChannel --------------------------------------------------------------- - -char *cChannel::buffer = NULL; - -cChannel::cChannel(void) -{ - *name = 0; -} - -cChannel::cChannel(const cChannel *Channel) -{ - strcpy(name, Channel ? Channel->name : "Pro7"); - frequency = Channel ? Channel->frequency : 12480; - polarization = Channel ? Channel->polarization : 'v'; - diseqc = Channel ? Channel->diseqc : 0; - 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; - pnr = Channel ? Channel->pnr : 0; - groupSep = Channel ? Channel->groupSep : false; -} - -const char *cChannel::ToText(cChannel *Channel) -{ - char buf[MaxChannelName * 2]; - char *s = Channel->name; - if (strchr(s, ':')) { - s = strcpy(buf, s); - strreplace(s, ':', '|'); - } - free(buffer); - if (Channel->groupSep) - asprintf(&buffer, ":%s\n", s); - else { - char apidbuf[32]; - char *q = apidbuf; - q += snprintf(q, sizeof(apidbuf), "%d", Channel->apid1); - if (Channel->apid2) - q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->apid2); - if (Channel->dpid1 || Channel->dpid2) - q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ";%d", Channel->dpid1); - if (Channel->dpid2) - q += snprintf(q, sizeof(apidbuf) - (q - apidbuf), ",%d", Channel->dpid2); - *q = 0; - asprintf(&buffer, "%s:%d:%c:%d:%d:%d:%s:%d:%d:%d\n", s, Channel->frequency, Channel->polarization, Channel->diseqc, Channel->srate, Channel->vpid, apidbuf, Channel->tpid, Channel->ca, Channel->pnr); - } - return buffer; -} - -const char *cChannel::ToText(void) -{ - return ToText(this); -} - -bool cChannel::Parse(const char *s) -{ - char *buffer = NULL; - if (*s == ':') { - if (*++s) { - strn0cpy(name, s, MaxChannelName); - groupSep = true; - number = 0; - } - else - return false; - } - else { - groupSep = false; - char *apidbuf = NULL; - int fields = sscanf(s, "%a[^:]:%d :%c:%d :%d :%d :%a[^:]:%d :%d :%d ", &buffer, &frequency, &polarization, &diseqc, &srate, &vpid, &apidbuf, &tpid, &ca, &pnr); - apid1 = apid2 = 0; - dpid1 = dpid2 = 0; - if (apidbuf) { - char *p = strchr(apidbuf, ';'); - if (p) - *p++ = 0; - sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); - if (p) - sscanf(p, "%d ,%d ", &dpid1, &dpid2); - free(apidbuf); - } - else - return false; - if (fields >= 9) { - if (fields == 9) { - // allow reading of old format - pnr = ca; - ca = tpid; - tpid = 0; - } - strn0cpy(name, buffer, MaxChannelName); - free(buffer); - } - else - return false; - } - strreplace(name, '|', ':'); - return true; -} - -bool cChannel::Save(FILE *f) -{ - return fprintf(f, ToText()) > 0; -} - // -- cTimer ----------------------------------------------------------------- char *cTimer::buffer = NULL; @@ -139,7 +30,7 @@ cTimer::cTimer(bool Instant) recording = pending = false; active = Instant ? taActInst : taInactive; cChannel *ch = Channels.GetByNumber(cDevice::CurrentChannel()); - channel = ch ? ch->number : 0; + channel = ch ? ch->Number() : 0; time_t t = time(NULL); struct tm tm_r; struct tm *now = localtime_r(&t, &tm_r); @@ -156,7 +47,7 @@ cTimer::cTimer(bool Instant) firstday = 0; summary = NULL; if (Instant && ch) - snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->name); + snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->Name()); } cTimer::cTimer(const cEventInfo *EventInfo) @@ -165,7 +56,7 @@ cTimer::cTimer(const cEventInfo *EventInfo) recording = pending = false; active = true; cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID()); - channel = ch ? ch->number : 0; + channel = ch ? ch->Number() : 0; time_t tstart = EventInfo->GetTime(); time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60; tstart -= Setup.MarginStart * 60; @@ -573,89 +464,6 @@ bool cCaDefinition::Parse(const char *s) cCommands Commands; -// -- cChannels -------------------------------------------------------------- - -cChannels Channels; - -bool cChannels::Load(const char *FileName, bool AllowComments) -{ - if (cConfig::Load(FileName, AllowComments)) { - ReNumber(); - return true; - } - return false; -} - -int cChannels::GetNextGroup(int Idx) -{ - cChannel *channel = Get(++Idx); - while (channel && !channel->groupSep) - channel = Get(++Idx); - return channel ? Idx : -1; -} - -int cChannels::GetPrevGroup(int Idx) -{ - cChannel *channel = Get(--Idx); - while (channel && !channel->groupSep) - channel = Get(--Idx); - return channel ? Idx : -1; -} - -int cChannels::GetNextNormal(int Idx) -{ - cChannel *channel = Get(++Idx); - while (channel && channel->groupSep) - channel = Get(++Idx); - return channel ? Idx : -1; -} - -void cChannels::ReNumber( void ) -{ - int Number = 0; - cChannel *ch = (cChannel *)First(); - while (ch) { - if (!ch->groupSep) - ch->number = ++Number; - ch = (cChannel *)ch->Next(); - } - maxNumber = Number; -} - -cChannel *cChannels::GetByNumber(int Number) -{ - cChannel *channel = (cChannel *)First(); - while (channel) { - if (!channel->groupSep && channel->number == Number) - return channel; - channel = (cChannel *)channel->Next(); - } - return NULL; -} - -cChannel *cChannels::GetByServiceID(unsigned short ServiceId) -{ - cChannel *channel = (cChannel *)First(); - while (channel) { - if (!channel->groupSep && channel->pnr == ServiceId) - return channel; - channel = (cChannel *)channel->Next(); - } - return NULL; -} - -bool cChannels::SwitchTo(int Number) -{ - cChannel *channel = GetByNumber(Number); - return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true); -} - -const char *cChannels::GetChannelNameByNumber(int Number) -{ - cChannel *channel = GetByNumber(Number); - return channel ? channel->name : NULL; -} - // -- cTimers ---------------------------------------------------------------- cTimers Timers; diff --git a/config.h b/config.h index c8a9cdd0..2da1420b 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.130 2002/09/30 15:57:23 kls Exp $ + * $Id: config.h 1.131 2002/10/05 09:58:58 kls Exp $ */ #ifndef __CONFIG_H @@ -32,34 +32,6 @@ #define MaxFileName 256 -#define ISTRANSPONDER(f1, f2) (abs((f1) - (f2)) < 4) - -class cChannel : public cListObject { -private: - static char *buffer; - static const char *ToText(cChannel *Channel); -public: - enum { MaxChannelName = 32 }; // 31 chars + terminating 0! - char name[MaxChannelName]; - int frequency; // MHz - char polarization; - int diseqc; - int srate; - int vpid; - int apid1, apid2; - int dpid1, dpid2; - int tpid; - int ca; - int pnr; - int number; // Sequence number assigned on load - bool groupSep; - cChannel(void); - cChannel(const cChannel *Channel); - const char *ToText(void); - bool Parse(const char *s); - bool Save(FILE *f); - }; - enum eTimerActive { taInactive = 0, taActive = 1, taInstant = 2, @@ -193,7 +165,7 @@ public: if (l->Parse(buffer)) Add(l); else { - esyslog("error in %s, line %d\n", fileName, line); + esyslog("ERROR: error in %s, line %d\n", fileName, line); delete l; result = false; break; @@ -229,23 +201,6 @@ public: } }; -class cChannels : public cConfig { -protected: - int maxNumber; -public: - cChannels(void) { maxNumber = 0; } - virtual bool Load(const char *FileName, bool AllowComments = false); - int GetNextGroup(int Idx); // Get next channel group - int GetPrevGroup(int Idx); // Get previous channel group - int GetNextNormal(int Idx); // Get next normal channel (not group) - void ReNumber(void); // Recalculate 'number' based on channel type - cChannel *GetByNumber(int Number); - cChannel *GetByServiceID(unsigned short ServiceId); - const char *GetChannelNameByNumber(int Number); - bool SwitchTo(int Number); - int MaxNumber(void) { return maxNumber; } - }; - class cTimers : public cConfig { public: cTimer *GetTimer(cTimer *Timer); @@ -265,7 +220,6 @@ public: const cCaDefinition *Get(int Number); }; -extern cChannels Channels; extern cTimers Timers; extern cCommands Commands; extern cSVDRPhosts SVDRPhosts; diff --git a/device.c b/device.c index 12166a8a..fa594b29 100644 --- a/device.c +++ b/device.c @@ -4,13 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 1.22 2002/09/28 12:20:22 kls Exp $ + * $Id: device.c 1.23 2002/10/05 15:18:39 kls Exp $ */ #include "device.h" #include #include #include +#include "channels.h" #include "eit.h" #include "i18n.h" #include "player.h" @@ -143,7 +144,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDe || !d->Receiving() // ...the one we have is not receiving... && (device[i]->Priority() < d->Priority() // ...this one has an even lower Priority, or... || device[i]->Priority() == d->Priority() // ...same Priority... - && device[i]->ProvidesCa(Channel->ca) < d->ProvidesCa(Channel->ca) // ...but this one provides fewer Ca values + && device[i]->ProvidesCa(Channel->Ca()) < d->ProvidesCa(Channel->Ca()) // ...but this one provides fewer Ca values ) ) ) { @@ -275,6 +276,11 @@ bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On) return false; } +bool cDevice::ProvidesSource(int Source) const +{ + return false; +} + bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const { return false; @@ -283,7 +289,7 @@ bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Needs bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) { if (LiveView) - isyslog("switching to channel %d", Channel->number); + isyslog("switching to channel %d", Channel->Number()); for (int i = 3; i--;) { switch (SetChannel(Channel, LiveView)) { case scrOk: return true; @@ -344,7 +350,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) if (CaDevice) { cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel if (CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! - cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+ + cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid1(), 0, 0, 0));//XXX+ else Result = scrNoTransfer; } @@ -359,10 +365,10 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) if (Result == scrOk) { if (LiveView && IsPrimaryDevice()) { - cSIProcessor::SetCurrentServiceID(Channel->pnr); - currentChannel = Channel->number; + cSIProcessor::SetCurrentServiceID(Channel->Sid()); + currentChannel = Channel->Number(); } - cStatus::MsgChannelSwitch(this, Channel->number); // only report status if channel switch successfull + cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull } return Result; diff --git a/device.h b/device.h index b6f44273..9dcf16ce 100644 --- a/device.h +++ b/device.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.h 1.20 2002/09/28 12:20:34 kls Exp $ + * $Id: device.h 1.21 2002/10/05 15:18:13 kls Exp $ */ #ifndef __DEVICE_H @@ -139,6 +139,8 @@ public: protected: static int currentChannel; public: + virtual bool ProvidesSource(int Source) const; + // Returns true if this device can provide the given source. virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const; // Returns true if this device can provide the given channel. // In case the device has cReceivers attached to it or it is the primary diff --git a/diseqc.c b/diseqc.c new file mode 100644 index 00000000..92b92cbb --- /dev/null +++ b/diseqc.c @@ -0,0 +1,136 @@ +/* + * diseqc.c: DiSEqC handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: diseqc.c 1.1 2002/10/05 13:54:32 kls Exp $ + */ + +#include "diseqc.h" +#include +#include "sources.h" + +// -- cDiseqc ---------------------------------------------------------------- + +cDiseqc::cDiseqc(void) +{ + commands = NULL; + currentAction = NULL;; + parsing = false; + numCodes = 0; +} + +cDiseqc::~cDiseqc() +{ + free(commands); +} + +bool cDiseqc::Parse(const char *s) +{ + bool result = false; + char *sourcebuf = NULL; + int fields = sscanf(s, "%a[^ ] %d %c %d %a[^\n]", &sourcebuf, &slof, &polarization, &lof, &commands); + if (fields == 4) + commands = NULL; //XXX Apparently sscanf() doesn't work correctly if the last %a argument results in an empty string + if (4 <= fields && fields <= 5) { + source = cSource::FromString(sourcebuf); + if (Sources.Get(source)) { + polarization = toupper(polarization); + if (polarization == 'V' || polarization == 'H') { + parsing = true; + bool Start = true; + while (Execute(Start) != daNone) + Start = false; + parsing = false; + result = !commands || currentAction && !*currentAction; + } + else + esyslog("ERROR: unknown polarization '%c'", polarization); + } + else + esyslog("ERROR: unknown source '%s'", sourcebuf); + } + free(sourcebuf); + return result; +} + +char *cDiseqc::Wait(char *s) +{ + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s && n >= 0) { + if (!parsing) + usleep(n * 1000); + return p; + } + esyslog("ERROR: illegal value for wait time in '%s'", s - 1); + return NULL; +} + +char *cDiseqc::Codes(char *s) +{ + char *e = strchr(s, ']'); + if (e) { + numCodes = 0; + char *t = s; + char *p = s; + while (t < e) { + if (numCodes < MaxDiseqcCodes) { + errno = 0; + int n = strtol(t, &p, 16); + if (!errno && p != t && 0 <= n && n <= 255) { + codes[numCodes++] = n; + t = skipspace(p); + } + else { + esyslog("ERROR: illegal code at '%s'", t); + return NULL; + } + } + else { + esyslog("ERROR: too many codes in code sequence '%s'", s - 1); + return NULL; + } + } + return e + 1; + } + else + esyslog("ERROR: missing closing ']' in code sequence '%s'", s - 1); + return NULL; +} + +cDiseqc::eDiseqcActions cDiseqc::Execute(bool Start) +{ + if (Start) + currentAction = commands; + while (currentAction && *currentAction) { + switch (*currentAction++) { + case ' ': break; + case 't': return daToneOff; + case 'T': return daToneOn; + case 'v': return daVoltage13; + case 'V': return daVoltage18; + case 'A': return daMiniA; + case 'B': return daMiniB; + case 'W': currentAction = Wait(currentAction); break; + case '[': currentAction = Codes(currentAction); return currentAction ? daCodes : daNone; + default: return daNone; + } + } + return daNone; +} + +// -- cDiseqcs --------------------------------------------------------------- + +cDiseqcs Diseqcs; + +cDiseqc *cDiseqcs::Get(int Source, int Frequency, char Polarization) +{ + for (cDiseqc *p = First(); p; p = Next(p)) { + if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) + return p; + } + return NULL; +} diff --git a/diseqc.conf b/diseqc.conf new file mode 100644 index 00000000..52222f3d --- /dev/null +++ b/diseqc.conf @@ -0,0 +1,30 @@ +# DiSEqC configuration for VDR +# +# Format: +# +# satellite slof polarization lof command... +# +# satellite: one of the 'S' codes defined in sources.conf +# slof: switch frequency of LNB; the first entry with +# an slof greater than the actual transponder +# frequency will be used +# polarization: V = vertical, H = horizontal +# lof: the local oscillator frequency to subtract from +# the actual transponder frequency +# command: +# t tone off +# T tone on +# v voltage low (13V) +# V voltage high (18V) +# A mini A +# B mini B +# Wnn wait nn milliseconds (nn may be any positive integer number) +# [xx ...] hex code sequence (max. 6) +# +# The 'command...' part is optional. + +S19.2E 11700 V 9750 t v W15 [E0 10 38 F0] W15 A W15 t +S19.2E 99999 V 10600 t v W15 [E0 10 38 F1] W15 A W15 T +S19.2E 11700 H 9750 t V W15 [E0 10 38 F2] W15 A W15 t +S19.2E 99999 H 10600 t V W15 [E0 10 38 F3] W15 A W15 T + diff --git a/diseqc.h b/diseqc.h new file mode 100644 index 00000000..f2b0e99c --- /dev/null +++ b/diseqc.h @@ -0,0 +1,60 @@ +/* + * diseqc.h: DiSEqC handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: diseqc.h 1.1 2002/10/05 13:02:52 kls Exp $ + */ + +#ifndef __DISEQC_H +#define __DISEQC_H + +#include "config.h" + +class cDiseqc : public cListObject { +public: + enum eDiseqcActions { + daNone, + daToneOff, + daToneOn, + daVoltage13, + daVoltage18, + daMiniA, + daMiniB, + daCodes, + }; + enum { MaxDiseqcCodes = 6 }; +private: + int source; + int slof; + char polarization; + int lof; + char *commands; + char *currentAction; + bool parsing; + uchar codes[MaxDiseqcCodes]; + int numCodes; + char *Wait(char *s); + char *Codes(char *s); +public: + cDiseqc(void); + ~cDiseqc(); + bool Parse(const char *s); + eDiseqcActions Execute(bool Start = false); + int Source(void) const { return source; } + int Slof(void) const { return slof; } + char Polarization(void) const { return polarization; } + int Lof(void) const { return lof; } + const char *Commands(void) const { return commands; } + uchar *Codes(int &NumCodes) { NumCodes = numCodes; return numCodes ? codes : NULL; } + }; + +class cDiseqcs : public cConfig { +public: + cDiseqc *Get(int Source, int Frequency, char Polarization); + }; + +extern cDiseqcs Diseqcs; + +#endif //__DISEQC_H diff --git a/dvbdevice.c b/dvbdevice.c index f337e357..eeaa7b07 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.21 2002/09/29 13:53:26 kls Exp $ + * $Id: dvbdevice.c 1.22 2002/10/06 09:07:45 kls Exp $ */ #include "dvbdevice.h" @@ -31,6 +31,8 @@ extern "C" { #endif #include #include +#include "channels.h" +#include "diseqc.h" #include "dvbosd.h" #include "player.h" #include "receiver.h" @@ -124,7 +126,9 @@ cDvbDevice::cDvbDevice(int n) else esyslog("ERROR: can't open DVB device %d", n); - frequency = 0; + source = -1; + frequency = -1; + diseqcCommands = NULL; } cDvbDevice::~cDvbDevice() @@ -344,18 +348,33 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On) return true; } +bool cDvbDevice::IsTunedTo(const cChannel *Channel) const +{ + return source == Channel->Source() && frequency == Channel->Frequency(); +} + +bool cDvbDevice::ProvidesSource(int Source) const +{ + int type = Source & cSource::st_Mask; + return type == cSource::stNone + || type == cSource::stCable && frontendType == FE_QAM + || type == cSource::stSat && frontendType == FE_QPSK + || type == cSource::stTerr && frontendType == FE_OFDM; + return true; +} + bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const { bool result = false; bool hasPriority = Priority < 0 || Priority > this->Priority(); bool needsDetachReceivers = true; - if (ProvidesCa(Channel->ca)) { + if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) { if (Receiving()) { - if (frequency == Channel->frequency) { + if (IsTunedTo(Channel)) { needsDetachReceivers = false; - if (!HasPid(Channel->vpid)) { - if (Channel->ca > CACONFBASE) { + if (!HasPid(Channel->Vpid())) { + if (Channel->Ca() > CACONFBASE) { needsDetachReceivers = true; result = hasPriority; } @@ -394,24 +413,24 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) LiveView = true; #endif - bool DoTune = frequency != Channel->frequency; // TODO will be changed when DiSEqC handling is revised + bool DoTune = !IsTunedTo(Channel); bool TurnOffLivePIDs = HasDecoder() && (DoTune - || Channel->ca > CACONFBASE && pidHandles[ptVideo].pid != Channel->vpid // CA channels can only be decrypted in "live" mode + || Channel->Ca() > CACONFBASE && pidHandles[ptVideo].pid != Channel->Vpid() // CA channels can only be decrypted in "live" mode || IsPrimaryDevice() && (LiveView // for a new live view the old PIDs need to be turned off - || pidHandles[ptVideo].pid == Channel->vpid // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + || pidHandles[ptVideo].pid == Channel->Vpid() // for recording the PIDs must be shifted from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ) ); bool StartTransferMode = IsPrimaryDevice() && !DoTune - && (LiveView && HasPid(Channel->vpid) && pidHandles[ptVideo].pid != Channel->vpid // the PID is already set as DMX_PES_OTHER - || !LiveView && pidHandles[ptVideo].pid == Channel->vpid // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER + && (LiveView && HasPid(Channel->Vpid()) && pidHandles[ptVideo].pid != Channel->Vpid() // the PID is already set as DMX_PES_OTHER + || !LiveView && pidHandles[ptVideo].pid == Channel->Vpid() // a recording is going to shift the PIDs from DMX_PES_AUDIO/VIDEO to DMX_PES_OTHER ); bool TurnOnLivePIDs = HasDecoder() && !StartTransferMode - && (Channel->ca > CACONFBASE // CA channels can only be decrypted in "live" mode + && (Channel->Ca() > CACONFBASE // CA channels can only be decrypted in "live" mode || LiveView ); @@ -452,67 +471,127 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) switch (frontendType) { case FE_QPSK: { // DVB-S - // Frequency offsets: + unsigned int frequency = Channel->Frequency(); - unsigned int freq = Channel->frequency; - int tone = SEC_TONE_OFF; + if (Setup.DiSEqC) { + cDiseqc *diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization()); + if (diseqc) { + if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) { +#ifndef NEWSTRUCT + int SecTone = SEC_TONE_OFF; + int SecVolt = SEC_VOLTAGE_13; +#endif + cDiseqc::eDiseqcActions da; + for (bool Start = true; (da = diseqc->Execute(Start)) != cDiseqc::daNone; Start = false) { + switch (da) { +#ifdef NEWSTRUCT + case cDiseqc::daNone: break; + case cDiseqc::daToneOff: CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); break; + case cDiseqc::daToneOn: CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_ON)); break; + case cDiseqc::daVoltage13: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); break; + case cDiseqc::daVoltage18: CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_18)); break; + case cDiseqc::daMiniA: CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_A)); break; + case cDiseqc::daMiniB: CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, SEC_MINI_B)); break; + case cDiseqc::daCodes: { + int n = 0; + uchar *codes = diseqc->Codes(n); + if (codes) { + struct dvb_diseqc_master_cmd cmd; + memcpy(cmd.msg, codes, min(n, int(sizeof(cmd.msg)))); + cmd.msg_len = n; + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); + } + } + break; +#else + // This may not work very good with the old driver. + // Let's try to emulate the NEWSTRUCT driver's behaviour as good as possible... + case cDiseqc::daNone: break; + case cDiseqc::daToneOff: CHECK(ioctl(fd_sec, SEC_SET_TONE, SecTone = SEC_TONE_OFF)); break; + case cDiseqc::daToneOn: CHECK(ioctl(fd_sec, SEC_SET_TONE, SecTone = SEC_TONE_ON)); break; + case cDiseqc::daVoltage13: CHECK(ioctl(fd_sec, SEC_SET_VOLTAGE, SecVolt = SEC_VOLTAGE_13)); break; + case cDiseqc::daVoltage18: CHECK(ioctl(fd_sec, SEC_SET_VOLTAGE, SecVolt = SEC_VOLTAGE_18)); break; + case cDiseqc::daMiniA: + case cDiseqc::daMiniB: { + secCmdSequence scmds; + memset(&scmds, 0, sizeof(scmds)); + scmds.voltage = SecVolt; + scmds.miniCommand = (da == cDiseqc::daMiniA) ? SEC_MINI_A : SEC_MINI_B; + scmds.continuousTone = SecTone; + CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); + } + break; + case cDiseqc::daCodes: { + int n = 0; + uchar *codes = diseqc->Codes(n); + if (codes && n >= 3 && codes[0] == 0xE0) { + secCommand scmd; + memset(&scmd, 0, sizeof(scmd)); + scmd.type = SEC_CMDTYPE_DISEQC; + scmd.u.diseqc.addr = codes[1]; + scmd.u.diseqc.cmd = codes[2]; + scmd.u.diseqc.numParams = n - 3; + memcpy(scmd.u.diseqc.params, &codes[3], min(n - 3, int(sizeof(scmd.u.diseqc.params)))); + + secCmdSequence scmds; + memset(&scmds, 0, sizeof(scmds)); + scmds.voltage = SecVolt; + scmds.miniCommand = SEC_MINI_NONE; + scmds.continuousTone = SecTone; + scmds.numCommands = 1; + scmds.commands = &scmd; - if (freq < (unsigned int)Setup.LnbSLOF) { - freq -= Setup.LnbFrequLo; - tone = SEC_TONE_OFF; + CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); + } + } + break; +#endif + } + } + diseqcCommands = diseqc->Commands(); + } + frequency -= diseqc->Lof(); + } + else { + esyslog("ERROR: no DiSEqC parameters found for channel %d", Channel->Number()); + return false; + } } else { - freq -= Setup.LnbFrequHi; - tone = SEC_TONE_ON; - } + int tone = SEC_TONE_OFF; + if (frequency < (unsigned int)Setup.LnbSLOF) { + frequency -= Setup.LnbFrequLo; + tone = SEC_TONE_OFF; + } + else { + frequency -= Setup.LnbFrequHi; + tone = SEC_TONE_ON; + } + int volt = (Channel->Polarization() == 'v' || Channel->Polarization() == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; #ifdef NEWSTRUCT - Frontend.frequency = freq * 1000UL; - Frontend.inversion = INVERSION_AUTO; - Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL; - Frontend.u.qpsk.fec_inner = FEC_AUTO; + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)); + CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)); #else - Frontend.Frequency = freq * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL; - Frontend.u.qpsk.FEC_inner = FEC_AUTO; + secCmdSequence scmds; + memset(&scmds, 0, sizeof(scmds)); + scmds.voltage = volt; + scmds.miniCommand = SEC_MINI_NONE; + scmds.continuousTone = tone; + CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); #endif - - int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; - - // DiSEqC: + } #ifdef NEWSTRUCT - struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4}; - cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0)); - - if (Setup.DiSEqC) - CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); - CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)); - if (Setup.DiSEqC) { - usleep(15 * 1000); - CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); - usleep(15 * 1000); - CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A)); - usleep(15 * 1000); - } - CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)); + Frontend.frequency = frequency * 1000UL; + Frontend.inversion = SpectralInversion(Channel->Inversion()); + Frontend.u.qpsk.symbol_rate = Channel->Srate() * 1000UL; + Frontend.u.qpsk.fec_inner = CodeRate(Channel->CoderateH()); #else - secCommand scmd; - scmd.type = 0; - scmd.u.diseqc.addr = 0x10; - scmd.u.diseqc.cmd = 0x38; - scmd.u.diseqc.numParams = 1; - scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); - - secCmdSequence scmds; - scmds.voltage = volt; - scmds.miniCommand = SEC_MINI_NONE; - scmds.continuousTone = tone; - scmds.numCommands = Setup.DiSEqC ? 1 : 0; - scmds.commands = &scmd; - - CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); + Frontend.Frequency = frequency * 1000UL; + Frontend.Inversion = SpectralInversion(Channel->Inversion()); + Frontend.u.qpsk.SymbolRate = Channel->Srate() * 1000UL; + Frontend.u.qpsk.FEC_inner = CodeRate(Channel->CoderateH()); #endif } break; @@ -521,17 +600,17 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) // Frequency and symbol rate: #ifdef NEWSTRUCT - Frontend.frequency = Channel->frequency * 1000000UL; - Frontend.inversion = INVERSION_AUTO; - Frontend.u.qam.symbol_rate = Channel->srate * 1000UL; - Frontend.u.qam.fec_inner = FEC_AUTO; - Frontend.u.qam.modulation = QAM_64; + Frontend.frequency = Channel->Frequency() * 1000000UL; + Frontend.inversion = SpectralInversion(Channel->Inversion()); + Frontend.u.qam.symbol_rate = Channel->Srate() * 1000UL; + Frontend.u.qam.fec_inner = CodeRate(Channel->CoderateH()); + Frontend.u.qam.modulation = Modulation(Channel->Modulation()); #else - Frontend.Frequency = Channel->frequency * 1000000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.qam.SymbolRate = Channel->srate * 1000UL; - Frontend.u.qam.FEC_inner = FEC_AUTO; - Frontend.u.qam.QAM = QAM_64; + Frontend.Frequency = Channel->Frequency() * 1000000UL; + Frontend.Inversion = SpectralInversion(Channel->Inversion()); + Frontend.u.qam.SymbolRate = Channel->Srate() * 1000UL; + Frontend.u.qam.FEC_inner = CodeRate(Channel->CoderateH()); + Frontend.u.qam.QAM = Modulation(Channel->Modulation()); #endif } break; @@ -540,25 +619,25 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) // Frequency and OFDM paramaters: #ifdef NEWSTRUCT - Frontend.frequency = Channel->frequency * 1000UL; - Frontend.inversion = INVERSION_AUTO; - Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ; - Frontend.u.ofdm.code_rate_HP = FEC_2_3; - Frontend.u.ofdm.code_rate_LP = FEC_1_2; - Frontend.u.ofdm.constellation = QAM_64; - Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE; + Frontend.frequency = Channel->Frequency() * 1000UL; + Frontend.inversion = SpectralInversion(Channel->Inversion()); + Frontend.u.ofdm.bandwidth = BandWidth(Channel->Bandwidth()); + Frontend.u.ofdm.code_rate_HP = CodeRate(Channel->CoderateH()); + Frontend.u.ofdm.code_rate_LP = CodeRate(Channel->CoderateL()); + Frontend.u.ofdm.constellation = Modulation(Channel->Modulation()); + Frontend.u.ofdm.transmission_mode = TransmitMode(Channel->Transmission()); + Frontend.u.ofdm.guard_interval = GuardInterval(Channel->Guard()); + Frontend.u.ofdm.hierarchy_information = Hierarchy(Channel->Hierarchy()); #else - Frontend.Frequency = Channel->frequency * 1000UL; - Frontend.Inversion = INVERSION_AUTO; - Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; - Frontend.u.ofdm.HP_CodeRate=FEC_2_3; - Frontend.u.ofdm.LP_CodeRate=FEC_1_2; - Frontend.u.ofdm.Constellation=QAM_64; - Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; - Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; - Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; + Frontend.Frequency = Channel->Frequency() * 1000UL; + Frontend.Inversion = SpectralInversion(Channel->Inversion()); + Frontend.u.ofdm.bandWidth = BandWidth(Channel->Bandwidth()); + Frontend.u.ofdm.HP_CodeRate = CodeRate(Channel->CoderateH()); + Frontend.u.ofdm.LP_CodeRate = CodeRate(Channel->CoderateL()); + Frontend.u.ofdm.Constellation = Modulation(Channel->Modulation()); + Frontend.u.ofdm.TransmissionMode = TransmitMode(Channel->Transmission()); + Frontend.u.ofdm.guardInterval = GuardInterval(Channel->Guard()); + Frontend.u.ofdm.HierarchyInformation = Hierarchy(Channel->Hierarchy()); #endif } break; @@ -592,7 +671,7 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) usleep(10 * 1000); } if (!(status & FE_HAS_LOCK)) { - esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1); + esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->Number(), CardIndex() + 1); if (LiveView && IsPrimaryDevice()) cThread::RaisePanic(); return false; @@ -602,43 +681,44 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) FrontendEvent event; if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 0) { if (event.type != FE_COMPLETION_EV) { - esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1); + esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->Number(), CardIndex() + 1); if (LiveView && IsPrimaryDevice()) cThread::RaisePanic(); return false; } } else - esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1); + esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->Number(), CardIndex() + 1); } else esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1); #endif - frequency = Channel->frequency; + source = Channel->Source(); + frequency = Channel->Frequency(); } // PID settings: if (TurnOnLivePIDs) { - if (!(AddPid(Channel->apid1, ptAudio) && AddPid(Channel->vpid, ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached) - esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->number, CardIndex() + 1); + if (!(AddPid(Channel->Apid1(), ptAudio) && AddPid(Channel->Vpid(), ptVideo))) {//XXX+ dolby dpid1!!! (if audio plugins are attached) + esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1); return false; } if (IsPrimaryDevice()) - AddPid(Channel->tpid, ptTeletext); + AddPid(Channel->Tpid(), ptTeletext); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); } else if (StartTransferMode) - cControl::Launch(new cTransferControl(this, Channel->vpid, Channel->apid1, 0, 0, 0)); + cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid1(), 0, 0, 0)); // Start setting system time: if (siProcessor) - siProcessor->SetCurrentTransponder(Channel->frequency); + siProcessor->SetCurrentTransponder(Channel->Frequency()); return true; } diff --git a/dvbdevice.h b/dvbdevice.h index acf569e0..df7aa035 100644 --- a/dvbdevice.h +++ b/dvbdevice.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.h 1.11 2002/09/28 12:21:36 kls Exp $ + * $Id: dvbdevice.h 1.12 2002/10/06 08:57:24 kls Exp $ */ #ifndef __DVBDEVICE_H @@ -61,8 +61,12 @@ public: // Channel facilities private: + int source; int frequency; + const char *diseqcCommands; + bool IsTunedTo(const cChannel *Channel) const; public: + virtual bool ProvidesSource(int Source) const; virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const; protected: virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); diff --git a/eit.c b/eit.c index 1e699300..444cf47c 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.52 2002/09/20 16:24:17 kls Exp $ + * $Id: eit.c 1.53 2002/10/05 13:44:23 kls Exp $ ***************************************************************************/ #include "eit.h" @@ -40,6 +40,7 @@ #include #include #include +#include "channels.h" #include "config.h" #include "libdtv/libdtv.h" #include "videodir.h" @@ -456,7 +457,7 @@ static void ReportEpgBugFixStats(bool Reset = false) for (int c = 0; c < p->n; c++) { cChannel *channel = Channels.GetByServiceID(p->serviceIDs[c]); if (channel) { - q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->name); + q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->Name()); delim = ", "; } } @@ -768,7 +769,7 @@ void cSchedule::Dump(FILE *f, const char *Prefix) const cChannel *channel = Channels.GetByServiceID(uServiceID); if (channel) { - fprintf(f, "%sC %u %s\n", Prefix, uServiceID, channel->name); + fprintf(f, "%sC %u %s\n", Prefix, uServiceID, channel->Name()); for (cEventInfo *p = Events.First(); p; p = Events.Next(p)) p->Dump(f, Prefix); fprintf(f, "%sc\n", Prefix); diff --git a/eitscan.c b/eitscan.c index 069a133d..c29b6b57 100644 --- a/eitscan.c +++ b/eitscan.c @@ -4,11 +4,12 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: eitscan.c 1.7 2002/09/08 11:08:52 kls Exp $ + * $Id: eitscan.c 1.8 2002/10/05 13:44:35 kls Exp $ */ #include "eitscan.h" #include +#include "channels.h" #include "dvbdevice.h" cEITScanner::cEITScanner(void) @@ -28,11 +29,11 @@ cEITScanner::~cEITScanner() bool cEITScanner::TransponderScanned(cChannel *Channel) { for (int i = 0; i < numTransponders; i++) { - if (transponders[i] == Channel->frequency) + if (transponders[i] == Channel->Frequency()) return true; } transponders = (int *)realloc(transponders, ++numTransponders * sizeof(int)); - transponders[numTransponders - 1] = Channel->frequency; + transponders[numTransponders - 1] = Channel->Frequency(); return false; } @@ -66,7 +67,7 @@ void cEITScanner::Process(void) if (Channel) { if (!Device->ProvidesChannel(Channel)) break; - if (Channel->pnr && !TransponderScanned(Channel)) { + if (Channel->Sid() && !TransponderScanned(Channel)) { if (Device == cDevice::PrimaryDevice() && !currentChannel) currentChannel = Device->CurrentChannel(); Device->SwitchChannel(Channel, false); diff --git a/i18n.c b/i18n.c index 81b77178..b814179e 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.93 2002/09/29 12:32:46 kls Exp $ + * $Id: i18n.c 1.94 2002/10/06 09:55:08 kls Exp $ * * Translations provided by: * @@ -890,21 +890,21 @@ const tI18nPhrase Phrases[] = { "Polarizare", "Polarizáció", }, - { "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", - "DiSEqC", + { "Source", + "Quelle", + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO + "",//TODO }, { "Srate", "Srate", @@ -1034,21 +1034,149 @@ const tI18nPhrase Phrases[] = { "Criptare", "CA", }, - { "Pnr", - "Pnr", - "Pnr", - "Pnr", - "Pnr", - "Núm. Progr.", - "Num. Progr.", - "Program Id", - "Ohjelmatunnus", - "Pnr", - "Pnr", - "Pnr", - "Pnr", - "Nr. Prog.", - "Pnr", + { "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + "Sid", + }, + { "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + "Inversion", + }, + { "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + "Bandwidth", + }, + { "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + "CoderateH", + }, + { "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + "CoderateL", + }, + { "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + "Modulation", + }, + { "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + "Transmission", + }, + { "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + "Guard", + }, + { "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", + "Hierarchy", }, // Timer parameters: { "Active", @@ -2723,6 +2851,54 @@ const tI18nPhrase Phrases[] = { "nu", "nem", }, + { "off", + "aus", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, + { "none", + "keine", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, + { "auto", + "auto", + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + "",// TODO + }, { "top", "oben", "zgoraj", diff --git a/menu.c b/menu.c index eaf260f4..8cce5357 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.209 2002/09/29 12:50:47 kls Exp $ + * $Id: menu.c 1.210 2002/10/06 09:52:52 kls Exp $ */ #include "menu.h" @@ -13,6 +13,7 @@ #include #include #include +#include "channels.h" #include "config.h" #include "cutter.h" #include "eit.h" @@ -21,6 +22,7 @@ #include "plugin.h" #include "recording.h" #include "remote.h" +#include "sources.h" #include "status.h" #include "videodir.h" @@ -53,7 +55,7 @@ void cMenuEditChanItem::Set(void) char buf[255]; cChannel *channel = Channels.GetByNumber(*value); if (channel) - snprintf(buf, sizeof(buf), "%d %s", *value, channel->name); + snprintf(buf, sizeof(buf), "%d %s", *value, channel->Name()); else *buf = 0; SetValue(buf); @@ -77,8 +79,8 @@ cMenuEditTranItem::cMenuEditTranItem(const char *Name, int *Value) transponder = *Value; cChannel *channel = Channels.First(); while (channel) { - if (!channel->groupSep && ISTRANSPONDER(channel->frequency, *Value)) { - number = channel->number; + if (!channel->GroupSep() && ISTRANSPONDER(channel->Frequency(), *Value)) { + number = channel->Number(); break; } channel = (cChannel *)channel->Next(); @@ -95,7 +97,7 @@ eOSState cMenuEditTranItem::ProcessKey(eKeys Key) number = *value; cChannel *channel = Channels.GetByNumber(*value); if (channel) - transponder = channel->frequency; + transponder = channel->Frequency(); *value = transponder; return state; } @@ -391,12 +393,137 @@ eOSState cMenuEditCaItem::ProcessKey(eKeys Key) return state; } +// --- cMenuEditSrcItem ------------------------------------------------------ + +class cMenuEditSrcItem : public cMenuEditIntItem { +private: + const cSource *source; +protected: + virtual void Set(void); +public: + cMenuEditSrcItem(const char *Name, int *Value); + eOSState ProcessKey(eKeys Key); + }; + +cMenuEditSrcItem::cMenuEditSrcItem(const char *Name, int *Value) +:cMenuEditIntItem(Name, Value, 0) +{ + source = Sources.Get(*Value); + Set(); +} + +void cMenuEditSrcItem::Set(void) +{ + if (source) { + char *buffer = NULL; + asprintf(&buffer, "%s - %s", cSource::ToString(source->Code()), source->Description()); + SetValue(buffer); + free(buffer); + } + else + cMenuEditIntItem::Set(); +} + +eOSState cMenuEditSrcItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + + if (state == osUnknown) { + if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? + if (source && source->Prev()) { + source = (cSource *)source->Prev(); + *value = source->Code(); + } + } + else if (NORMALKEY(Key) == kRight) { + if (source) { + if (source->Next()) + source = (cSource *)source->Next(); + } + else + source = Sources.First(); + if (source) + *value = source->Code(); + } + else + return state; // we don't call cMenuEditIntItem::ProcessKey(Key) here since we don't accept numerical input + Set(); + state = osContinue; + } + return state; +} + +// --- cMenuEditMapItem ------------------------------------------------------ + +class cMenuEditMapItem : public cMenuEditItem { +protected: + int *value; + const tChannelParameterMap *map; + const char *zeroString; + virtual void Set(void); +public: + cMenuEditMapItem(const char *Name, int *Value, const tChannelParameterMap *Map, const char *ZeroString = NULL); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuEditMapItem::cMenuEditMapItem(const char *Name, int *Value, const tChannelParameterMap *Map, const char *ZeroString) +:cMenuEditItem(Name) +{ + value = Value; + map = Map; + zeroString = ZeroString; + Set(); +} + +void cMenuEditMapItem::Set(void) +{ + int n = MapToUser(*value, map); + if (n == 999) + SetValue(tr("auto")); + else if (n == 0 && zeroString) + SetValue(zeroString); + else if (n >= 0) { + char buf[16]; + snprintf(buf, sizeof(buf), "%d", n); + SetValue(buf); + } + else + SetValue("???"); +} + +eOSState cMenuEditMapItem::ProcessKey(eKeys Key) +{ + eOSState state = cMenuEditItem::ProcessKey(Key); + + if (state == osUnknown) { + int newValue = *value; + int n = DriverIndex(*value, map); + if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly? + if (n-- > 0) + newValue = map[n].driverValue; + } + else if (NORMALKEY(Key) == kRight) { + if (map[++n].userValue >= 0) + newValue = map[n].driverValue; + } + else + return state; + if (newValue != *value) { + *value = newValue; + Set(); + } + state = osContinue; + } + return state; +} + // --- cMenuEditChannel ------------------------------------------------------ class cMenuEditChannel : public cOsdMenu { private: cChannel *channel; cChannel data; + void Setup(void); public: cMenuEditChannel(int Index); virtual eOSState ProcessKey(eKeys Key); @@ -408,24 +535,49 @@ cMenuEditChannel::cMenuEditChannel(int Index) channel = Channels.Get(Index); if (channel) { data = *channel; - Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), tr(FileNameChars))); - Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); - Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); - Add(new cMenuEditIntItem( tr("DiSEqC"), &data.diseqc, 0, 10)); //TODO exact limits??? - Add(new cMenuEditIntItem( tr("Srate"), &data.srate)); - Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF)); - Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0x1FFF)); - Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0x1FFF)); - Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF)); - Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF)); - Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); - Add(new cMenuEditCaItem( tr("CA"), &data.ca, true)); - Add(new cMenuEditIntItem( tr("Pnr"), &data.pnr, 0)); + Setup(); } } +void cMenuEditChannel::Setup(void) +{ + int current = Current(); + char type = *cSource::ToString(data.source); +#define ST(s) if (strchr(s, type)) + + Clear(); + + // Parameters for all types of sources: + Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), tr(FileNameChars))); + Add(new cMenuEditSrcItem( tr("Source"), &data.source)); + Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency)); + Add(new cMenuEditIntItem( tr("Vpid"), &data.vpid, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Apid1"), &data.apid1, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Apid2"), &data.apid2, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Dpid1"), &data.dpid1, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Dpid2"), &data.dpid2, 0, 0x1FFF)); + Add(new cMenuEditIntItem( tr("Tpid"), &data.tpid, 0, 0x1FFF)); + Add(new cMenuEditCaItem( tr("CA"), &data.ca, true)); + Add(new cMenuEditIntItem( tr("Sid"), &data.sid, 0)); + // Parameters for specific types of sources: + ST(" S ") Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv")); + ST("CS ") Add(new cMenuEditIntItem( tr("Srate"), &data.srate)); + ST("CST") Add(new cMenuEditMapItem( tr("Inversion"), &data.inversion, InversionValues, tr("off"))); + ST("CST") Add(new cMenuEditMapItem( tr("CoderateH"), &data.coderateH, CoderateValues, tr("none"))); + ST(" T") Add(new cMenuEditMapItem( tr("CoderateL"), &data.coderateL, CoderateValues, tr("none"))); + ST("C T") Add(new cMenuEditMapItem( tr("Modulation"), &data.modulation, ModulationValues, "QPSK")); + ST(" T") Add(new cMenuEditMapItem( tr("Bandwidth"), &data.bandwidth, BandwidthValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Transmission"), &data.transmission, TransmissionValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Guard"), &data.guard, GuardValues)); + ST(" T") Add(new cMenuEditMapItem( tr("Hierarchy"), &data.hierarchy, HierarchyValues, tr("none"))); + + SetCurrent(Get(current)); + Display(); +} + eOSState cMenuEditChannel::ProcessKey(eKeys Key) { + int oldSource = data.source; eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { @@ -436,6 +588,8 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key) state = osBack; } } + if (Key != kNone && (data.source & cSource::st_Mask) != (oldSource & cSource::st_Mask)) + Setup(); return state; } @@ -455,7 +609,7 @@ cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) { index = Index; channel = Channel; - if (channel->groupSep) + if (channel->GroupSep()) SetColor(clrCyan, clrBackground); Set(); } @@ -463,10 +617,10 @@ cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel) void cMenuChannelItem::Set(void) { char *buffer = NULL; - if (!channel->groupSep) - asprintf(&buffer, "%d\t%s", channel->number, channel->name ); + if (!channel->GroupSep()) + asprintf(&buffer, "%d\t%s", channel->Number(), channel->Name()); else - asprintf(&buffer, "---\t%s ----------------------------------------------------------------", channel->name); + asprintf(&buffer, "---\t%s ----------------------------------------------------------------", channel->Name()); SetText(buffer, false); } @@ -530,7 +684,7 @@ eOSState cMenuChannels::New(void) Channels.ReNumber(); Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true); Channels.Save(); - isyslog("channel %d added", channel->number); + isyslog("channel %d added", channel->Number()); return AddSubMenu(new cMenuEditChannel(Current())); } @@ -539,7 +693,7 @@ eOSState cMenuChannels::Del(void) if (Count() > 0) { int Index = Current(); cChannel *channel = Channels.Get(Index); - int DeletedChannel = channel->number; + int DeletedChannel = channel->Number(); // Check if there is a timer using this channel: for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) { if (ti->channel == DeletedChannel) { @@ -578,8 +732,8 @@ eOSState cMenuChannels::Del(void) void cMenuChannels::Move(int From, int To) { - int FromNumber = Channels.Get(From)->number; - int ToNumber = Channels.Get(To)->number; + int FromNumber = Channels.Get(From)->Number(); + int ToNumber = Channels.Get(To)->Number(); // Move and renumber the channels: Channels.Move(From, To); Channels.ReNumber(); @@ -933,7 +1087,7 @@ cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID()); if (channel) { char *buffer; - asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); + asprintf(&buffer, "%-17.*s\t%.*s %s - %s", 17, channel->Name(), 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); SetTitle(buffer, false); free(buffer); int Line = 2; @@ -984,7 +1138,7 @@ cMenuWhatsOnItem::cMenuWhatsOnItem(const cEventInfo *EventInfo) eventInfo = EventInfo; char *buffer = NULL; cChannel *channel = Channels.GetByNumber(eventInfo->GetChannelNumber()); - asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", eventInfo->GetChannelNumber(), 6, channel ? channel->name : "???", 5, eventInfo->GetTimeString(), eventInfo->GetTitle()); + asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", eventInfo->GetChannelNumber(), 6, channel ? channel->Name() : "???", 5, eventInfo->GetTimeString(), eventInfo->GetTitle()); SetText(buffer, false); } @@ -1026,7 +1180,7 @@ cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentCha if (pArray[num]) { cChannel *channel = Channels.GetByServiceID(pArray[num]->GetServiceID()); if (channel) { - pArray[num]->SetChannelNumber(channel->number); + pArray[num]->SetChannelNumber(channel->Number()); num++; } } @@ -1149,7 +1303,7 @@ cMenuSchedule::cMenuSchedule(void) otherChannel = 0; cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel()); if (channel) { - cMenuWhatsOn::SetCurrentChannel(channel->number); + cMenuWhatsOn::SetCurrentChannel(channel->Number()); schedules = cSIProcessor::Schedules(mutexLock); PrepareSchedule(channel); SetHelp(tr("Record"), tr("Now"), tr("Next")); @@ -1170,11 +1324,11 @@ void cMenuSchedule::PrepareSchedule(cChannel *Channel) { Clear(); char *buffer = NULL; - asprintf(&buffer, tr("Schedule - %s"), Channel->name); + asprintf(&buffer, tr("Schedule - %s"), Channel->Name()); SetTitle(buffer); free(buffer); if (schedules) { - const cSchedule *Schedule = Channel->pnr ? schedules->GetSchedule(Channel->pnr) : schedules->GetSchedule(); + const cSchedule *Schedule = Channel->Sid() ? schedules->GetSchedule(Channel->Sid()) : schedules->GetSchedule(); int num = Schedule->NumEvents(); const cEventInfo **pArray = MALLOC(const cEventInfo *, num); if (pArray) { @@ -1238,7 +1392,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) if (Count()) { cChannel *channel = Channels.GetByServiceID(((cMenuScheduleItem *)Get(Current()))->eventInfo->GetServiceID()); if (channel) - ChannelNr = channel->number; + ChannelNr = channel->Number(); } now = true; return AddSubMenu(new cMenuWhatsOn(schedules, true, ChannelNr)); @@ -1266,8 +1420,8 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) cChannel *channel = Channels.GetByServiceID(ei->GetServiceID()); if (channel) { PrepareSchedule(channel); - if (channel->number != cDevice::CurrentChannel()) { - otherChannel = channel->number; + if (channel->Number() != cDevice::CurrentChannel()) { + otherChannel = channel->Number(); SetHelp(tr("Record"), tr("Now"), tr("Next"), tr("Switch")); } Display(); @@ -1636,17 +1790,44 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key) // --- cMenuSetupLNB --------------------------------------------------------- class cMenuSetupLNB : public cMenuSetupBase { +private: + void Setup(void); public: cMenuSetupLNB(void); + virtual eOSState ProcessKey(eKeys Key); }; cMenuSetupLNB::cMenuSetupLNB(void) { SetSection(tr("LNB")); - Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); - Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo)); - Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi)); + Setup(); +} + +void cMenuSetupLNB::Setup(void) +{ + int current = Current(); + + Clear(); + Add(new cMenuEditBoolItem(tr("Setup.LNB$Use DiSEqC"), &data.DiSEqC)); + if (!data.DiSEqC) { + Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); + Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo)); + Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi)); + } + + SetCurrent(Get(current)); + Display(); +} + +eOSState cMenuSetupLNB::ProcessKey(eKeys Key) +{ + int oldDiSEqC = data.DiSEqC; + eOSState state = cMenuSetupBase::ProcessKey(Key); + + if (Key != kNone && data.DiSEqC != oldDiSEqC) + Setup(); + return state; } // --- cMenuSetupCICAM ------------------------------------------------------- @@ -2152,10 +2333,10 @@ void cDisplayChannel::DisplayChannel(const cChannel *Channel) { int BufSize = Width() + 1; char buffer[BufSize]; - if (Channel && Channel->number > 0) - snprintf(buffer, BufSize, "%d%s %s", Channel->number, number ? "-" : "", Channel->name); + if (Channel && Channel->Number() > 0) + snprintf(buffer, BufSize, "%d%s %s", Channel->Number(), number ? "-" : "", Channel->Name()); else - snprintf(buffer, BufSize, "%s", Channel ? Channel->name : tr("*** Invalid Channel ***")); + snprintf(buffer, BufSize, "%s", Channel ? Channel->Name() : tr("*** Invalid Channel ***")); Interface->Fill(0, 0, Setup.OSDwidth, 1, clrBackground); Interface->Write(0, 0, buffer); const char *date = DayDateTime(); @@ -2266,7 +2447,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) if (channel) { Interface->Clear(); DisplayChannel(channel); - if (!channel->groupSep) + if (!channel->GroupSep()) group = -1; } } @@ -2283,7 +2464,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) //XXX case kGreen: return osEventNow; //XXX case kYellow: return osEventNext; case kOk: if (group >= 0) - Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(group))->number); + Channels.SwitchTo(Channels.Get(Channels.GetNextNormal(group))->Number()); return osEnd; default: if (NORMALKEY(Key) == kUp || NORMALKEY(Key) == kDown || (Key & (k_Repeat | k_Release)) == 0) { cRemote::Put(Key); @@ -2433,7 +2614,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer) fileName = strdup(Recording.FileName()); cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName); cChannel *ch = Channels.GetByNumber(timer->channel); - recorder = new cRecorder(fileName, ch->ca, timer->priority, ch->vpid, ch->apid1, ch->apid2, ch->dpid1, ch->dpid2); + recorder = new cRecorder(fileName, ch->Ca(), timer->priority, ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2()); if (device->AttachReceiver(recorder)) { Recording.WriteSummary(); cStatus::MsgRecording(device, Recording.Name()); @@ -2460,7 +2641,7 @@ bool cRecordControl::GetEventInfo(void) cMutexLock MutexLock; const cSchedules *Schedules = cSIProcessor::Schedules(MutexLock); if (Schedules) { - const cSchedule *Schedule = Schedules->GetSchedule(channel->pnr); + const cSchedule *Schedule = Schedules->GetSchedule(channel->Sid()); if (Schedule) { eventInfo = Schedule->GetEventAround(Time); if (eventInfo) { diff --git a/recording.c b/recording.c index c9234468..544bbbdb 100644 --- a/recording.c +++ b/recording.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: recording.c 1.67 2002/08/24 14:09:49 kls Exp $ + * $Id: recording.c 1.68 2002/10/05 13:44:56 kls Exp $ */ #include "recording.h" @@ -14,6 +14,7 @@ #include #include #include +#include "channels.h" #include "i18n.h" #include "interface.h" #include "remux.h" //XXX+ I_FRAME diff --git a/sources.c b/sources.c new file mode 100644 index 00000000..fc660a5c --- /dev/null +++ b/sources.c @@ -0,0 +1,104 @@ +/* + * sources.c: Source handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: sources.c 1.1 2002/10/06 09:27:10 kls Exp $ + */ + +#include "sources.h" +#include + +// -- cSource ---------------------------------------------------------------- + +cSource::cSource(void) +{ + code = stNone; + description = NULL; +} + +cSource::~cSource() +{ + free(description); +} + +bool cSource::Parse(const char *s) +{ + char *codeBuf = NULL; + if (2 == sscanf(s, "%a[^ ] %a[^\n]", &codeBuf, &description)) + code = FromString(codeBuf); + free(codeBuf); + return code != stNone && description && *description; +} + +const char *cSource::ToString(int Code) +{ + static char buffer[16]; + char *q = buffer; + switch (Code & st_Mask) { + case stCable: *q++ = 'C'; break; + case stSat: *q++ = 'S'; + { + int pos = Code & ~st_Mask; + q += snprintf(q, sizeof(buffer) - 2, "%u.%u", (pos & ~st_Neg) / 10, (pos & ~st_Neg) % 10); // can't simply use "%g" here since the silly 'locale' messes up the decimal point + *q++ = (Code & st_Neg) ? 'E' : 'W'; + } + break; + case stTerr: *q++ = 'T'; break; + default: *q++ = Code + '0'; // backward compatibility + } + *q = 0; + return buffer; +} + +int cSource::FromString(const char *s) +{ + int type = stNone; + switch (toupper(*s)) { + case 'C': type = stCable; break; + case 'S': type = stSat; break; + case 'T': type = stTerr; break; + case '0' ... '9': type = *s - '0'; break; // backward compatibility + default: esyslog("ERROR: unknown source key '%c'", *s); + return stNone; + } + int code = type; + if (type == stSat) { + int pos = 0; + bool dot = false; + bool neg = false; + while (*++s) { + switch (toupper(*s)) { + case '0' ... '9': pos *= 10; + pos += *s - '0'; + break; + case '.': dot = true; + break; + case 'E': neg = true; // fall through to 'W' + case 'W': if (!dot) + pos *= 10; + break; + default: esyslog("ERROR: unknown source character '%c'", *s); + return stNone; + } + } + if (neg) + pos |= st_Neg; + code |= pos; + } + return code; +} + +// -- cSources --------------------------------------------------------------- + +cSources Sources; + +cSource *cSources::Get(int Code) +{ + for (cSource *p = First(); p; p = Next(p)) { + if (p->Code() == Code) + return p; + } + return NULL; +} diff --git a/sources.conf b/sources.conf new file mode 100644 index 00000000..f30e52f7 --- /dev/null +++ b/sources.conf @@ -0,0 +1,50 @@ +# Sources configuration for VDR +# +# Format: +# +# code description +# +# Please contact kls@cadsoft.de before assigning a new code +# to a description, in order to keep them unique. + +# Satellites + +S5E Sirius 2/3 +S7E Eutelsat W3 +S10E Eutelsat W1R +S13E Hotbird 1-5 +S16E Eutelsat W2 +S19.2E Astra 1 +S23.5E Astra 3 +S26E Arabsat 2A/3A +S28.2E Astra 2 +S28.5E Eurobird +S30.E Arabsat 30.5E +S31.3 Türksat 1B +S36E Eutelsat W4 / Sesat +S42E Turksat 1C / Eurasiasat + +S1W Thor 2/3 / Intelsat 707 +S4W Amos 1 +S5W Telecom 2C +S7W Nilesat 101/102 +S8W Atlantic bird 2 / Telecom 2D +S11W Express 3A +S14W Express 2 +S15W Telstar 12 +S18W Intelsat +S21W NSS 803 +S27.W Intelsat 27.5W +S30W Hispasat 1 +S31.5W Intelsat 31.5W +S34.5W Intelsat 34.5W +S37.5W Telstar 11 +S43W PAS + +# Cable + +C Cable + +# Terrestrial + +T Terrestrial diff --git a/sources.h b/sources.h new file mode 100644 index 00000000..65d1bd6e --- /dev/null +++ b/sources.h @@ -0,0 +1,45 @@ +/* + * sources.h: Source handling + * + * See the main source file 'vdr.c' for copyright information and + * how to reach the author. + * + * $Id: sources.h 1.1 2002/10/04 14:25:03 kls Exp $ + */ + +#ifndef __SOURCES_H +#define __SOURCES_H + +#include "config.h" + +class cSource : public cListObject { +public: + enum eSourceType { + stNone = 0x0000, + stCable = 0x4000, + stSat = 0x8000, + stTerr = 0xC000, + st_Mask = 0xC000, + st_Neg = 0x0800, + }; +private: + int code; + char *description; +public: + cSource(void); + ~cSource(); + int Code(void) const { return code; } + const char *Description(void) const { return description; } + bool Parse(const char *s); + static const char *ToString(int Code); + static int FromString(const char *s); + }; + +class cSources : public cConfig { +public: + cSource *Get(int Code); + }; + +extern cSources Sources; + +#endif //__SOURCES_H diff --git a/svdrp.c b/svdrp.c index 325b7dab..81906b48 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.43 2002/09/28 15:50:19 kls Exp $ + * $Id: svdrp.c 1.44 2002/10/05 13:45:05 kls Exp $ */ #include "svdrp.h" @@ -26,6 +26,7 @@ #include #include #include +#include "channels.h" #include "config.h" #include "device.h" #include "keys.h" @@ -412,7 +413,7 @@ void cSVDRP::CmdCHAN(const char *Option) int i = 1; cChannel *channel; while ((channel = Channels.GetByNumber(i)) != NULL) { - if (strcasecmp(channel->name, Option) == 0) { + if (strcasecmp(channel->Name(), Option) == 0) { n = i; break; } @@ -427,7 +428,7 @@ void cSVDRP::CmdCHAN(const char *Option) cChannel *channel = Channels.GetByNumber(n); if (channel) { if (!cDevice::PrimaryDevice()->SwitchChannel(channel, true)) { - Reply(554, "Error switching to channel \"%d\"", channel->number); + Reply(554, "Error switching to channel \"%d\"", channel->Number()); return; } } @@ -441,7 +442,7 @@ void cSVDRP::CmdCHAN(const char *Option) } cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel()); if (channel) - Reply(250, "%d %s", channel->number, channel->name); + Reply(250, "%d %s", channel->Number(), channel->Name()); else Reply(550, "Unable to find channel \"%d\"", cDevice::CurrentChannel()); } @@ -630,7 +631,7 @@ void cSVDRP::CmdLSTC(const char *Option) if (isnumber(Option)) { cChannel *channel = Channels.GetByNumber(strtol(Option, NULL, 10)); if (channel) - Reply(250, "%d %s", channel->number, channel->ToText()); + Reply(250, "%d %s", channel->Number(), channel->ToText()); else Reply(501, "Channel \"%s\" not defined", Option); } @@ -640,9 +641,9 @@ void cSVDRP::CmdLSTC(const char *Option) while (i <= Channels.MaxNumber()) { cChannel *channel = Channels.GetByNumber(i); if (channel) { - if (strcasestr(channel->name, Option)) { + if (strcasestr(channel->Name(), Option)) { if (next) - Reply(-250, "%d %s", next->number, next->ToText()); + Reply(-250, "%d %s", next->Number(), next->ToText()); next = channel; } } @@ -653,7 +654,7 @@ void cSVDRP::CmdLSTC(const char *Option) i++; } if (next) - Reply(250, "%d %s", next->number, next->ToText()); + Reply(250, "%d %s", next->Number(), next->ToText()); else Reply(501, "Channel \"%s\" not defined", Option); } @@ -662,7 +663,7 @@ void cSVDRP::CmdLSTC(const char *Option) for (int i = 1; i <= Channels.MaxNumber(); i++) { cChannel *channel = Channels.GetByNumber(i); if (channel) - Reply(i < Channels.MaxNumber() ? -250 : 250, "%d %s", channel->number, channel->ToText()); + Reply(i < Channels.MaxNumber() ? -250 : 250, "%d %s", channel->Number(), channel->ToText()); else Reply(501, "Channel \"%d\" not found", i); } @@ -778,8 +779,8 @@ void cSVDRP::CmdMODC(const char *Option) } *channel = c; Channels.Save(); - isyslog("channel %d modified", channel->number); - Reply(250, "%d %s", channel->number, channel->ToText()); + isyslog("channel %d modified", channel->Number()); + Reply(250, "%d %s", channel->Number(), channel->ToText()); } else Reply(501, "Channel \"%d\" not defined", n); @@ -844,8 +845,8 @@ void cSVDRP::CmdNEWC(const char *Option) Channels.Add(channel); Channels.ReNumber(); Channels.Save(); - isyslog("channel %d added", channel->number); - Reply(250, "%d %s", channel->number, channel->ToText()); + isyslog("channel %d added", channel->Number()); + Reply(250, "%d %s", channel->Number(), channel->ToText()); } else Reply(501, "Error in channel settings"); diff --git a/vdr.5 b/vdr.5 index 00c58edb..8d6acfbc 100644 --- a/vdr.5 +++ b/vdr.5 @@ -8,7 +8,7 @@ .\" License as specified in the file COPYING that comes with the .\" vdr distribution. .\" -.\" $Id: vdr.5 1.5 2002/09/29 13:06:40 kls Exp $ +.\" $Id: vdr.5 1.6 2002/10/06 08:56:01 kls Exp $ .\" .TH vdr 5 "7 Sep 2002" "1.2.0" "Video Disk Recorder Files" .SH NAME @@ -29,7 +29,7 @@ character, followed by arbitrary text. Example: A \fBchannel definition\fR is a line with channel data, where the fields are separated by ':' characters. Example: -\fBRTL:12188:h:1:27500:163:104:105:0:12003\fR +\fBRTL:12188:h:S19.2E:27500:163:104:105:0:12003\fR The line number of a channel definition (not counting group separators!) defines the channel's number in OSD menus and the \fItimers.conf\fR file. @@ -44,16 +44,44 @@ it has to be replaced by '|'). .B Frequency The transponder frequency in MHz for DVB-S and DVB-C, kHz for DVB-T (as an integer). .TP -.B Polarization -The polarization of the satellite signal. 'h' or 'H' for horizontal, 'v' or 'V' -for vertical (DVB-S only). +.B Parameters +Various parameters, depending on whether this is a DVB-S, DVB-C or DVB-T channel. +Each parameter consist of a key character, followed by an integer number that +represents the actual setting of that parameter. The valid key characters, their +meaning (and allowed values) are +.TS +tab (@); +l l. +\fBB\fR@Bandwidth (6, 7, 8) +\fBC\fR@Code rate high priority (0, 12, 23, 34, 45, 56, 67, 78, 89) +\fBD\fR@Code rate low priority (0, 12, 23, 34, 45, 56, 67, 78, 89) +\fBG\fR@Guard interval (4, 8, 16, 32) +\fBH\fR@Horizontal polarization +\fBI\fR@Inversion (0, 1) +\fBM\fR@Modulation (0, 16, 32, 64, 128, 256) +\fBT\fR@Transmission mode (2, 8) +\fBV\fR@Vertical polarization +\fBY\fR@Hierarchy (0, 1, 2, 4) +.TE +The polarization parameters have no integer numbers following them. This is for +compatibility with files from older versions and also to keep the DVB-S entries +as simple as possible. + +The special value \fB999\fR is used for "automatic", which means the driver +will automatically determine the proper value (if possible). + +An example of a parameter field for a DVB-T channel might look like this: + +\fBB8C23D12M64T2G32Y0\fR .TP -.B -DiSEqC -The DiSEqC code to use for this channel (integer, DVB-S only). +.B Source +The signal source of this channel, as defined in the file \fIsources.conf\fR. +For compatibility with files from older versions numeric values will be accepted +and also written back correctly, but they will have no meaning for the \fBDiSEqC\fR +settings. You should replace the numerical values with the proper source identifiers +defined in \fIsources.conf\fR. .TP -.B -Srate +.B Srate The symbol rate of this channel (DVB-S and DVB-C only). .TP .B VPID @@ -78,8 +106,8 @@ l l. \fB>=100\fR@requires a specific decryption method defined in \fIca.conf\fR .TE .TP -.B PNR -The program number (aka service ID) of this channel. +.B SID +The service ID of this channel. .SS TIMERS The file \fItimers.conf\fR contains the timer setup. Each line contains one timer definition, with individual fields @@ -191,6 +219,69 @@ Arbitrary text that describes the recording made by this timer. Any newline characters in the summary have to be replaced by '|', and the summary may contain ':' characters. If this field is not empty, its contents will be written into the \fIsummary.vdr\fR file of the recording. +.SS SOURCES +The file \fIsources.conf\fR defines the codes to be used in the \fBSource\fR field +of channels in \fIchannels.conf\fR and assigns descriptive texts to them. +Example: + +\fBS19.2E Astra 1\fR + +Anything after (and including) a '#' character is comment. + +The first character of the \fBcode\fR must be one of +.TS +tab (@); +l l. +\fBS\fR@Satellite +\fBC\fR@Cable +\fBT\fR@Terrestrial +.TE +and is followed by further data pertaining to that particular source. In case of +\fBS\fRatellite this is the orbital position in degrees, followed by \fBE\fR for +east or \fBW\fR for west. +.SS DISEQC +The file \fIdiseqc.conf\fR defines the \fBDiSEqC\fR control sequences to be sent +to the DVB-S card in order to access a given satellite position and/or band. +Example: + +\fBS19.2E 11700 V 9750 t v W15 [E0 10 38 F0] W15 A W15 t\fR + +Anything after (and including) a '#' character is comment. + +The first word in a parameter line must be one of the codes defined in the +file \fIsources.conf\fR and tells which satellite this line applies to. + +Following is the "switch frequency" of the LNB (slof), which is the transponder +frequency up to which this entry shall be used; the first entry with an slof greater +than the actual transponder frequency will be used. Typically there is only one slof +per LNB, but the syntax allows any number of frequency ranges to be defined. +Note that there should be a last entry with the value \fB99999\fR for each satellite, +which covers the upper frequency range. + +The third parameter defines the polarization to which this entry applies. It can +be either \fBH\fR for horizontal or \fBV\fR for vertical. + +The fourth parameter specifies the "local oscillator frequency" (lof) of the LNB +to use for the given frequency range. This number will be subtracted from the +actual transponder frequency when tuning to the channel. + +The rest of the line holds the actual sequence of DiSEqC actions to be taken. +The code letters used here are +.TS +tab (@); +l l. +\fBt\fR@22kHz tone off +\fBT\fR@22kHz tone on +\fBv\fR@voltage low (13V) +\fBV\fR@voltage high (18V) +\fBA\fR@mini A +\fBB\fR@mini B +\fBWnn\fR@wait nn milliseconds (nn may be any positive integer number) +\fB[xx ...]\fR@hex code sequence (max. 6) +.TE +There can be any number of actions in a line, including none at all - in which case +the entry would be used only to set the LOF to use for the given frequency range +and polarization. .SS CONDITIONAL ACCESS The file \fIca.conf\fR defines the numbers to be used in the \fBConditional access\fR field of channels in \fIchannels.conf\fR and assigns descriptive texts to them. diff --git a/vdr.c b/vdr.c index fd23ae1e..7e22477b 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.124 2002/09/29 12:55:03 kls Exp $ + * $Id: vdr.c 1.125 2002/10/06 10:25:04 kls Exp $ */ #include @@ -30,9 +30,11 @@ #include #include #include +#include "channels.h" #include "config.h" #include "cutter.h" #include "device.h" +#include "diseqc.h" #include "dvbdevice.h" #include "eitscan.h" #include "i18n.h" @@ -44,6 +46,7 @@ #include "plugin.h" #include "rcu.h" #include "recording.h" +#include "sources.h" #include "tools.h" #include "videodir.h" @@ -311,9 +314,11 @@ int main(int argc, char *argv[]) cPlugin::SetConfigDirectory(ConfigDirectory); Setup.Load(AddDirectory(ConfigDirectory, "setup.conf")); + Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true); + Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true); Channels.Load(AddDirectory(ConfigDirectory, "channels.conf")); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); - Commands.Load(AddDirectory(ConfigDirectory, "commands.conf")); + Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true); SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true); CaDefinitions.Load(AddDirectory(ConfigDirectory, "ca.conf"), true); Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));