From 7643361b7033632dec89274f1d256362017dc3f1 Mon Sep 17 00:00:00 2001 From: Lars Hanisch Date: Sun, 29 May 2011 18:42:43 +0200 Subject: [PATCH] unicable2.vdr-1.7.15 patch from fds2001 --- diseqc.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++--- diseqc.conf | 14 ++++++++ diseqc.h | 29 ++++++++++++++++ dvbdevice.c | 93 ++++++++++++++++++++++++++++++++------------------ unicable.conf | 15 ++++++++ vdr.c | 1 + 6 files changed, 210 insertions(+), 36 deletions(-) create mode 100644 unicable.conf diff --git a/diseqc.c b/diseqc.c index d446299..b1fa971 100644 --- a/diseqc.c +++ b/diseqc.c @@ -24,6 +24,7 @@ cDiseqc::cDiseqc(void) commands = NULL; parsing = false; numCodes = 0; + unicable = -1; } cDiseqc::~cDiseqc() @@ -101,10 +102,9 @@ const char *cDiseqc::Codes(const char *s) const char *p; int n = strtol(t, &p, 16); if (!errno && p != t && 0 <= n && n <= 255) { - if (!parsing) { - codes[NumCodes++] = uchar(n); - numCodes = NumCodes; - } + if (!parsing) + codes[NumCodes] = uchar(n); + ++NumCodes; t = skipspace(p); } else { @@ -117,6 +117,8 @@ const char *cDiseqc::Codes(const char *s) const return NULL; } } + if (parsing) + numCodes = NumCodes; return e + 1; } else @@ -124,6 +126,46 @@ const char *cDiseqc::Codes(const char *s) const return NULL; } +const char *cDiseqc::Unicable(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) + unicable = n; + return p; + } + esyslog("ERROR: invalid unicable sat in '%s'", s - 1); + return NULL; +} + +unsigned int cDiseqc::UnicableFreq(unsigned int frequency, int satcr, unsigned int bpf) const +{ + unsigned int t = frequency == 0 ? 0 : (frequency + bpf + 2) / 4 - 350; + if (t < 1024 && satcr >= 0 && satcr < 8) + { + codes[3] = t >> 8 | (t == 0 ? 0 : unicable << 2) | satcr << 5; + codes[4] = t; + return (t + 350) * 4 - frequency; + } + + return 0; +} + +void cDiseqc::UnicablePin(int pin) const +{ + if (pin >= 0 && pin <= 255) { + numCodes = 6; + codes[2] = 0x5c; + codes[5] = pin; + } + else { + numCodes = 5; + codes[2] = 0x5a; + } +} + cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction) const { if (!*CurrentAction) @@ -139,6 +181,7 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction) const case 'B': return daMiniB; case 'W': *CurrentAction = Wait(*CurrentAction); break; case '[': *CurrentAction = Codes(*CurrentAction); return *CurrentAction ? daCodes : daNone; + case 'U': *CurrentAction = Unicable(*CurrentAction); return *CurrentAction ? daUnicable : daNone; default: return daNone; } } @@ -164,3 +207,46 @@ const cDiseqc *cDiseqcs::Get(int Device, int Source, int Frequency, char Polariz } return NULL; } + +// --- cUnicable -------------------------------------------------------------- + +cUnicable::cUnicable() +{ + satcr = -1; + bpf = 0; + pin = -1; + unused = true; +} + +bool cUnicable::Parse(const char *s) +{ + bool result = false; + int fields = sscanf(s, "%d %u %d", &satcr, &bpf, &pin); + if (fields >= 2) { + if (satcr >= 0 && satcr < 8) + result = true; + else + esyslog("Error: invalid unicable channel '%d'", satcr); + if (result && fields == 3 && (pin < 0 || pin > 255)) { + esyslog("Error: invalid unicable pin '%d'", pin); + result = false; + } + } + return result; +} + + +// --- cUnicables -------------------------------------------------------------- + +cUnicables Unicables; + +cUnicable *cUnicables::GetUnused() +{ + for (cUnicable *p = First(); p; p = Next(p)) { + if (p->Unused()) { + p->Use(); + return p; + } + } + return NULL; +} diff --git a/diseqc.conf b/diseqc.conf index c9ab3ad..dad3fde 100644 --- a/diseqc.conf +++ b/diseqc.conf @@ -18,6 +18,7 @@ # V voltage high (18V) # A mini A # B mini B +# Un unicable 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,16 @@ 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 +# +# Unicable +# +# S19.2E 11700 V 9750 t V U0 W10 [E0 10 5A 00 00] W10 v +# S19.2E 99999 V 10600 t V U1 W10 [E0 10 5A 00 00] W10 v +# S19.2E 11700 H 9750 t V U2 W10 [E0 10 5A 00 00] W10 v +# S19.2E 99999 H 10600 t V U3 W10 [E0 10 5A 00 00] W10 v +# +# S13.0E 11700 V 9750 t V U4 W10 [E0 10 5A 00 00] W10 v +# S13.0E 99999 V 10600 t V U5 W10 [E0 10 5A 00 00] W10 v +# S13.0E 11700 H 9750 t V U6 W10 [E0 10 5A 00 00] W10 v +# S13.0E 99999 H 10600 t V U7 W10 [E0 10 5A 00 00] W10 v + diff --git a/diseqc.h b/diseqc.h index 413ed4d..552e3da 100644 --- a/diseqc.h +++ b/diseqc.h @@ -23,6 +23,7 @@ class cDiseqc : public cListObject { daMiniA, daMiniB, daCodes, + daUnicable, }; enum { MaxDiseqcCodes = 6 }; private: @@ -32,11 +33,13 @@ class cDiseqc : public cListObject { char polarization; int lof; char *commands; + mutable int unicable; bool parsing; mutable uchar codes[MaxDiseqcCodes]; mutable int numCodes; const char *Wait(const char *s) const; const char *Codes(const char *s) const; + const char *Unicable(const char *s) const; public: cDiseqc(void); ~cDiseqc(); @@ -56,6 +59,9 @@ class cDiseqc : public cListObject { int Lof(void) const { return lof; } const char *Commands(void) const { return commands; } const uchar *Codes(int &NumCodes) const { NumCodes = numCodes; return numCodes ? codes : NULL; } + bool Unicable() const { return unicable >= 0; } + unsigned int UnicableFreq(unsigned int frequency, int satcr, unsigned int bpf) const; + void UnicablePin(int pin) const; }; class cDiseqcs : public cConfig { @@ -65,4 +71,27 @@ class cDiseqcs : public cConfig { extern cDiseqcs Diseqcs; +class cUnicable : public cListObject { +private: + int satcr; + unsigned int bpf; + int pin; + bool unused; +public: + cUnicable(); + bool Parse(const char *s); + int Satcr() const { return satcr; } + unsigned int Bpf() const { return bpf; } + int Pin() const { return pin; } + bool Unused() const { return unused; } + void Use() { unused = false; } + }; + +class cUnicables : public cConfig { +public: + cUnicable *GetUnused(); + }; + +extern cUnicables Unicables; + #endif //__DISEQC_H diff --git a/dvbdevice.c b/dvbdevice.c index b0750dd..f244176 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -267,13 +267,15 @@ class cDvbTuner : public cThread { time_t lastTimeoutReport; fe_delivery_system frontendType; cChannel channel; - const char *diseqcCommands; + cUnicable *unicable; + const cDiseqc *diseqcLast; 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); bool SetFrontend(void); virtual void Action(void); public: @@ -286,6 +288,9 @@ class cDvbTuner : public cThread { bool Locked(int TimeoutMs = 0); int GetSignalStrength(void) const; int GetSignalQuality(void) const; + int UnicableSatcr() const { return unicable ? unicable->Satcr() : -1; } + int UnicableBpf() const { return unicable ? unicable->Bpf() : 0; } + int UnicablePin() const { return unicable ? unicable->Pin() : -1; } }; cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType) @@ -299,10 +304,13 @@ cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_ tuneTimeout = 0; lockTimeout = 0; lastTimeoutReport = 0; - diseqcCommands = NULL; + unicable = NULL; + diseqcLast = NULL; tunerStatus = tsIdle; - if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) + if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) { CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power + unicable = Unicables.GetUnused(); + } SetDescription("tuner on frontend %d/%d", adapter, frontend); Start(); } @@ -313,6 +321,10 @@ cDvbTuner::~cDvbTuner() newSet.Broadcast(); locked.Broadcast(); Cancel(3); + if (diseqcLast && diseqcLast->Unicable()) { + unsigned int frequency = 0; + ExecuteDiseqc(diseqcLast, frequency); + } } bool cDvbTuner::IsTunedTo(const cChannel *Channel) const @@ -482,6 +494,43 @@ static unsigned int FrequencyToHz(unsigned int f) return f; } +void cDvbTuner::ExecuteDiseqc(const cDiseqc *diseqc, unsigned int &frequency) +{ + cDiseqc::eDiseqcActions da; + for (const char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) { + switch (da) { + 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; + const uchar *codes = diseqc->Codes(n); + if (codes) { + struct dvb_diseqc_master_cmd cmd; + cmd.msg_len = min(n, int(sizeof(cmd.msg))); + memcpy(cmd.msg, codes, cmd.msg_len); + CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); + } + } + break; + case cDiseqc::daUnicable: { + frequency = diseqc->UnicableFreq(frequency, UnicableSatcr(), UnicableBpf()); + diseqc->UnicablePin(UnicablePin()); + if (frequency == 0) { + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); + esyslog("ERROR: unable to setup unicable frequency for channel %d (f=%u, s=%d, b=%d)", channel.Number(), frequency, UnicableSatcr(), UnicableBpf()); + } + } + break; + default: esyslog("ERROR: unknown diseqc command %d", da); + } + } +} + bool cDvbTuner::SetFrontend(void) { #define MAXFRONTENDCMDS 16 @@ -511,34 +560,14 @@ bool cDvbTuner::SetFrontend(void) if (Setup.DiSEqC) { const cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), channel.Frequency(), dtp.Polarization()); if (diseqc) { - if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) { - cDiseqc::eDiseqcActions da; - for (const char *CurrentAction = NULL; (da = diseqc->Execute(&CurrentAction)) != cDiseqc::daNone; ) { - switch (da) { - 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; - const uchar *codes = diseqc->Codes(n); - if (codes) { - struct dvb_diseqc_master_cmd cmd; - cmd.msg_len = min(n, int(sizeof(cmd.msg))); - memcpy(cmd.msg, codes, cmd.msg_len); - CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); - } - } - break; - default: esyslog("ERROR: unknown diseqc command %d", da); - } - } - diseqcCommands = diseqc->Commands(); - } frequency -= diseqc->Lof(); + if (diseqc->Commands() && (!diseqcLast || strcmp(diseqcLast->Commands(), diseqc->Commands()) != 0 || diseqc->Unicable())) { + ExecuteDiseqc(diseqc, frequency); + if (frequency == 0) { + return false; + } + diseqcLast = diseqc; + } } else { esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number()); @@ -657,7 +686,7 @@ void cDvbTuner::Action(void) case tsTuned: if (Timer.TimedOut()) { tunerStatus = tsSet; - diseqcCommands = NULL; + diseqcLast = 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); @@ -667,7 +696,7 @@ void cDvbTuner::Action(void) case tsLocked: if (Status & FE_REINIT) { tunerStatus = tsSet; - diseqcCommands = NULL; + diseqcLast = NULL; isyslog("frontend %d/%d was reinitialized", adapter, frontend); lastTimeoutReport = 0; continue; diff --git a/unicable.conf b/unicable.conf new file mode 100644 index 0000000..e71d9fc --- /dev/null +++ b/unicable.conf @@ -0,0 +1,15 @@ +# Unicable configuration for VDR +# +# Format: +# +# channel frequency [pin] +# +# channel: unicable channel (0-7) +# frequency: frequency of the unicable channel +# pin: optional pin of the unicable channel (0-255) +# +# Examples: + +0 1400 +1 1516 + diff --git a/vdr.c b/vdr.c index c32e45f..7c1e934 100644 --- a/vdr.c +++ b/vdr.c @@ -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); + Unicables.Load(AddDirectory(ConfigDirectory, "unicable.conf"), true); Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true); Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")); Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));