diff --git a/CONTRIBUTORS b/CONTRIBUTORS index d00ec5e5..3b7890ea 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2661,6 +2661,7 @@ Stephan Austerm Lars Hanisch for suggesting to assign the source character 'V' to "Analog Video" + for a patch that was used to implement SCR (Satellite Channel Routing) Alex Lasnier for adding tuning support for ATSC devices diff --git a/HISTORY b/HISTORY index 8c005b14..c71afa05 100644 --- a/HISTORY +++ b/HISTORY @@ -6743,8 +6743,15 @@ Video Disk Recorder Revision History extends over TS packet boundaries is now done by locally skipping TS packets in cFrameDetector. -2011-09-10: Version 1.7.22 +2011-09-11: Version 1.7.22 - Fixed scaling subtitles in case the primary device's GetVideoSize() function doesn't return actual values (thanks to Luca Olivetti). - The DiSEqC codes are now copied in the call to cDiseqc::Execute(). +- VDR now supports "Satellite Channel Routing" (SCR) (based on the "unicable" patch + from Lars Hanisch). Since "Unicable" is a registered trademark and stands for only + one of many implementations of SCR, the following changes have been made compared + to the patch, which need to be taken into account by people who have set up their + system using the patch: + - The 'U' parameter in the diseqc.conf file has been changed to 'S' ("Scr"). + - The configuration file name has been changed from "unicable.conf" to "scr.conf". diff --git a/INSTALL b/INSTALL index e69768a7..ea04f1c9 100644 --- a/INSTALL +++ b/INSTALL @@ -386,6 +386,12 @@ accessed using DiSEqC, you have to go to the "Setup" menu and set the "DiSEqC" parameter to "on". You also need to set up the file 'diseqc.conf' to properly access your DiSEqC equipment (see man vdr(5) for details). +A special form of DiSEqC is used to connect several receivers to one signal +source using only a single cable. This method, known as "Satellite Channel Routing" +according to EN50494 (aka "Unicable(TM)", "OLT(TM)", "SatCR", "Single Cable +Distribution", "Channel Stacking System" or "Single Cable Interface") uses +the file "scr.conf" to specify which SCR channels use which user band frequency. + Running VDR with DVB-C (cable) or DVB-T (terrestrial): ------------------------------------------------------ diff --git a/diseqc.c b/diseqc.c index 591d31d8..07529606 100644 --- a/diseqc.c +++ b/diseqc.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: diseqc.c 2.6 2011/09/10 13:38:38 kls Exp $ + * $Id: diseqc.c 2.7 2011/09/11 13:39:48 kls Exp $ */ #include "diseqc.h" @@ -12,6 +12,51 @@ #include "sources.h" #include "thread.h" +// --- cScr ------------------------------------------------------------------ + +cScr::cScr(void) +{ + channel = -1; + userBand = 0; + pin = -1; + used = false; +} + +bool cScr::Parse(const char *s) +{ + bool result = false; + int fields = sscanf(s, "%d %u %d", &channel, &userBand, &pin); + if (fields == 2 || fields == 3) { + if (channel >= 0 && channel < 8) { + result = true; + if (fields == 3 && (pin < 0 || pin > 255)) { + esyslog("Error: invalid SCR pin '%d'", pin); + result = false; + } + } + else + esyslog("Error: invalid SCR channel '%d'", channel); + } + return result; +} + + +// --- cScrs ----------------------------------------------------------------- + +cScrs Scrs; + +cScr *cScrs::GetUnused(void) +{ + cMutexLock MutexLock(&mutex); + for (cScr *p = First(); p; p = Next(p)) { + if (!p->Used()) { + p->SetUsed(true); + return p; + } + } + return NULL; +} + // --- cDiseqc --------------------------------------------------------------- cDiseqc::cDiseqc(void) @@ -21,6 +66,7 @@ cDiseqc::cDiseqc(void) slof = 0; polarization = 0; lof = 0; + scrBank = -1; commands = NULL; parsing = false; } @@ -59,7 +105,7 @@ bool cDiseqc::Parse(const char *s) if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') { parsing = true; const char *CurrentAction = NULL; - while (Execute(&CurrentAction, NULL, NULL) != daNone) + while (Execute(&CurrentAction, NULL, NULL, NULL, NULL) != daNone) ; parsing = false; result = !commands || !*CurrentAction; @@ -74,6 +120,31 @@ bool cDiseqc::Parse(const char *s) return result; } +uint cDiseqc::SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const +{ + uint t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; + if (t < 1024 && Scr->Channel() >= 0 && Scr->Channel() < 8) { + Codes[3] = t >> 8 | (t == 0 ? 0 : scrBank << 2) | Scr->Channel() << 5; + Codes[4] = t; + if (t) + return (t + 350) * 4 - SatFrequency; + } + return 0; +} + +int cDiseqc::SetScrPin(const cScr *Scr, uint8_t *Codes) const +{ + if (Scr->Pin() >= 0 && Scr->Pin() <= 255) { + Codes[2] = 0x5C; + Codes[5] = Scr->Pin(); + return 6; + } + else { + Codes[2] = 0x5A; + return 5; + } +} + const char *cDiseqc::Wait(const char *s) const { char *p = NULL; @@ -88,6 +159,24 @@ const char *cDiseqc::Wait(const char *s) const return NULL; } +const char *cDiseqc::GetScrBank(const char *s) const +{ + char *p = NULL; + errno = 0; + int n = strtol(s, &p, 10); + if (!errno && p != s && n >= 0 && n < 8) { + if (parsing) { + if (scrBank < 0) + scrBank = n; + else + esyslog("ERROR: more than one scr bank in '%s'", s - 1); + } + return p; + } + esyslog("ERROR: more than one scr bank in '%s'", s - 1); + return NULL; +} + const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) const { const char *e = strchr(s, ']'); @@ -129,7 +218,7 @@ const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) co return NULL; } -cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes) const +cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const { if (!*CurrentAction) *CurrentAction = commands; @@ -143,7 +232,16 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Code case 'A': return daMiniA; case 'B': return daMiniB; case 'W': *CurrentAction = Wait(*CurrentAction); break; - case '[': *CurrentAction = GetCodes(*CurrentAction, Codes, MaxCodes); return *CurrentAction ? daCodes : daNone; + case 'S': *CurrentAction = GetScrBank(*CurrentAction); break; + case '[': *CurrentAction = GetCodes(*CurrentAction, Codes, MaxCodes); + if (*CurrentAction) { + if (Scr && Frequency) { + *Frequency = SetScrFrequency(*Frequency, Scr, Codes); + *MaxCodes = SetScrPin(Scr, Codes); + } + return daCodes; + } + break; default: return daNone; } } @@ -154,7 +252,7 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Code cDiseqcs Diseqcs; -const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization) const +const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const { int Devices = 0; for (const cDiseqc *p = First(); p; p = Next(p)) { @@ -164,8 +262,16 @@ const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polariz } if (Devices && !(Devices & (1 << Device - 1))) continue; - if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) + if (p->Source() == Source && p->Slof() > Frequency && p->Polarization() == toupper(Polarization)) { + if (p->IsScr() && Scr && !*Scr) { + *Scr = Scrs.GetUnused(); + if (*Scr) + dsyslog("SCR %d assigned to device %d", (*Scr)->Index(), Device); + else + esyslog("ERROR: no free SCR entry available for device %d", Device); + } return p; + } } return NULL; } diff --git a/diseqc.conf b/diseqc.conf index c9ab3ad3..2895c43e 100644 --- a/diseqc.conf +++ b/diseqc.conf @@ -18,6 +18,7 @@ # V voltage high (18V) # A mini A # B mini B +# Sn Satellite channel routing code sequence for bank n follows # Wnn wait nn milliseconds (nn may be any positive integer number) # [xx ...] hex code sequence (max. 6) # @@ -75,3 +76,15 @@ S13.0E 99999 H 10600 t V W15 [E0 10 38 F7] W15 B W15 T # S19.2E 99999 H 10560 t v # S19.2E 12110 V 11080 t v # S19.2E 99999 V 10720 t v +# +# SCR (Satellite Channel Routing): +# +# S19.2E 11700 V 9750 t V W10 S0 [E0 10 5A 00 00] W10 v +# S19.2E 99999 V 10600 t V W10 S1 [E0 10 5A 00 00] W10 v +# S19.2E 11700 H 9750 t V W10 S2 [E0 10 5A 00 00] W10 v +# S19.2E 99999 H 10600 t V W10 S3 [E0 10 5A 00 00] W10 v +# +# S13.0E 11700 V 9750 t V W10 S4 [E0 10 5A 00 00] W10 v +# S13.0E 99999 V 10600 t V W10 S5 [E0 10 5A 00 00] W10 v +# S13.0E 11700 H 9750 t V W10 S6 [E0 10 5A 00 00] W10 v +# S13.0E 99999 H 10600 t V W10 S7 [E0 10 5A 00 00] W10 v diff --git a/diseqc.h b/diseqc.h index 6dbf04f8..44b8e51e 100644 --- a/diseqc.h +++ b/diseqc.h @@ -4,13 +4,39 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: diseqc.h 2.3 2011/09/10 13:36:50 kls Exp $ + * $Id: diseqc.h 2.4 2011/09/11 13:40:16 kls Exp $ */ #ifndef __DISEQC_H #define __DISEQC_H #include "config.h" +#include "thread.h" + +class cScr : public cListObject { +private: + int channel; + uint userBand; + int pin; + bool used; +public: + cScr(void); + bool Parse(const char *s); + int Channel(void) const { return channel; } + uint UserBand(void) const { return userBand; } + int Pin(void) const { return pin; } + bool Used(void) const { return used; } + void SetUsed(bool Used) { used = Used; } + }; + +class cScrs : public cConfig { +private: + cMutex mutex; +public: + cScr *GetUnused(void); + }; + +extern cScrs Scrs; class cDiseqc : public cListObject { public: @@ -22,6 +48,7 @@ public: daVoltage18, daMiniA, daMiniB, + daScr, daCodes, }; enum { MaxDiseqcCodes = 6 }; @@ -31,37 +58,53 @@ private: int slof; char polarization; int lof; + mutable int scrBank; char *commands; bool parsing; + uint SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const; + int SetScrPin(const cScr *Scr, uint8_t *Codes) const; const char *Wait(const char *s) const; + const char *GetScrBank(const char *s) const; const char *GetCodes(const char *s, uchar *Codes = NULL, uint8_t *MaxCodes = NULL) const; public: cDiseqc(void); ~cDiseqc(); bool Parse(const char *s); - eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes) const; - // Parses the DiSEqC commands and returns the appropriate action code - // with every call. CurrentAction must be the address of a character pointer, - // which is initialized to NULL. This pointer is used internally while parsing - // the commands and shall not be modified once Execute() has been called with - // it. Call Execute() repeatedly (always providing the same CurrentAction pointer) - // until it returns daNone. After a successful execution of all commands - // *CurrentAction points to the value 0x00. - // If the current action consists of sending code bytes to the device, those - // bytes will be copied into Codes. MaxCodes must be initialized to the maximum - // number of bytes Codes can handle, and will be set to the actual number of - // bytes copied to Codes upon return. + eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const; + ///< Parses the DiSEqC commands and returns the appropriate action code + ///< with every call. CurrentAction must be the address of a character pointer, + ///< which is initialized to NULL. This pointer is used internally while parsing + ///< the commands and shall not be modified once Execute() has been called with + ///< it. Call Execute() repeatedly (always providing the same CurrentAction pointer) + ///< until it returns daNone. After a successful execution of all commands + ///< *CurrentAction points to the value 0x00. + ///< If the current action consists of sending code bytes to the device, those + ///< bytes will be copied into Codes. MaxCodes must be initialized to the maximum + ///< number of bytes Codes can handle, and will be set to the actual number of + ///< bytes copied to Codes upon return. + ///< If this DiSEqC entry requires SCR, the given Scr will be used. This must + ///< be a pointer returned from a previous call to cDiseqcs::Get(). + ///< Frequency must be the frequency the tuner will be tuned to, and will be + ///< set to the proper SCR frequency upon return (if SCR is used). int Devices(void) const { return devices; } int Source(void) const { return source; } int Slof(void) const { return slof; } char Polarization(void) const { return polarization; } int Lof(void) const { return lof; } + bool IsScr() const { return scrBank >= 0; } const char *Commands(void) const { return commands; } }; class cDiseqcs : public cConfig { public: - const cDiseqc *Get(int Device, int Source, int Frequency, char Polarization) const; + const cDiseqc *Get(int Device, int Source, int Frequency, char Polarization, const cScr **Scr) const; + ///< Selects a DiSEqC entry suitable for the given Device and tuning parameters. + ///< If this DiSEqC entry requires SCR and the given *Scr is NULL + ///< a free one will be selected from the Scrs and a pointer to that will + ///< be returned in Scr. The caller shall memorize that pointer and reuse it in + ///< subsequent calls. + ///< Scr may be NULL for checking whether there is any DiSEqC entry for the + ///< given transponder. }; extern cDiseqcs Diseqcs; diff --git a/dvbdevice.c b/dvbdevice.c index 4aea70e5..1cd883eb 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 2.44 2011/09/10 13:34:02 kls Exp $ + * $Id: dvbdevice.c 2.45 2011/09/11 13:50:20 kls Exp $ */ #include "dvbdevice.h" @@ -267,13 +267,15 @@ private: time_t lastTimeoutReport; fe_delivery_system frontendType; cChannel channel; - const char *diseqcCommands; + const cDiseqc *lastDiseqc; + const cScr *scr; eTunerStatus tunerStatus; cMutex mutex; cCondVar locked; cCondVar newSet; void ClearEventQueue(void) const; bool GetFrontendStatus(fe_status_t &Status) const; + void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency) const; bool SetFrontend(void); virtual void Action(void); public: @@ -299,7 +301,8 @@ cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_ tuneTimeout = 0; lockTimeout = 0; lastTimeoutReport = 0; - diseqcCommands = NULL; + lastDiseqc = NULL; + scr = NULL; tunerStatus = tsIdle; if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power @@ -313,6 +316,10 @@ cDvbTuner::~cDvbTuner() newSet.Broadcast(); locked.Broadcast(); Cancel(3); + if (lastDiseqc && lastDiseqc->IsScr()) { + unsigned int Frequency = 0; + ExecuteDiseqc(lastDiseqc, &Frequency); + } } bool cDvbTuner::IsTunedTo(const cChannel *Channel) const @@ -482,6 +489,30 @@ static unsigned int FrequencyToHz(unsigned int f) return f; } +void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency) const +{ + struct dvb_diseqc_master_cmd cmd; + const char *CurrentAction = NULL; + for (;;) { + cmd.msg_len = sizeof(cmd.msg); + cDiseqc::eDiseqcActions da = Diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len, scr, Frequency); + if (da == cDiseqc::daNone) + break; + switch (da) { + 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: CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break; + default: esyslog("ERROR: unknown diseqc command %d", da); + } + } + if (scr) + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // makes sure we don't block the bus! +} + bool cDvbTuner::SetFrontend(void) { #define MAXFRONTENDCMDS 16 @@ -509,30 +540,14 @@ bool cDvbTuner::SetFrontend(void) if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) { unsigned int frequency = channel.Frequency(); if (Setup.DiSEqC) { - const cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), frequency, dtp.Polarization()); - if (diseqc) { - if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) { - struct dvb_diseqc_master_cmd cmd; - const char *CurrentAction = NULL; - for (;;) { - cmd.msg_len = sizeof(cmd.msg); - cDiseqc::eDiseqcActions da = diseqc->Execute(&CurrentAction, cmd.msg, &cmd.msg_len); - if (da == cDiseqc::daNone) - break; - switch (da) { - 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: CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); break; - default: esyslog("ERROR: unknown diseqc command %d", da); - } - } - diseqcCommands = diseqc->Commands(); - } + if (const cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), frequency, dtp.Polarization(), &scr)) { frequency -= diseqc->Lof(); + if (diseqc != lastDiseqc || diseqc->IsScr()) { + ExecuteDiseqc(diseqc, &frequency); + if (frequency == 0) + return false; + lastDiseqc = diseqc; + } } else { esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number()); @@ -651,7 +666,7 @@ void cDvbTuner::Action(void) case tsTuned: if (Timer.TimedOut()) { tunerStatus = tsSet; - diseqcCommands = NULL; + lastDiseqc = NULL; if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder()); lastTimeoutReport = time(NULL); @@ -661,7 +676,7 @@ void cDvbTuner::Action(void) case tsLocked: if (Status & FE_REINIT) { tunerStatus = tsSet; - diseqcCommands = NULL; + lastDiseqc = NULL; isyslog("frontend %d/%d was reinitialized", adapter, frontend); lastTimeoutReport = 0; continue; @@ -1036,7 +1051,7 @@ bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const dtp.Modulation() == PSK_8 && !(frontendInfo.caps & FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North American broadcasters - this is a best guess to determine this condition return false; // requires modulation system which frontend doesn't provide if (!cSource::IsSat(Channel->Source()) || - !Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization())) + !Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), Channel->Frequency(), dtp.Polarization(), NULL)) return DeviceHooksProvidesTransponder(Channel); return false; } diff --git a/scr.conf b/scr.conf new file mode 100644 index 00000000..9d02dc10 --- /dev/null +++ b/scr.conf @@ -0,0 +1,20 @@ +# SCR (Satellite Channel Routing) configuration for VDR +# +# Format: +# +# channel frequency [pin] +# +# channel: SCR channel index (0-7) +# frequency: frequency of the SCR channel ("user band") +# pin: optional pin of the SCR channel (0-255) +# +# Examples: + +# 0 1284 +# 1 1400 +# 2 1516 +# 3 1632 +# 4 1748 +# 5 1864 +# 6 1980 +# 7 2096 diff --git a/vdr.5 b/vdr.5 index c46a2bf2..5608fa17 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 2.23 2011/08/21 14:06:50 kls Exp $ +.\" $Id: vdr.5 2.24 2011/09/10 14:45:00 kls Exp $ .\" .TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files" .SH NAME @@ -467,6 +467,7 @@ l l. \fBV\fR@voltage high (18V) \fBA\fR@mini A \fBB\fR@mini B +\fBSn\fR@Satellite channel routing code sequence for bank n follows \fBWnn\fR@wait nn milliseconds (nn may be any positive integer number) \fB[xx ...]\fR@hex code sequence (max. 6) .TE @@ -484,6 +485,33 @@ to receive the satellites following thereafter. In this case, only the devices 1, 2 and 4 would be able to receive any satellites following this line and up to the next such line, or the end of the file. Devices may be listed more than once. +.SS SATELLITE CHANNEL ROUTING (SCR) +The file \fIscr.conf\fR contains the channel definitions of the SCR device in use. +The format is + +channel frequency [pin] + +where channel is the SCR device's channel index (0-7), frequency is the user band +frequency of the given channel, and pin is an optional pin number (0-255). The +actual values are device specific and can be found in the SCR device's manual. + +Examples: + +0 1284 +.br +1 1400 +.br +2 1516 +.br +3 1632 +.br +4 1748 +.br +5 1864 +.br +6 1980 +.br +7 2096 .SS REMOTE CONTROL KEYS The file \fIremote.conf\fR contains the key assignments for all remote control units. Each line consists of one key assignment in the following format: diff --git a/vdr.c b/vdr.c index c32e45fd..a599d7c9 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.tvdr.de * - * $Id: vdr.c 2.23 2011/08/15 12:42:39 kls Exp $ + * $Id: vdr.c 2.24 2011/09/10 15:03:23 kls Exp $ */ #include @@ -598,6 +598,7 @@ int main(int argc, char *argv[]) Setup.Load(AddDirectory(ConfigDirectory, "setup.conf")); Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true); Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC); + Scrs.Load(AddDirectory(ConfigDirectory, "scr.conf"), true); Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));