From 3ddef935916adef8f70ec04f126b2486470a3e1e Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 2 Sep 2009 18:27:34 +0000 Subject: [PATCH] extensions to tune dvb-s2 via s2api --- src/dvb/dvb.h | 4 +- src/dvb/dvb_adapter.c | 2 + src/dvb/dvb_fe.c | 100 +++++++++++++++++++++++++++++++++++++-- src/dvb/dvb_multiplex.c | 101 +++++++++++++++++++++++++++++++++------- src/dvb/dvb_tables.c | 46 ++++++++++++++++-- 5 files changed, 226 insertions(+), 27 deletions(-) diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 9fb66ea4..77c7c3c3 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -64,7 +64,9 @@ typedef struct dvb_mux_conf { struct dvb_frontend_parameters dmc_fe_params; int dmc_polarisation; dvb_satconf_t *dmc_satconf; - + fe_modulation_t dmc_fe_modulation; + fe_delivery_system_t dmc_fe_delsys; + fe_rolloff_t dmc_fe_rolloff; } dvb_mux_conf_t; diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 9b6a157d..5dddafa0 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -601,10 +601,12 @@ dvb_fe_opts(th_dvb_adapter_t *tda, const char *which) fe_opts_add(a, "2/3", FEC_2_3); fe_opts_add(a, "3/4", FEC_3_4); fe_opts_add(a, "4/5", FEC_4_5); + fe_opts_add(a, "3/5", FEC_3_5); fe_opts_add(a, "5/6", FEC_5_6); fe_opts_add(a, "6/7", FEC_6_7); fe_opts_add(a, "7/8", FEC_7_8); fe_opts_add(a, "8/9", FEC_8_9); + fe_opts_add(a, "9/10", FEC_9_10); return a; } diff --git a/src/dvb/dvb_fe.c b/src/dvb/dvb_fe.c index 68a37ffe..1b68d7d5 100644 --- a/src/dvb/dvb_fe.c +++ b/src/dvb/dvb_fe.c @@ -174,6 +174,48 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi) } +static int check_frontend (int fe_fd, int dvr, int human_readable) { + (void)dvr; + fe_status_t status; + uint16_t snr, signal; + uint32_t ber, uncorrected_blocks; + int timeout = 0; + + do { + if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1) + perror("FE_READ_STATUS failed"); + /* some frontends might not support all these ioctls, thus we + * avoid printing errors + */ + if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1) + signal = -2; + if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1) + snr = -2; + if (ioctl(fe_fd, FE_READ_BER, &ber) == -1) + ber = -2; + if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1) + uncorrected_blocks = -2; + + if (human_readable) { + printf ("status %02x | signal %3u%% | snr %3u%% | ber %d | unc %d | ", + status, (signal * 100) / 0xffff, (snr * 100) / 0xffff, ber, uncorrected_blocks); + } else { + printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ", + status, signal, snr, ber, uncorrected_blocks); + } + if (status & FE_HAS_LOCK) + printf("FE_HAS_LOCK"); + printf("\n"); + + if ((status & FE_HAS_LOCK) || (++timeout >= 10)) + break; + + usleep(1000000); + } while (1); + + return 0; +} + /** * @@ -245,12 +287,62 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason) "dvb", "\"%s\" tuning to \"%s\" (%s)", tda->tda_rootpath, buf, reason); - r = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, &p); + if (tda->tda_type == FE_QPSK) { + struct dtv_property clear_p[] = { + { .cmd = DTV_CLEAR }, + }; + + struct dtv_properties clear_cmdseq = { + .num = 1, + .props = clear_p + }; + + if ((ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &clear_cmdseq)) != 0) { + perror("FE_SET_PROPERTY DTV_CLEAR failed"); + return; + } + struct dvb_frontend_event ev; + + /* Support for legacy satellite tune, with the new API. */ + struct dtv_property _dvbs_cmdargs[] = { + { .cmd = DTV_DELIVERY_SYSTEM, .u.data = tdmi->tdmi_conf.dmc_fe_delsys }, + { .cmd = DTV_FREQUENCY, .u.data = p.frequency }, + { .cmd = DTV_MODULATION, .u.data = tdmi->tdmi_conf.dmc_fe_modulation }, + { .cmd = DTV_SYMBOL_RATE, .u.data = p.u.qpsk.symbol_rate }, + { .cmd = DTV_INNER_FEC, .u.data = p.u.qpsk.fec_inner }, + { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO }, + { .cmd = DTV_ROLLOFF, .u.data = tdmi->tdmi_conf.dmc_fe_rolloff }, + { .cmd = DTV_PILOT, .u.data = PILOT_AUTO }, + { .cmd = DTV_TUNE }, + }; + + struct dtv_properties _dvbs_cmdseq = { + .num = 9, + .props = _dvbs_cmdargs + }; + + /* discard stale QPSK events */ + while (1) { + if (ioctl(tda->tda_fe_fd, FE_GET_EVENT, &ev) == -1) + break; + } + + tvhlog(LOG_INFO, + "dvb", "tuning via s2api to %s, freq %d, symbolrate %d, fec %d, sys %d, mod %d", + buf, p.frequency, p.u.qpsk.symbol_rate, p.u.qpsk.fec_inner, tdmi->tdmi_conf.dmc_fe_delsys, + tdmi->tdmi_conf.dmc_fe_modulation); + r = ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &_dvbs_cmdseq); + + if(0) + check_frontend (tda->tda_fe_fd, 0, 1); + } else + r = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, &p); + if(r != 0) { tvhlog(LOG_ERR, "dvb", "\"%s\" tuning to \"%s\"" - " -- Front configuration failed -- %s", - tda->tda_rootpath, buf, strerror(errno)); - } + " -- Front configuration failed -- %s", + tda->tda_rootpath, buf, strerror(errno)); + } tda->tda_mux_current = tdmi; diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index 0598a551..dc012c12 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -133,7 +133,10 @@ tdmi_compare_conf(int adapter_type, case FE_QPSK: return memcmp(&a->dmc_fe_params.u.qpsk, &b->dmc_fe_params.u.qpsk, - sizeof(a->dmc_fe_params.u.qpsk)); + sizeof(a->dmc_fe_params.u.qpsk)) || + a->dmc_fe_modulation != b->dmc_fe_modulation || + a->dmc_fe_delsys != b->dmc_fe_delsys || + a->dmc_fe_rolloff != b->dmc_fe_rolloff; } return 0; } @@ -166,6 +169,8 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc, if(!tdmi_compare_conf(tda->tda_type, &tdmi->tdmi_conf, dmc)) return NULL; // Nothings changed + memcpy(&tdmi->tdmi_conf, dmc, sizeof(struct dvb_mux_conf)); + dvb_mux_save(tdmi); dvb_mux_nicename(buf, sizeof(buf), tdmi); @@ -315,9 +320,12 @@ dvb_mux_find_by_identifier(const char *identifier) } - - - +static struct strtab rollofftab[] = { + { "ROLLOFF_35", ROLLOFF_35 }, + { "ROLLOFF_20", ROLLOFF_20 }, + { "ROLLOFF_25", ROLLOFF_25 }, + { "ROLLOFF_AUTO", ROLLOFF_AUTO } +}; static struct strtab fectab[] = { { "NONE", FEC_NONE }, @@ -329,19 +337,44 @@ static struct strtab fectab[] = { { "6/7", FEC_6_7 }, { "7/8", FEC_7_8 }, { "8/9", FEC_8_9 }, - { "AUTO", FEC_AUTO } + { "AUTO", FEC_AUTO }, + { "3/5", FEC_3_4 }, + { "9/10", FEC_9_10 } }; static struct strtab qamtab[] = { - { "QPSK", QPSK }, - { "QAM16", QAM_16 }, - { "QAM32", QAM_32 }, - { "QAM64", QAM_64 }, - { "QAM128", QAM_128 }, - { "QAM256", QAM_256 }, - { "AUTO", QAM_AUTO }, - { "8VSB", VSB_8 }, - { "16VSB", VSB_16 } + { "QPSK", QPSK }, + { "QAM16", QAM_16 }, + { "QAM32", QAM_32 }, + { "QAM64", QAM_64 }, + { "QAM128", QAM_128 }, + { "QAM256", QAM_256 }, + { "AUTO", QAM_AUTO }, + { "8VSB", VSB_8 }, + { "16VSB", VSB_16 }, + { "PSK_8", PSK_8 }, + { "APSK_16", APSK_16 }, + { "APSK_32", APSK_32 }, + { "DQPSK", DQPSK } +}; + +static struct strtab delsystab[] = { + { "SYS_UNDEFINED", SYS_UNDEFINED }, + { "SYS_DVBC_ANNEX_AC", SYS_DVBC_ANNEX_AC }, + { "SYS_DVBC_ANNEX_B", SYS_DVBC_ANNEX_B }, + { "SYS_DVBT", SYS_DVBT }, + { "SYS_DSS", SYS_DSS }, + { "SYS_DVBS", SYS_DVBS }, + { "SYS_DVBS2", SYS_DVBS2 }, + { "SYS_DVBH", SYS_DVBH }, + { "SYS_ISDBT", SYS_ISDBT }, + { "SYS_ISDBS", SYS_ISDBS }, + { "SYS_ISDBC", SYS_ISDBC }, + { "SYS_ATSC", SYS_ATSC }, + { "SYS_ATSCMH", SYS_ATSCMH }, + { "SYS_DMBTH", SYS_DMBTH }, + { "SYS_CMMB", SYS_CMMB }, + { "SYS_DAB", SYS_DAB } }; static struct strtab bwtab[] = { @@ -429,10 +462,19 @@ dvb_mux_save(th_dvb_mux_instance_t *tdmi) htsmsg_add_u32(m, "symbol_rate", f->u.qpsk.symbol_rate); htsmsg_add_str(m, "fec", - val2str(f->u.qpsk.fec_inner, fectab)); + val2str(f->u.qpsk.fec_inner, fectab)); htsmsg_add_str(m, "polarisation", - val2str(tdmi->tdmi_conf.dmc_polarisation, poltab)); + val2str(tdmi->tdmi_conf.dmc_polarisation, poltab)); + + htsmsg_add_str(m, "modulation", + val2str(tdmi->tdmi_conf.dmc_fe_modulation, qamtab)); + + htsmsg_add_str(m, "delivery_system", + val2str(tdmi->tdmi_conf.dmc_fe_delsys, delsystab)); + + htsmsg_add_str(m, "rolloff", + val2str(tdmi->tdmi_conf.dmc_fe_rolloff, rollofftab)); break; case FE_QAM: @@ -470,7 +512,6 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier) struct dvb_mux_conf dmc; const char *s; int r; - int polarisation = 0; unsigned int tsid, u32, enabled; dvb_satconf_t *sc; @@ -531,7 +572,31 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier) s = htsmsg_get_str(m, "polarisation"); if(s == NULL || (r = str2val(s, poltab)) < 0) return "Invalid polarisation"; - polarisation = r; + dmc.dmc_polarisation = r; + + s = htsmsg_get_str(m, "modulation"); + if(s == NULL || (r = str2val(s, qamtab)) < 0) { + r = str2val("QPSK", qamtab); + tvhlog(LOG_INFO, + "dvb", "no modulation for mux found, defaulting to QPSK"); + } + dmc.dmc_fe_modulation = r; + + s = htsmsg_get_str(m, "delivery_system"); + if(s == NULL || (r = str2val(s, delsystab)) < 0) { + r = str2val("SYS_DVBS", delsystab); + tvhlog(LOG_INFO, + "dvb", "no delivery system for mux found, defaulting to SYS_DVBS"); + } + dmc.dmc_fe_delsys = r; + + s = htsmsg_get_str(m, "rolloff"); + if(s == NULL || (r = str2val(s, rollofftab)) < 0) { + r = str2val("ROLLOFF_35", rollofftab); + tvhlog(LOG_INFO, + "dvb", "no rolloff for mux found, defaulting to ROLLOFF_35"); + } + dmc.dmc_fe_rolloff = r; break; case FE_QAM: diff --git a/src/dvb/dvb_tables.c b/src/dvb/dvb_tables.c index fb6ba6c5..e9be2707 100644 --- a/src/dvb/dvb_tables.c +++ b/src/dvb/dvb_tables.c @@ -800,9 +800,11 @@ dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, /** * Tables for delivery descriptor parsing */ -static const fe_code_rate_t fec_tab [8] = { +static const fe_code_rate_t fec_tab [16] = { FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4, - FEC_5_6, FEC_7_8, FEC_NONE, FEC_NONE + FEC_5_6, FEC_7_8, FEC_8_9, FEC_3_5, + FEC_4_5, FEC_9_10, FEC_NONE, FEC_NONE, + FEC_NONE, FEC_NONE, FEC_NONE, FEC_NONE }; @@ -862,7 +864,7 @@ static int dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, uint16_t tsid) { - int freq, symrate; + int freq, symrate, modulation; struct dvb_mux_conf dmc; if(!tdmi->tdmi_adapter->tda_autodiscovery) @@ -884,14 +886,50 @@ dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, bcdtoint(ptr[9]) * 10 + (ptr[10] >> 4); dmc.dmc_fe_params.u.qam.symbol_rate = symrate * 100; - dmc.dmc_fe_params.u.qam.fec_inner = fec_tab[ptr[10] & 0x07]; + dmc.dmc_fe_params.u.qam.fec_inner = fec_tab[ptr[10] & 0x0f]; dmc.dmc_polarisation = (ptr[6] >> 5) & 0x03; // Same satconf (lnb, switch, etc) dmc.dmc_satconf = tdmi->tdmi_conf.dmc_satconf; + modulation = (ptr[6] & 0x03); + + if (modulation == 0x01) + dmc.dmc_fe_modulation = QPSK; + else if (modulation == 0x02) + dmc.dmc_fe_modulation = PSK_8; + else if (modulation == 0x03) + dmc.dmc_fe_modulation = QAM_16; + else + dmc.dmc_fe_modulation = 0; + + if (ptr[6] & 0x04) { + dmc.dmc_fe_delsys = SYS_DVBS2; + + switch ((ptr[6] >> 3) & 0x03) { + case 0x00: + dmc.dmc_fe_rolloff = ROLLOFF_35; + break; + case 0x01: + dmc.dmc_fe_rolloff = ROLLOFF_25; + break; + case 0x02: + dmc.dmc_fe_rolloff = ROLLOFF_20; + break; + default: + case 0x03: + dmc.dmc_fe_rolloff = ROLLOFF_AUTO; + break; + } + } + else { + dmc.dmc_fe_delsys = SYS_DVBS; + dmc.dmc_fe_rolloff = ROLLOFF_35; + } + dvb_mux_create(tdmi->tdmi_adapter, &dmc, tsid, NULL, "automatic mux discovery", 1, NULL); + return 0; }