mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
The actual tuning is now done in a separate thread
This commit is contained in:
parent
2d2369fca0
commit
b9422baff2
@ -441,6 +441,7 @@ Oliver Endriss <o.endriss@gmx.de>
|
|||||||
|
|
||||||
Reinhard Walter Buchner <rw.buchner@freenet.de>
|
Reinhard Walter Buchner <rw.buchner@freenet.de>
|
||||||
for adding some satellites to 'sources.conf'
|
for adding some satellites to 'sources.conf'
|
||||||
|
for his help in testing tuning with "Motor-DiSEqC"
|
||||||
|
|
||||||
Lauri Tischler <lauri.tischler@efore.fi>
|
Lauri Tischler <lauri.tischler@efore.fi>
|
||||||
for helping to test and debug the new channel source and DiSEqC handling
|
for helping to test and debug the new channel source and DiSEqC handling
|
||||||
|
6
HISTORY
6
HISTORY
@ -1845,3 +1845,9 @@ Video Disk Recorder Revision History
|
|||||||
- Improved handling of repeated remote keys.
|
- Improved handling of repeated remote keys.
|
||||||
- The RCU now only sets the channel number display when there are no incoming remote
|
- The RCU now only sets the channel number display when there are no incoming remote
|
||||||
control keys, which improves reaction on repeated keys.
|
control keys, which improves reaction on repeated keys.
|
||||||
|
- The actual tuning is now done in a separate thread, which makes zapping through the
|
||||||
|
channels a lot faster and no longer gets stuck on channels that don't broadcast.
|
||||||
|
This also makes "Motor-DiSEqC" work (thanks to Reinhard Walter Buchner for his help
|
||||||
|
in testing this). Since switching channels now no longer explicitly waits for a
|
||||||
|
channel lock in the foreground thread, the "panic level" mechanism is no longer
|
||||||
|
used (maybe we don't need it nay more, anyway).
|
||||||
|
25
diseqc.c
25
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 1.1 2002/10/05 13:54:32 kls Exp $
|
* $Id: diseqc.c 1.2 2002/12/07 13:44:56 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "diseqc.h"
|
#include "diseqc.h"
|
||||||
@ -16,7 +16,6 @@
|
|||||||
cDiseqc::cDiseqc(void)
|
cDiseqc::cDiseqc(void)
|
||||||
{
|
{
|
||||||
commands = NULL;
|
commands = NULL;
|
||||||
currentAction = NULL;;
|
|
||||||
parsing = false;
|
parsing = false;
|
||||||
numCodes = 0;
|
numCodes = 0;
|
||||||
}
|
}
|
||||||
@ -39,11 +38,11 @@ bool cDiseqc::Parse(const char *s)
|
|||||||
polarization = toupper(polarization);
|
polarization = toupper(polarization);
|
||||||
if (polarization == 'V' || polarization == 'H') {
|
if (polarization == 'V' || polarization == 'H') {
|
||||||
parsing = true;
|
parsing = true;
|
||||||
bool Start = true;
|
char *CurrentAction = NULL;
|
||||||
while (Execute(Start) != daNone)
|
while (Execute(&CurrentAction) != daNone)
|
||||||
Start = false;
|
;
|
||||||
parsing = false;
|
parsing = false;
|
||||||
result = !commands || currentAction && !*currentAction;
|
result = !commands || !*CurrentAction;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
esyslog("ERROR: unknown polarization '%c'", polarization);
|
esyslog("ERROR: unknown polarization '%c'", polarization);
|
||||||
@ -101,12 +100,12 @@ char *cDiseqc::Codes(char *s)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cDiseqc::eDiseqcActions cDiseqc::Execute(bool Start)
|
cDiseqc::eDiseqcActions cDiseqc::Execute(char **CurrentAction)
|
||||||
{
|
{
|
||||||
if (Start)
|
if (!*CurrentAction)
|
||||||
currentAction = commands;
|
*CurrentAction = commands;
|
||||||
while (currentAction && *currentAction) {
|
while (*CurrentAction && **CurrentAction) {
|
||||||
switch (*currentAction++) {
|
switch (*(*CurrentAction)++) {
|
||||||
case ' ': break;
|
case ' ': break;
|
||||||
case 't': return daToneOff;
|
case 't': return daToneOff;
|
||||||
case 'T': return daToneOn;
|
case 'T': return daToneOn;
|
||||||
@ -114,8 +113,8 @@ cDiseqc::eDiseqcActions cDiseqc::Execute(bool Start)
|
|||||||
case 'V': return daVoltage18;
|
case 'V': return daVoltage18;
|
||||||
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 = Codes(currentAction); return currentAction ? daCodes : daNone;
|
case '[': *CurrentAction = Codes(*CurrentAction); return *CurrentAction ? daCodes : daNone;
|
||||||
default: return daNone;
|
default: return daNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
diseqc.h
12
diseqc.h
@ -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.h 1.1 2002/10/05 13:02:52 kls Exp $
|
* $Id: diseqc.h 1.2 2002/12/07 13:54:02 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DISEQC_H
|
#ifndef __DISEQC_H
|
||||||
@ -31,7 +31,6 @@ private:
|
|||||||
char polarization;
|
char polarization;
|
||||||
int lof;
|
int lof;
|
||||||
char *commands;
|
char *commands;
|
||||||
char *currentAction;
|
|
||||||
bool parsing;
|
bool parsing;
|
||||||
uchar codes[MaxDiseqcCodes];
|
uchar codes[MaxDiseqcCodes];
|
||||||
int numCodes;
|
int numCodes;
|
||||||
@ -41,7 +40,14 @@ public:
|
|||||||
cDiseqc(void);
|
cDiseqc(void);
|
||||||
~cDiseqc();
|
~cDiseqc();
|
||||||
bool Parse(const char *s);
|
bool Parse(const char *s);
|
||||||
eDiseqcActions Execute(bool Start = false);
|
eDiseqcActions Execute(char **CurrentAction);
|
||||||
|
// 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.
|
||||||
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; }
|
||||||
|
355
dvbdevice.c
355
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 1.37 2002/11/16 12:36:50 kls Exp $
|
* $Id: dvbdevice.c 1.38 2002/12/07 14:50:46 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbdevice.h"
|
#include "dvbdevice.h"
|
||||||
@ -60,8 +60,207 @@ static int DvbOpen(const char *Name, int n, int Mode, bool ReportError = false)
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- cDvbTuner -------------------------------------------------------------
|
||||||
|
|
||||||
|
class cDvbTuner : public cThread {
|
||||||
|
private:
|
||||||
|
enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked };
|
||||||
|
int fd_frontend;
|
||||||
|
int cardIndex;
|
||||||
|
fe_type_t frontendType;
|
||||||
|
cChannel channel;
|
||||||
|
const char *diseqcCommands;
|
||||||
|
bool active;
|
||||||
|
eTunerStatus tunerStatus;
|
||||||
|
cMutex mutex;
|
||||||
|
cCondVar newSet;
|
||||||
|
bool SetFrontend(void);
|
||||||
|
virtual void Action(void);
|
||||||
|
public:
|
||||||
|
cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType);
|
||||||
|
virtual ~cDvbTuner();
|
||||||
|
bool IsTunedTo(const cChannel *Channel) const;
|
||||||
|
void Set(const cChannel *Channel);
|
||||||
|
bool Locked(void) { return tunerStatus == tsLocked; }
|
||||||
|
};
|
||||||
|
|
||||||
|
cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_type_t FrontendType)
|
||||||
|
{
|
||||||
|
fd_frontend = Fd_Frontend;
|
||||||
|
cardIndex = CardIndex;
|
||||||
|
frontendType = FrontendType;
|
||||||
|
diseqcCommands = NULL;
|
||||||
|
active = false;
|
||||||
|
tunerStatus = tsIdle;
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
cDvbTuner::~cDvbTuner()
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
tunerStatus = tsIdle;
|
||||||
|
newSet.Broadcast();
|
||||||
|
Cancel(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
|
||||||
|
{
|
||||||
|
return tunerStatus != tsIdle && channel.Source() == Channel->Source() && channel.Frequency() == Channel->Frequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbTuner::Set(const cChannel *Channel)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
channel = *Channel;
|
||||||
|
tunerStatus = tsSet;
|
||||||
|
newSet.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int FrequencyToHz(unsigned int f)
|
||||||
|
{
|
||||||
|
while (f && f < 1000000)
|
||||||
|
f *= 1000;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbTuner::SetFrontend(void)
|
||||||
|
{
|
||||||
|
dvb_frontend_parameters Frontend;
|
||||||
|
|
||||||
|
memset(&Frontend, 0, sizeof(Frontend));
|
||||||
|
|
||||||
|
switch (frontendType) {
|
||||||
|
case FE_QPSK: { // DVB-S
|
||||||
|
|
||||||
|
unsigned int frequency = channel.Frequency();
|
||||||
|
|
||||||
|
if (Setup.DiSEqC) {
|
||||||
|
cDiseqc *diseqc = Diseqcs.Get(channel.Source(), channel.Frequency(), channel.Polarization());
|
||||||
|
if (diseqc) {
|
||||||
|
if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) {
|
||||||
|
cDiseqc::eDiseqcActions da;
|
||||||
|
for (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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diseqcCommands = diseqc->Commands();
|
||||||
|
}
|
||||||
|
frequency -= diseqc->Lof();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
esyslog("ERROR: no DiSEqC parameters found for channel %d", channel.Number());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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;
|
||||||
|
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
|
||||||
|
CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
|
||||||
|
}
|
||||||
|
|
||||||
|
Frontend.frequency = frequency * 1000UL;
|
||||||
|
Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
|
||||||
|
Frontend.u.qpsk.symbol_rate = channel.Srate() * 1000UL;
|
||||||
|
Frontend.u.qpsk.fec_inner = fe_code_rate_t(channel.CoderateH());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FE_QAM: { // DVB-C
|
||||||
|
|
||||||
|
// Frequency and symbol rate:
|
||||||
|
|
||||||
|
Frontend.frequency = FrequencyToHz(channel.Frequency());
|
||||||
|
Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
|
||||||
|
Frontend.u.qam.symbol_rate = channel.Srate() * 1000UL;
|
||||||
|
Frontend.u.qam.fec_inner = fe_code_rate_t(channel.CoderateH());
|
||||||
|
Frontend.u.qam.modulation = fe_modulation_t(channel.Modulation());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FE_OFDM: { // DVB-T
|
||||||
|
|
||||||
|
// Frequency and OFDM paramaters:
|
||||||
|
|
||||||
|
Frontend.frequency = FrequencyToHz(channel.Frequency());
|
||||||
|
Frontend.inversion = fe_spectral_inversion_t(channel.Inversion());
|
||||||
|
Frontend.u.ofdm.bandwidth = fe_bandwidth_t(channel.Bandwidth());
|
||||||
|
Frontend.u.ofdm.code_rate_HP = fe_code_rate_t(channel.CoderateH());
|
||||||
|
Frontend.u.ofdm.code_rate_LP = fe_code_rate_t(channel.CoderateL());
|
||||||
|
Frontend.u.ofdm.constellation = fe_modulation_t(channel.Modulation());
|
||||||
|
Frontend.u.ofdm.transmission_mode = fe_transmit_mode_t(channel.Transmission());
|
||||||
|
Frontend.u.ofdm.guard_interval = fe_guard_interval_t(channel.Guard());
|
||||||
|
Frontend.u.ofdm.hierarchy_information = fe_hierarchy_t(channel.Hierarchy());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend) < 0) {
|
||||||
|
esyslog("ERROR: frontend %d: %m", cardIndex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbTuner::Action(void)
|
||||||
|
{
|
||||||
|
dsyslog("tuner thread started on device %d (pid=%d)", cardIndex + 1, getpid());
|
||||||
|
active = true;
|
||||||
|
while (active) {
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
if (tunerStatus == tsSet)
|
||||||
|
tunerStatus = SetFrontend() ? tsTuned : tsIdle;
|
||||||
|
if (tunerStatus == tsTuned) {
|
||||||
|
fe_status_t status = fe_status_t(0);
|
||||||
|
CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
|
||||||
|
if (status & FE_HAS_LOCK)
|
||||||
|
tunerStatus = tsLocked;
|
||||||
|
}
|
||||||
|
dvb_frontend_event event;
|
||||||
|
if (ioctl(fd_frontend, FE_GET_EVENT, &event) == 0) {
|
||||||
|
if (tunerStatus != tsIdle && event.status & FE_REINIT) {
|
||||||
|
tunerStatus = tsSet;
|
||||||
|
esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newSet.TimedWait(mutex, 1000);
|
||||||
|
}
|
||||||
|
dsyslog("tuner thread ended on device %d (pid=%d)", cardIndex + 1, getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cDvbDevice ------------------------------------------------------------
|
||||||
|
|
||||||
cDvbDevice::cDvbDevice(int n)
|
cDvbDevice::cDvbDevice(int n)
|
||||||
{
|
{
|
||||||
|
dvbTuner = NULL;
|
||||||
frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
|
frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
|
||||||
siProcessor = NULL;
|
siProcessor = NULL;
|
||||||
spuDecoder = NULL;
|
spuDecoder = NULL;
|
||||||
@ -69,7 +268,7 @@ cDvbDevice::cDvbDevice(int n)
|
|||||||
|
|
||||||
// Devices that are present on all card types:
|
// Devices that are present on all card types:
|
||||||
|
|
||||||
fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK);
|
int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK);
|
||||||
|
|
||||||
// Devices that are only present on cards with decoders:
|
// Devices that are only present on cards with decoders:
|
||||||
|
|
||||||
@ -90,8 +289,10 @@ cDvbDevice::cDvbDevice(int n)
|
|||||||
if (fd_frontend >= 0) {
|
if (fd_frontend >= 0) {
|
||||||
dvb_frontend_info feinfo;
|
dvb_frontend_info feinfo;
|
||||||
siProcessor = new cSIProcessor(DvbName(DEV_DVB_DEMUX, n));
|
siProcessor = new cSIProcessor(DvbName(DEV_DVB_DEMUX, n));
|
||||||
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0)
|
if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) {
|
||||||
frontendType = feinfo.type;
|
frontendType = feinfo.type;
|
||||||
|
dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LOG_ERROR;
|
LOG_ERROR;
|
||||||
}
|
}
|
||||||
@ -99,16 +300,13 @@ cDvbDevice::cDvbDevice(int n)
|
|||||||
esyslog("ERROR: can't open DVB device %d", n);
|
esyslog("ERROR: can't open DVB device %d", n);
|
||||||
|
|
||||||
aPid1 = aPid2 = 0;
|
aPid1 = aPid2 = 0;
|
||||||
|
|
||||||
source = -1;
|
|
||||||
frequency = -1;
|
|
||||||
diseqcCommands = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cDvbDevice::~cDvbDevice()
|
cDvbDevice::~cDvbDevice()
|
||||||
{
|
{
|
||||||
delete spuDecoder;
|
delete spuDecoder;
|
||||||
delete siProcessor;
|
delete siProcessor;
|
||||||
|
delete dvbTuner;
|
||||||
// We're not explicitly closing any device files here, since this sometimes
|
// We're not explicitly closing any device files here, since this sometimes
|
||||||
// caused segfaults. Besides, the program is about to terminate anyway...
|
// caused segfaults. Besides, the program is about to terminate anyway...
|
||||||
}
|
}
|
||||||
@ -322,11 +520,6 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbDevice::IsTunedTo(const cChannel *Channel) const
|
|
||||||
{
|
|
||||||
return source == Channel->Source() && frequency == Channel->Frequency();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDvbDevice::ProvidesSource(int Source) const
|
bool cDvbDevice::ProvidesSource(int Source) const
|
||||||
{
|
{
|
||||||
int type = Source & cSource::st_Mask;
|
int type = Source & cSource::st_Mask;
|
||||||
@ -346,7 +539,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
|
|||||||
if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
|
if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel->Ca())) {
|
||||||
#ifdef DO_MULTIPLE_RECORDINGS
|
#ifdef DO_MULTIPLE_RECORDINGS
|
||||||
if (Receiving()) {
|
if (Receiving()) {
|
||||||
if (IsTunedTo(Channel)) {
|
if (dvbTuner->IsTunedTo(Channel)) {
|
||||||
needsDetachReceivers = false;
|
needsDetachReceivers = false;
|
||||||
if (!HasPid(Channel->Vpid())) {
|
if (!HasPid(Channel->Vpid())) {
|
||||||
if (Channel->Ca() > CACONFBASE) {
|
if (Channel->Ca() > CACONFBASE) {
|
||||||
@ -375,18 +568,11 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int FrequencyToHz(unsigned int f)
|
|
||||||
{
|
|
||||||
while (f && f < 1000000)
|
|
||||||
f *= 1000;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
||||||
{
|
{
|
||||||
bool IsEncrypted = Channel->Ca() > CACONFBASE;
|
bool IsEncrypted = Channel->Ca() > CACONFBASE;
|
||||||
|
|
||||||
bool DoTune = !IsTunedTo(Channel);
|
bool DoTune = !dvbTuner->IsTunedTo(Channel);
|
||||||
|
|
||||||
bool TurnOffLivePIDs = HasDecoder()
|
bool TurnOffLivePIDs = HasDecoder()
|
||||||
&& (DoTune
|
&& (DoTune
|
||||||
@ -436,136 +622,15 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DoTune) {
|
if (DoTune) {
|
||||||
|
dvbTuner->Set(Channel);
|
||||||
dvb_frontend_parameters Frontend;
|
/*XXX do we still need this???
|
||||||
|
|
||||||
memset(&Frontend, 0, sizeof(Frontend));
|
|
||||||
|
|
||||||
switch (frontendType) {
|
|
||||||
case FE_QPSK: { // DVB-S
|
|
||||||
|
|
||||||
unsigned int frequency = Channel->Frequency();
|
|
||||||
|
|
||||||
if (Setup.DiSEqC) {
|
|
||||||
cDiseqc *diseqc = Diseqcs.Get(Channel->Source(), Channel->Frequency(), Channel->Polarization());
|
|
||||||
if (diseqc) {
|
|
||||||
if (diseqc->Commands() && (!diseqcCommands || strcmp(diseqcCommands, diseqc->Commands()) != 0)) {
|
|
||||||
cDiseqc::eDiseqcActions da;
|
|
||||||
for (bool Start = true; (da = diseqc->Execute(Start)) != cDiseqc::daNone; Start = false) {
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diseqcCommands = diseqc->Commands();
|
|
||||||
}
|
|
||||||
frequency -= diseqc->Lof();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
esyslog("ERROR: no DiSEqC parameters found for channel %d", Channel->Number());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
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;
|
|
||||||
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
|
|
||||||
CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
|
|
||||||
}
|
|
||||||
|
|
||||||
Frontend.frequency = frequency * 1000UL;
|
|
||||||
Frontend.inversion = fe_spectral_inversion_t(Channel->Inversion());
|
|
||||||
Frontend.u.qpsk.symbol_rate = Channel->Srate() * 1000UL;
|
|
||||||
Frontend.u.qpsk.fec_inner = fe_code_rate_t(Channel->CoderateH());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FE_QAM: { // DVB-C
|
|
||||||
|
|
||||||
// Frequency and symbol rate:
|
|
||||||
|
|
||||||
Frontend.frequency = FrequencyToHz(Channel->Frequency());
|
|
||||||
Frontend.inversion = fe_spectral_inversion_t(Channel->Inversion());
|
|
||||||
Frontend.u.qam.symbol_rate = Channel->Srate() * 1000UL;
|
|
||||||
Frontend.u.qam.fec_inner = fe_code_rate_t(Channel->CoderateH());
|
|
||||||
Frontend.u.qam.modulation = fe_modulation_t(Channel->Modulation());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FE_OFDM: { // DVB-T
|
|
||||||
|
|
||||||
// Frequency and OFDM paramaters:
|
|
||||||
|
|
||||||
Frontend.frequency = FrequencyToHz(Channel->Frequency());
|
|
||||||
Frontend.inversion = fe_spectral_inversion_t(Channel->Inversion());
|
|
||||||
Frontend.u.ofdm.bandwidth = fe_bandwidth_t(Channel->Bandwidth());
|
|
||||||
Frontend.u.ofdm.code_rate_HP = fe_code_rate_t(Channel->CoderateH());
|
|
||||||
Frontend.u.ofdm.code_rate_LP = fe_code_rate_t(Channel->CoderateL());
|
|
||||||
Frontend.u.ofdm.constellation = fe_modulation_t(Channel->Modulation());
|
|
||||||
Frontend.u.ofdm.transmission_mode = fe_transmit_mode_t(Channel->Transmission());
|
|
||||||
Frontend.u.ofdm.guard_interval = fe_guard_interval_t(Channel->Guard());
|
|
||||||
Frontend.u.ofdm.hierarchy_information = fe_hierarchy_t(Channel->Hierarchy());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discard stale events:
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
dvb_frontend_event event;
|
|
||||||
if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tuning:
|
|
||||||
|
|
||||||
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
|
|
||||||
|
|
||||||
// Wait for channel lock:
|
|
||||||
|
|
||||||
fe_status_t status = fe_status_t(0);
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
|
|
||||||
if (status & FE_HAS_LOCK)
|
|
||||||
break;
|
|
||||||
usleep(10 * 1000);
|
|
||||||
}
|
|
||||||
if (!(status & FE_HAS_LOCK)) {
|
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())
|
if (LiveView && IsPrimaryDevice())
|
||||||
cThread::RaisePanic();
|
cThread::RaisePanic();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
XXX*/
|
||||||
source = Channel->Source();
|
|
||||||
frequency = Channel->Frequency();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PID settings:
|
// PID settings:
|
||||||
|
11
dvbdevice.h
11
dvbdevice.h
@ -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.h 1.18 2002/11/03 12:31:15 kls Exp $
|
* $Id: dvbdevice.h 1.19 2002/12/07 14:44:29 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DVBDEVICE_H
|
#ifndef __DVBDEVICE_H
|
||||||
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#define MAXDVBDEVICES 4
|
#define MAXDVBDEVICES 4
|
||||||
|
|
||||||
|
class cDvbTuner;
|
||||||
|
|
||||||
class cDvbDevice : public cDevice {
|
class cDvbDevice : public cDevice {
|
||||||
friend class cDvbOsd;
|
friend class cDvbOsd;
|
||||||
private:
|
private:
|
||||||
@ -33,7 +35,7 @@ public:
|
|||||||
// Must be called before accessing any DVB functions.
|
// Must be called before accessing any DVB functions.
|
||||||
private:
|
private:
|
||||||
fe_type_t frontendType;
|
fe_type_t frontendType;
|
||||||
int fd_osd, fd_frontend, fd_audio, fd_video, fd_dvr;
|
int fd_osd, fd_audio, fd_video, fd_dvr;
|
||||||
int OsdDeviceHandle(void) const { return fd_osd; }
|
int OsdDeviceHandle(void) const { return fd_osd; }
|
||||||
protected:
|
protected:
|
||||||
virtual void MakePrimaryDevice(bool On);
|
virtual void MakePrimaryDevice(bool On);
|
||||||
@ -53,10 +55,7 @@ public:
|
|||||||
// Channel facilities
|
// Channel facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int source;
|
cDvbTuner *dvbTuner;
|
||||||
int frequency;
|
|
||||||
const char *diseqcCommands;
|
|
||||||
bool IsTunedTo(const cChannel *Channel) const;
|
|
||||||
public:
|
public:
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
||||||
|
Loading…
Reference in New Issue
Block a user