Add support for DVB-S and LNB setup via voltage control and diseqc.
This commit is contained in:
parent
96bea3b8eb
commit
5fe9339e0f
8 changed files with 252 additions and 16 deletions
3
Makefile
3
Makefile
|
@ -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
92
diseqc.c
Normal 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
24
diseqc.h
Normal 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
7
dvb.h
|
@ -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;
|
||||
|
|
30
dvb_fe.c
30
dvb_fe.c
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
1
tvhead.h
1
tvhead.h
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue