diff --git a/Makefile b/Makefile index 0d7292d7..bbd14fcc 100644 --- a/Makefile +++ b/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 diff --git a/diseqc.c b/diseqc.c new file mode 100644 index 00000000..b2b0d61f --- /dev/null +++ b/diseqc.c @@ -0,0 +1,92 @@ +#include +#include +#include + +//#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); +} + + diff --git a/diseqc.h b/diseqc.h new file mode 100644 index 00000000..2038962a --- /dev/null +++ b/diseqc.h @@ -0,0 +1,24 @@ +#ifndef __DISEQC_H__ +#define __DISEQC_H__ + +#include +#include + + +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 + diff --git a/dvb.h b/dvb.h index 7d2c3a42..72946499 100644 --- a/dvb.h +++ b/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; diff --git a/dvb_fe.c b/dvb_fe.c index 561d551f..1d11f9f6 100644 --- a/dvb_fe.c +++ b/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" diff --git a/dvb_muxconfig.c b/dvb_muxconfig.c index cc940fdb..28451878 100644 --- a/dvb_muxconfig.c +++ b/dvb_muxconfig.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -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; } diff --git a/man/tvheadend.1 b/man/tvheadend.1 index 048e562e..24be00ee 100644 --- a/man/tvheadend.1 +++ b/man/tvheadend.1 @@ -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\fR +Low band bottom frequency, defaults to 9,750,000 kHz +.TP +\fB\tlnb_hifreq = \fR\fI\fR +High band bottom frequency, defaults to 10,600,000 kHz +.TP +\fB\tlnb_switchfreq = \fR\fI\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. diff --git a/tvhead.h b/tvhead.h index 30cd2a65..62d52620 100644 --- a/tvhead.h +++ b/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 */