Add support for DVB-S and LNB setup via voltage control and diseqc.

This commit is contained in:
Andreas Öman 2008-03-30 18:36:12 +00:00
parent 96bea3b8eb
commit 5fe9339e0f
8 changed files with 252 additions and 16 deletions

View file

@ -12,7 +12,8 @@ SRCS += pvr.c autorec.c ffmuxer.c
SRCS += epg.c epg_xmltv.c
SRCS += dvb.c dvb_support.c dvb_dvr.c dvb_muxconfig.c dvb_fe.c dvb_tables.c
SRCS += dvb.c dvb_support.c dvb_dvr.c dvb_muxconfig.c dvb_fe.c dvb_tables.c \
diseqc.c
SRCS += iptv_input.c iptv_output.c

92
diseqc.c Normal file
View file

@ -0,0 +1,92 @@
#include <linux/dvb/frontend.h>
#include <sys/ioctl.h>
#include <time.h>
//#include "scan.h"
#include "diseqc.h"
struct diseqc_cmd switch_cmds[] = {
{ { { 0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf2, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf1, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf3, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf4, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf6, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf5, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf7, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf8, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xfa, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xf9, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xfb, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xfc, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xfe, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xfd, 0x00, 0x00 }, 4 }, 0 },
{ { { 0xe0, 0x10, 0x38, 0xff, 0x00, 0x00 }, 4 }, 0 }
};
/*--------------------------------------------------------------------------*/
static inline
void msleep(uint32_t msec)
{
struct timespec req = { msec / 1000, 1000000 * (msec % 1000) };
while (nanosleep(&req, &req))
;
}
#define printf(x...)
int diseqc_send_msg (int fd, fe_sec_voltage_t v, struct diseqc_cmd **cmd,
fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
{
int err;
if ((err = ioctl(fd, FE_SET_TONE, SEC_TONE_OFF)))
return err;
if ((err = ioctl(fd, FE_SET_VOLTAGE, v)))
return err;
msleep(15);
while (*cmd) {
if ((err = ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &(*cmd)->cmd)))
return err;
msleep((*cmd)->wait);
cmd++;
}
msleep(15);
if ((err = ioctl(fd, FE_DISEQC_SEND_BURST, b)))
return err;
msleep(15);
return ioctl(fd, FE_SET_TONE, t);
}
int diseqc_setup(int frontend_fd, int switch_pos, int voltage_18, int hiband)
{
struct diseqc_cmd *cmd[2] = { NULL, NULL };
int i = 4 * switch_pos + 2 * hiband + (voltage_18 ? 1 : 0);
if(i < 0 || i >= (int) (sizeof(switch_cmds)/sizeof(struct diseqc_cmd)))
return -1;
cmd[0] = &switch_cmds[i];
return diseqc_send_msg (frontend_fd,
i % 2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13,
cmd,
(i/2) % 2 ? SEC_TONE_ON : SEC_TONE_OFF,
(i/4) % 2 ? SEC_MINI_B : SEC_MINI_A);
}

24
diseqc.h Normal file
View file

@ -0,0 +1,24 @@
#ifndef __DISEQC_H__
#define __DISEQC_H__
#include <stdint.h>
#include <linux/dvb/frontend.h>
struct diseqc_cmd {
struct dvb_diseqc_master_cmd cmd;
uint32_t wait;
};
extern int diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd **cmd,
fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b);
/**
* set up the switch to position/voltage/tone
*/
int diseqc_setup(int frontend_fd, int switch_pos, int voltage_18, int hiband);
#endif

7
dvb.h
View file

@ -19,6 +19,13 @@
#ifndef DVB_H_
#define DVB_H_
enum polarisation {
POLARISATION_HORIZONTAL = 0x00,
POLARISATION_VERTICAL = 0x01,
POLARISATION_CIRCULAR_LEFT = 0x02,
POLARISATION_CIRCULAR_RIGHT = 0x03
};
#define DVB_FEC_ERROR_LIMIT 20
extern struct th_dvb_adapter_list dvb_adapters_probing;

View file

@ -38,7 +38,7 @@
#include "dispatch.h"
#include "dvb.h"
#include "dvb_support.h"
#include "diseqc.h"
typedef struct dvb_fe_cmd {
TAILQ_ENTRY(dvb_fe_cmd) link;
@ -61,6 +61,7 @@ dvb_fe_manager(void *aux)
th_dvb_mux_instance_t *tdmi = NULL;
fe_status_t fe_status;
th_dvb_table_t *tdt;
struct dvb_frontend_parameters p;
while(1) {
ts.tv_sec = time(NULL) + 1;
@ -80,7 +81,32 @@ dvb_fe_manager(void *aux)
tdmi = c->tdmi;
i = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, tdmi->tdmi_fe_params);
p = *tdmi->tdmi_fe_params;
if(tdmi->tdmi_type == FE_QPSK) {
/* DVB-S */
int lowfreq, hifreq, switchfreq, hiband;
lowfreq = atoi(config_get_str("lnb_lowfreq", "9750000" ));
hifreq = atoi(config_get_str("lnb_hifreq", "10600000"));
switchfreq = atoi(config_get_str("lnb_switchfreq", "11700000"));
hiband = switchfreq && p.frequency > switchfreq;
diseqc_setup(tda->tda_fe_fd,
0, /* switch position */
tdmi->tdmi_polarisation == POLARISATION_HORIZONTAL,
hiband);
usleep(50000);
if(hiband)
p.frequency = abs(p.frequency - hifreq);
else
p.frequency = abs(p.frequency - lowfreq);
}
i = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, &p);
if(i != 0) {
syslog(LOG_ERR, "\"%s\" tuning to %dHz"

View file

@ -21,6 +21,7 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <linux/dvb/frontend.h>
@ -35,7 +36,8 @@
static void
dvb_add_mux(struct dvb_frontend_parameters *fe_param, fe_type_t type)
dvb_add_mux(struct dvb_frontend_parameters *fe_param, fe_type_t type,
int polarisation)
{
th_dvb_adapter_t *tda;
char buf[100];
@ -74,20 +76,35 @@ dvb_add_mux(struct dvb_frontend_parameters *fe_param, fe_type_t type)
tdmi->tdmi_type = type;
tdmi->tdmi_fe_params = malloc(sizeof(struct dvb_frontend_parameters));
tdmi->tdmi_polarisation = polarisation;
memcpy(tdmi->tdmi_fe_params, fe_param,
sizeof(struct dvb_frontend_parameters));
/* Generate names */
if(tdmi->tdmi_type == FE_QPSK) {
const char *pol;
switch(polarisation) {
case POLARISATION_VERTICAL: pol = "V"; break;
case POLARISATION_HORIZONTAL: pol = "H"; break;
default: pol = "X"; break;
}
/* Frequency is in kHz */
snprintf(buf, sizeof(buf), "%s/%.1fMHz/%s",
typetxt, (float)fe_param->frequency / 1000.0f, pol);
} else {
snprintf(buf, sizeof(buf), "%s/%.1fMHz",
typetxt, (float)fe_param->frequency / 1000000.0f);
}
tdmi->tdmi_shortname = strdup(buf);
snprintf(buf, sizeof(buf), "%s/%s/%.1fMHz",
tda->tda_sname, typetxt,
(float)fe_param->frequency / 1000000.0f);
snprintf(buf, sizeof(buf), "%s/%s", tda->tda_sname, tdmi->tdmi_shortname),
tdmi->tdmi_uniquename = strdup(buf);
snprintf(buf, sizeof(buf), "%s/%.1fMHz",
typetxt, (float)fe_param->frequency / 1000000.0f);
tdmi->tdmi_shortname = strdup(buf);
}
}
@ -180,7 +197,7 @@ dvb_t_config(const char *l)
r = str2val(fec2, fectab);
f.u.ofdm.code_rate_LP = r == FEC_NONE ? FEC_AUTO : r;
dvb_add_mux(&f, FE_OFDM);
dvb_add_mux(&f, FE_OFDM, 0);
}
@ -207,7 +224,45 @@ dvb_c_config(const char *l)
f.u.qam.fec_inner = str2val(fec, fectab);
f.u.qam.modulation = str2val(qam, qamtab);
dvb_add_mux(&f, FE_QAM);
dvb_add_mux(&f, FE_QAM, 0);
}
static void
dvb_s_config(const char *l)
{
unsigned long freq, symrate;
char fec[20], polarisation;
struct dvb_frontend_parameters f;
int r;
r = sscanf(l, "%lu %c %lu %s",
&freq, &polarisation, &symrate, fec);
if(r != 4)
return;
memset(&f, 0, sizeof(f));
f.inversion = INVERSION_AUTO;
f.frequency = freq;
f.u.qpsk.symbol_rate = symrate;
f.u.qpsk.fec_inner = str2val(fec, fectab);
switch(toupper(polarisation)) {
case 'V':
polarisation = POLARISATION_VERTICAL;
break;
case 'H':
polarisation = POLARISATION_HORIZONTAL;
break;
default:
return;
}
dvb_add_mux(&f, FE_QPSK, polarisation);
}
@ -244,6 +299,10 @@ dvb_muxfile_add(const char *fname)
dvb_c_config(line + 1);
break;
case 'S':
dvb_s_config(line + 1);
break;
default:
break;
}

View file

@ -147,7 +147,17 @@ adapters.
.SS "DVB Adapters"
TVheadend will probe all DVB it can find in /dev/dvb/adapterX.
All adapters will be registered and probed according to the configuration
files given (see below).
files given (see below). Due to limited testing not all DVB standards has
been fully confirmed to work.
.TP
\fB\tDVB-T \fRWorking
.TP
\fB\tDVB-C \fRWorking
.TP
\fB\tDVB-S \fRExperimental
.TP
\fB\tATSC \fRNot implmented
.PP
Currently, only DVB-T and DVB-C adapters are supported.
The primary reason for this is that nobody has yet has been able to test
tvheadend with a DVB-S card.
@ -160,8 +170,8 @@ used for the dvb-utils
utility (where it is called 'initial-tuning-data-file').
.PP
Add this to your configuration file:
.PP
dvbmuxfile = /path/to/your/mux/description/file
.TP
\fB\tdvbmuxfile = \fR\fI/path/to/your/mux/description/file\fR
.PP
Multiple 'dvbmuxfile'-statements can be added if you have multiple
adapters connected to different DVB networks. Tvheadend will make sure
@ -172,6 +182,22 @@ Tvheadend can not by itself scan for muxes nor can it use the
information received in the NIT (Network Information Table) to add
multiplexes by itself. This might be implemented in the future if
there is such a demand.
.SS "LNB configuration"
To configure the LO/HI bands of the LNB use the following configuration
statements.
.TP
\fB\tlnb_lowfreq = \fR\fI<frequency in kHz>\fR
Low band bottom frequency, defaults to 9,750,000 kHz
.TP
\fB\tlnb_hifreq = \fR\fI<frequency in kHz>\fR
High band bottom frequency, defaults to 10,600,000 kHz
.TP
\fB\tlnb_switchfreq = \fR\fI<frequency in kHz>\fR
If transponder frequency is higher than this, it will switch the LNB to
the HI band. Defaults to 11,700,000 kHz.
.PP
Thus, the default configuration reflects a Universal LNB for Europe.
(10800 to 11800 MHz and 11600 to 12700 Mhz)
.SS "MPEG Transport Stream Multiplex"
Tvheadend's internal concept of a MUX maps directly to a MPEG
transport stream multiplex as defined in ITU-T Recommendation H.222.0.

View file

@ -174,6 +174,7 @@ typedef struct th_dvb_mux_instance {
int tdmi_type; /* really fe_type_t */
struct dvb_frontend_parameters *tdmi_fe_params;
int tdmi_polarisation;
const char *tdmi_shortname; /* Only unique for the specific adapter */
const char *tdmi_uniquename; /* Globally unique */