mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
VDR now supports "Satellite Channel Routing" (SCR)
This commit is contained in:
parent
78e89efee8
commit
413a0e6373
@ -2661,6 +2661,7 @@ Stephan Austerm
|
|||||||
|
|
||||||
Lars Hanisch <dvb@flensrocker.de>
|
Lars Hanisch <dvb@flensrocker.de>
|
||||||
for suggesting to assign the source character 'V' to "Analog Video"
|
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 <alex@fepg.org>
|
Alex Lasnier <alex@fepg.org>
|
||||||
for adding tuning support for ATSC devices
|
for adding tuning support for ATSC devices
|
||||||
|
9
HISTORY
9
HISTORY
@ -6743,8 +6743,15 @@ Video Disk Recorder Revision History
|
|||||||
extends over TS packet boundaries is now done by locally skipping TS packets
|
extends over TS packet boundaries is now done by locally skipping TS packets
|
||||||
in cFrameDetector.
|
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
|
- Fixed scaling subtitles in case the primary device's GetVideoSize() function doesn't
|
||||||
return actual values (thanks to Luca Olivetti).
|
return actual values (thanks to Luca Olivetti).
|
||||||
- The DiSEqC codes are now copied in the call to cDiseqc::Execute().
|
- 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".
|
||||||
|
6
INSTALL
6
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
|
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).
|
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):
|
Running VDR with DVB-C (cable) or DVB-T (terrestrial):
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
|
||||||
|
118
diseqc.c
118
diseqc.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: 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"
|
#include "diseqc.h"
|
||||||
@ -12,6 +12,51 @@
|
|||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
#include "thread.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::cDiseqc(void)
|
cDiseqc::cDiseqc(void)
|
||||||
@ -21,6 +66,7 @@ cDiseqc::cDiseqc(void)
|
|||||||
slof = 0;
|
slof = 0;
|
||||||
polarization = 0;
|
polarization = 0;
|
||||||
lof = 0;
|
lof = 0;
|
||||||
|
scrBank = -1;
|
||||||
commands = NULL;
|
commands = NULL;
|
||||||
parsing = false;
|
parsing = false;
|
||||||
}
|
}
|
||||||
@ -59,7 +105,7 @@ bool cDiseqc::Parse(const char *s)
|
|||||||
if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') {
|
if (polarization == 'V' || polarization == 'H' || polarization == 'L' || polarization == 'R') {
|
||||||
parsing = true;
|
parsing = true;
|
||||||
const char *CurrentAction = NULL;
|
const char *CurrentAction = NULL;
|
||||||
while (Execute(&CurrentAction, NULL, NULL) != daNone)
|
while (Execute(&CurrentAction, NULL, NULL, NULL, NULL) != daNone)
|
||||||
;
|
;
|
||||||
parsing = false;
|
parsing = false;
|
||||||
result = !commands || !*CurrentAction;
|
result = !commands || !*CurrentAction;
|
||||||
@ -74,6 +120,31 @@ bool cDiseqc::Parse(const char *s)
|
|||||||
return result;
|
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
|
const char *cDiseqc::Wait(const char *s) const
|
||||||
{
|
{
|
||||||
char *p = NULL;
|
char *p = NULL;
|
||||||
@ -88,6 +159,24 @@ const char *cDiseqc::Wait(const char *s) const
|
|||||||
return NULL;
|
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 *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) const
|
||||||
{
|
{
|
||||||
const char *e = strchr(s, ']');
|
const char *e = strchr(s, ']');
|
||||||
@ -129,7 +218,7 @@ const char *cDiseqc::GetCodes(const char *s, uchar *Codes, uint8_t *MaxCodes) co
|
|||||||
return NULL;
|
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)
|
if (!*CurrentAction)
|
||||||
*CurrentAction = commands;
|
*CurrentAction = commands;
|
||||||
@ -143,7 +232,16 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Code
|
|||||||
case 'A': return daMiniA;
|
case 'A': return daMiniA;
|
||||||
case 'B': return daMiniB;
|
case 'B': return daMiniB;
|
||||||
case 'W': *CurrentAction = Wait(*CurrentAction); break;
|
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;
|
default: return daNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,7 +252,7 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Code
|
|||||||
|
|
||||||
cDiseqcs Diseqcs;
|
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;
|
int Devices = 0;
|
||||||
for (const cDiseqc *p = First(); p; p = Next(p)) {
|
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)))
|
if (Devices && !(Devices & (1 << Device - 1)))
|
||||||
continue;
|
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 p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
13
diseqc.conf
13
diseqc.conf
@ -18,6 +18,7 @@
|
|||||||
# V voltage high (18V)
|
# V voltage high (18V)
|
||||||
# A mini A
|
# A mini A
|
||||||
# B mini B
|
# B mini B
|
||||||
|
# Sn Satellite channel routing code sequence for bank n follows
|
||||||
# Wnn wait nn milliseconds (nn may be any positive integer number)
|
# Wnn wait nn milliseconds (nn may be any positive integer number)
|
||||||
# [xx ...] hex code sequence (max. 6)
|
# [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 99999 H 10560 t v
|
||||||
# S19.2E 12110 V 11080 t v
|
# S19.2E 12110 V 11080 t v
|
||||||
# S19.2E 99999 V 10720 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
|
||||||
|
71
diseqc.h
71
diseqc.h
@ -4,13 +4,39 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: 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
|
#ifndef __DISEQC_H
|
||||||
#define __DISEQC_H
|
#define __DISEQC_H
|
||||||
|
|
||||||
#include "config.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<cScr> {
|
||||||
|
private:
|
||||||
|
cMutex mutex;
|
||||||
|
public:
|
||||||
|
cScr *GetUnused(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern cScrs Scrs;
|
||||||
|
|
||||||
class cDiseqc : public cListObject {
|
class cDiseqc : public cListObject {
|
||||||
public:
|
public:
|
||||||
@ -22,6 +48,7 @@ public:
|
|||||||
daVoltage18,
|
daVoltage18,
|
||||||
daMiniA,
|
daMiniA,
|
||||||
daMiniB,
|
daMiniB,
|
||||||
|
daScr,
|
||||||
daCodes,
|
daCodes,
|
||||||
};
|
};
|
||||||
enum { MaxDiseqcCodes = 6 };
|
enum { MaxDiseqcCodes = 6 };
|
||||||
@ -31,37 +58,53 @@ private:
|
|||||||
int slof;
|
int slof;
|
||||||
char polarization;
|
char polarization;
|
||||||
int lof;
|
int lof;
|
||||||
|
mutable int scrBank;
|
||||||
char *commands;
|
char *commands;
|
||||||
bool parsing;
|
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 *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;
|
const char *GetCodes(const char *s, uchar *Codes = NULL, uint8_t *MaxCodes = NULL) const;
|
||||||
public:
|
public:
|
||||||
cDiseqc(void);
|
cDiseqc(void);
|
||||||
~cDiseqc();
|
~cDiseqc();
|
||||||
bool Parse(const char *s);
|
bool Parse(const char *s);
|
||||||
eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes) const;
|
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
|
///< Parses the DiSEqC commands and returns the appropriate action code
|
||||||
// with every call. CurrentAction must be the address of a character pointer,
|
///< with every call. CurrentAction must be the address of a character pointer,
|
||||||
// which is initialized to NULL. This pointer is used internally while parsing
|
///< 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
|
///< the commands and shall not be modified once Execute() has been called with
|
||||||
// it. Call Execute() repeatedly (always providing the same CurrentAction pointer)
|
///< it. Call Execute() repeatedly (always providing the same CurrentAction pointer)
|
||||||
// until it returns daNone. After a successful execution of all commands
|
///< until it returns daNone. After a successful execution of all commands
|
||||||
// *CurrentAction points to the value 0x00.
|
///< *CurrentAction points to the value 0x00.
|
||||||
// If the current action consists of sending code bytes to the device, those
|
///< 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
|
///< 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
|
///< number of bytes Codes can handle, and will be set to the actual number of
|
||||||
// bytes copied to Codes upon return.
|
///< 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 Devices(void) const { return devices; }
|
||||||
int Source(void) const { return source; }
|
int Source(void) const { return source; }
|
||||||
int Slof(void) const { return slof; }
|
int Slof(void) const { return slof; }
|
||||||
char Polarization(void) const { return polarization; }
|
char Polarization(void) const { return polarization; }
|
||||||
int Lof(void) const { return lof; }
|
int Lof(void) const { return lof; }
|
||||||
|
bool IsScr() const { return scrBank >= 0; }
|
||||||
const char *Commands(void) const { return commands; }
|
const char *Commands(void) const { return commands; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class cDiseqcs : public cConfig<cDiseqc> {
|
class cDiseqcs : public cConfig<cDiseqc> {
|
||||||
public:
|
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;
|
extern cDiseqcs Diseqcs;
|
||||||
|
73
dvbdevice.c
73
dvbdevice.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbdevice.c 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"
|
#include "dvbdevice.h"
|
||||||
@ -267,13 +267,15 @@ private:
|
|||||||
time_t lastTimeoutReport;
|
time_t lastTimeoutReport;
|
||||||
fe_delivery_system frontendType;
|
fe_delivery_system frontendType;
|
||||||
cChannel channel;
|
cChannel channel;
|
||||||
const char *diseqcCommands;
|
const cDiseqc *lastDiseqc;
|
||||||
|
const cScr *scr;
|
||||||
eTunerStatus tunerStatus;
|
eTunerStatus tunerStatus;
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
cCondVar locked;
|
cCondVar locked;
|
||||||
cCondVar newSet;
|
cCondVar newSet;
|
||||||
void ClearEventQueue(void) const;
|
void ClearEventQueue(void) const;
|
||||||
bool GetFrontendStatus(fe_status_t &Status) const;
|
bool GetFrontendStatus(fe_status_t &Status) const;
|
||||||
|
void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency) const;
|
||||||
bool SetFrontend(void);
|
bool SetFrontend(void);
|
||||||
virtual void Action(void);
|
virtual void Action(void);
|
||||||
public:
|
public:
|
||||||
@ -299,7 +301,8 @@ cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_
|
|||||||
tuneTimeout = 0;
|
tuneTimeout = 0;
|
||||||
lockTimeout = 0;
|
lockTimeout = 0;
|
||||||
lastTimeoutReport = 0;
|
lastTimeoutReport = 0;
|
||||||
diseqcCommands = NULL;
|
lastDiseqc = NULL;
|
||||||
|
scr = NULL;
|
||||||
tunerStatus = tsIdle;
|
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
|
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
|
||||||
@ -313,6 +316,10 @@ cDvbTuner::~cDvbTuner()
|
|||||||
newSet.Broadcast();
|
newSet.Broadcast();
|
||||||
locked.Broadcast();
|
locked.Broadcast();
|
||||||
Cancel(3);
|
Cancel(3);
|
||||||
|
if (lastDiseqc && lastDiseqc->IsScr()) {
|
||||||
|
unsigned int Frequency = 0;
|
||||||
|
ExecuteDiseqc(lastDiseqc, &Frequency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
||||||
@ -482,6 +489,30 @@ static unsigned int FrequencyToHz(unsigned int f)
|
|||||||
return 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)
|
bool cDvbTuner::SetFrontend(void)
|
||||||
{
|
{
|
||||||
#define MAXFRONTENDCMDS 16
|
#define MAXFRONTENDCMDS 16
|
||||||
@ -509,30 +540,14 @@ bool cDvbTuner::SetFrontend(void)
|
|||||||
if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
|
if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
|
||||||
unsigned int frequency = channel.Frequency();
|
unsigned int frequency = channel.Frequency();
|
||||||
if (Setup.DiSEqC) {
|
if (Setup.DiSEqC) {
|
||||||
const cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), frequency, dtp.Polarization());
|
if (const cDiseqc *diseqc = Diseqcs.Get(device, channel.Source(), frequency, dtp.Polarization(), &scr)) {
|
||||||
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();
|
|
||||||
}
|
|
||||||
frequency -= diseqc->Lof();
|
frequency -= diseqc->Lof();
|
||||||
|
if (diseqc != lastDiseqc || diseqc->IsScr()) {
|
||||||
|
ExecuteDiseqc(diseqc, &frequency);
|
||||||
|
if (frequency == 0)
|
||||||
|
return false;
|
||||||
|
lastDiseqc = diseqc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number());
|
esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number());
|
||||||
@ -651,7 +666,7 @@ void cDvbTuner::Action(void)
|
|||||||
case tsTuned:
|
case tsTuned:
|
||||||
if (Timer.TimedOut()) {
|
if (Timer.TimedOut()) {
|
||||||
tunerStatus = tsSet;
|
tunerStatus = tsSet;
|
||||||
diseqcCommands = NULL;
|
lastDiseqc = NULL;
|
||||||
if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these
|
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());
|
isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder());
|
||||||
lastTimeoutReport = time(NULL);
|
lastTimeoutReport = time(NULL);
|
||||||
@ -661,7 +676,7 @@ void cDvbTuner::Action(void)
|
|||||||
case tsLocked:
|
case tsLocked:
|
||||||
if (Status & FE_REINIT) {
|
if (Status & FE_REINIT) {
|
||||||
tunerStatus = tsSet;
|
tunerStatus = tsSet;
|
||||||
diseqcCommands = NULL;
|
lastDiseqc = NULL;
|
||||||
isyslog("frontend %d/%d was reinitialized", adapter, frontend);
|
isyslog("frontend %d/%d was reinitialized", adapter, frontend);
|
||||||
lastTimeoutReport = 0;
|
lastTimeoutReport = 0;
|
||||||
continue;
|
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
|
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
|
return false; // requires modulation system which frontend doesn't provide
|
||||||
if (!cSource::IsSat(Channel->Source()) ||
|
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 DeviceHooksProvidesTransponder(Channel);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
20
scr.conf
Normal file
20
scr.conf
Normal file
@ -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
|
30
vdr.5
30
vdr.5
@ -8,7 +8,7 @@
|
|||||||
.\" License as specified in the file COPYING that comes with the
|
.\" License as specified in the file COPYING that comes with the
|
||||||
.\" vdr distribution.
|
.\" vdr distribution.
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: vdr.5 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"
|
.TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -467,6 +467,7 @@ l l.
|
|||||||
\fBV\fR@voltage high (18V)
|
\fBV\fR@voltage high (18V)
|
||||||
\fBA\fR@mini A
|
\fBA\fR@mini A
|
||||||
\fBB\fR@mini B
|
\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)
|
\fBWnn\fR@wait nn milliseconds (nn may be any positive integer number)
|
||||||
\fB[xx ...]\fR@hex code sequence (max. 6)
|
\fB[xx ...]\fR@hex code sequence (max. 6)
|
||||||
.TE
|
.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
|
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
|
to the next such line, or the end of the file. Devices may be listed more than
|
||||||
once.
|
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
|
.SS REMOTE CONTROL KEYS
|
||||||
The file \fIremote.conf\fR contains the key assignments for all remote control
|
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:
|
units. Each line consists of one key assignment in the following format:
|
||||||
|
3
vdr.c
3
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.tvdr.de
|
* 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 <getopt.h>
|
#include <getopt.h>
|
||||||
@ -598,6 +598,7 @@ int main(int argc, char *argv[])
|
|||||||
Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
|
Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
|
||||||
Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
|
Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
|
||||||
Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
|
Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
|
||||||
|
Scrs.Load(AddDirectory(ConfigDirectory, "scr.conf"), true);
|
||||||
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
|
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
|
||||||
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
|
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
|
||||||
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
|
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
|
||||||
|
Loading…
Reference in New Issue
Block a user