diff --git a/Makefile b/Makefile index 5cda57d1..fe5a3e92 100644 --- a/Makefile +++ b/Makefile @@ -176,6 +176,7 @@ SRCS-${CONFIG_LINUXDVB} += \ src/input/mpegts/linuxdvb/linuxdvb_mux.c \ src/input/mpegts/linuxdvb/linuxdvb_service.c \ src/input/mpegts/linuxdvb/linuxdvb_satconf.c \ + src/input/mpegts/linuxdvb/diseqc.c # IPTV SRCS-${CONFIG_IPTV} += \ diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index 8caf5e71..3ac7a0e3 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -257,7 +257,7 @@ linuxdvb_frontend_is_enabled ( mpegts_input_t *mi ) static void linuxdvb_frontend_display_name ( mpegts_input_t* mi, char *buf, size_t len ) { - strncpy(buf, linuxdvb_frontend_class_get_title(&mi->mi_id), len); + strncpy(buf, linuxdvb_frontend_class_get_title(&mi->mi_id) ?: "", len); } #if 0 @@ -312,55 +312,7 @@ static int linuxdvb_frontend_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi ) { - int r; - char buf1[256], buf2[256]; - linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi; - mpegts_mux_instance_t *cur = LIST_FIRST(&mi->mi_mux_active); - - mi->mi_display_name(mi, buf1, sizeof(buf1)); - mmi->mmi_mux->mm_display_name(mmi->mmi_mux, buf2, sizeof(buf2)); - tvhdebug("linuxdvb", "%s - starting %s", buf1, buf2); - - // Not sure if this is right place? - /* Currently active */ - if (cur != NULL) { - - /* Already tuned */ - if (mmi == cur) - return 0; - - /* Stop current */ - cur->mmi_mux->mm_stop(cur->mmi_mux); - } - assert(LIST_FIRST(&mi->mi_mux_active) == NULL); - - /* Open FE */ - if (lfe->lfe_fe_fd <= 0) { - lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0); - tvhtrace("linuxdvb", "%s - opening FE %s (%d)", buf1, lfe->lfe_fe_path, lfe->lfe_fe_fd); - if (lfe->lfe_fe_fd <= 0) { - return SM_CODE_TUNING_FAILED; - } - } - - /* Tune */ - tvhtrace("linuxdvb", "%s - tuning", buf1); - r = linuxdvb_frontend_tune(lfe, (linuxdvb_mux_t*)mmi->mmi_mux, -1); - - /* Failed */ - if (r != 0) { - tvherror("linuxdvb", "%s - failed to tune [e=%s]", buf1, strerror(errno)); - if (errno == EINVAL) - mmi->mmi_tune_failed = 1; - return SM_CODE_TUNING_FAILED; - } - - /* Start monitor */ - time(&lfe->lfe_monitor); - lfe->lfe_monitor += 4; - gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50); - - return r; + return linuxdvb_frontend_tune1((linuxdvb_frontend_t*)mi, mmi, -1); } static int @@ -512,7 +464,7 @@ linuxdvb_frontend_monitor ( void *aux ) if (!mmi) return; mm = mmi->mmi_mux; lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf)); - tvhdebug("linuxdvb", "%s - checking FE status", buf); + tvhtrace("linuxdvb", "%s - checking FE status", buf); /* Get current status */ if (ioctl(lfe->lfe_fe_fd, FE_READ_STATUS, &fe_status) == -1) { @@ -529,6 +481,7 @@ linuxdvb_frontend_monitor ( void *aux ) /* Set default period */ gtimer_arm(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 1); + tvhtrace("linuxdvb", "%s - starus %d", buf, status); /* Waiting for lock */ if (!lfe->lfe_locked) { @@ -665,11 +618,37 @@ linuxdvb_frontend_input_thread ( void *aux ) * *************************************************************************/ int -linuxdvb_frontend_tune - ( linuxdvb_frontend_t *lfe, linuxdvb_mux_t *lm, uint32_t freq ) +linuxdvb_frontend_tune0 + ( linuxdvb_frontend_t *lfe, mpegts_mux_instance_t *mmi, uint32_t freq ) { int r; struct dvb_frontend_event ev; + char buf1[256]; + mpegts_mux_instance_t *cur = LIST_FIRST(&lfe->mi_mux_active); + linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mmi->mmi_mux; + + // Not sure if this is right place? + /* Currently active */ + if (cur != NULL) { + + /* Already tuned */ + if (mmi == cur) + return 0; + + /* Stop current */ + cur->mmi_mux->mm_stop(cur->mmi_mux); + } + assert(LIST_FIRST(&lfe->mi_mux_active) == NULL); + + /* Open FE */ + if (lfe->lfe_fe_fd <= 0) { + lfe->mi_display_name((mpegts_input_t*)lfe, buf1, sizeof(buf1)); + lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0); + tvhtrace("linuxdvb", "%s - opening FE %s (%d)", buf1, lfe->lfe_fe_path, lfe->lfe_fe_fd); + if (lfe->lfe_fe_fd <= 0) { + return SM_CODE_TUNING_FAILED; + } + } /* S2 tuning */ #if DVB_API_VERSION >= 5 @@ -753,6 +732,37 @@ linuxdvb_frontend_tune r = ioctl(lfe->lfe_fe_fd, FE_SET_FRONTEND, p); #endif + /* Failed */ + if (r != 0) { + tvherror("linuxdvb", "%s - failed to tune [e=%s]", buf1, strerror(errno)); + if (errno == EINVAL) + mmi->mmi_tune_failed = 1; + return SM_CODE_TUNING_FAILED; + } + + return r; +} + +int +linuxdvb_frontend_tune1 + ( linuxdvb_frontend_t *lfe, mpegts_mux_instance_t *mmi, uint32_t freq ) +{ + int r; + char buf1[256], buf2[256]; + + lfe->mi_display_name((mpegts_input_t*)lfe, buf1, sizeof(buf1)); + mmi->mmi_mux->mm_display_name(mmi->mmi_mux, buf2, sizeof(buf2)); + tvhdebug("linuxdvb", "%s - starting %s", buf1, buf2); + + /* Tune */ + tvhtrace("linuxdvb", "%s - tuning", buf1); + r = linuxdvb_frontend_tune0(lfe, mmi, freq); + + /* Start monitor */ + time(&lfe->lfe_monitor); + lfe->lfe_monitor += 4; + gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50); + return r; } @@ -802,9 +812,9 @@ linuxdvb_frontend_create0 lfe->mi_stop_mux = linuxdvb_frontend_stop_mux; lfe->mi_open_service = linuxdvb_frontend_open_service; lfe->mi_close_service = linuxdvb_frontend_close_service; - lfe->lfe_open_pid = linuxdvb_frontend_open_pid; lfe->mi_network_class = linuxdvb_frontend_network_class; lfe->mi_network_create = linuxdvb_frontend_network_create; + lfe->lfe_open_pid = linuxdvb_frontend_open_pid; /* Adapter link */ lfe->lh_parent = (linuxdvb_hardware_t*)la; diff --git a/src/input/mpegts/linuxdvb/linuxdvb_mux.c b/src/input/mpegts/linuxdvb/linuxdvb_mux.c index ce15307f..db7555a7 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_mux.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_mux.c @@ -73,6 +73,20 @@ linuxdvb_mux_##c##_class_##l##_enum (void *o)\ .str_set = linuxdvb_mux_##t##_class_##l##_set,\ .str_enum = linuxdvb_mux_##t##_class_##l##_enum +static const char * +linuxdvb_mux_class_delsys_get (void *o) +{ + linuxdvb_mux_t *lm = o; + return dvb_delsys2str(lm->lm_tuning.dmc_fe_delsys); +} +static int +linuxdvb_mux_class_delsys_set (void *o, const char *s) +{ + linuxdvb_mux_t *lm = o; + lm->lm_tuning.dmc_fe_delsys = dvb_str2delsys(s); + return 1; +} + const idclass_t linuxdvb_mux_class = { .ic_super = &mpegts_mux_class, @@ -135,12 +149,27 @@ linuxdvb_mux_class_X(dvbt, ofdm, code_rate_LP, feclo, #endif ); +#define linuxdvb_mux_dvbt_class_delsys_get linuxdvb_mux_class_delsys_get +#define linuxdvb_mux_dvbt_class_delsys_set linuxdvb_mux_class_delsys_set +static htsmsg_t * +linuxdvb_mux_dvbt_class_delsys_enum (void *o) +{ + htsmsg_t *list = htsmsg_create_list(); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_DVBT)); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_DVBT2)); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_TURBO)); + return list; +} + const idclass_t linuxdvb_mux_dvbt_class = { .ic_super = &linuxdvb_mux_class, .ic_class = "linuxdvb_mux_dvbt", .ic_caption = "Linux DVB-T Multiplex", .ic_properties = (const property_t[]){ + { + MUX_PROP_STR("delsys", "Delivery System", dvbt, delsys), + }, { .type = PT_U32, .id = "frequency", @@ -187,12 +216,27 @@ linuxdvb_mux_class_X(dvbc, qam, fec_inner, fec, , FEC_9_10 #endif ); + +#define linuxdvb_mux_dvbc_class_delsys_get linuxdvb_mux_class_delsys_get +#define linuxdvb_mux_dvbc_class_delsys_set linuxdvb_mux_class_delsys_set +static htsmsg_t * +linuxdvb_mux_dvbc_class_delsys_enum (void *o) +{ + htsmsg_t *list = htsmsg_create_list(); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_DVBC_ANNEX_AC)); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_DVBC_ANNEX_B)); + return list; +} + const idclass_t linuxdvb_mux_dvbc_class = { .ic_super = &linuxdvb_mux_class, .ic_class = "linuxdvb_mux_dvbc", .ic_caption = "Linux DVB-C Multiplex", .ic_properties = (const property_t[]){ + { + MUX_PROP_STR("delsys", "Delivery System", dvbc, delsys), + }, { .type = PT_U32, .id = "frequency", @@ -255,12 +299,26 @@ linuxdvb_mux_dvbs_class_polarity_enum (void *o) return list; } +#define linuxdvb_mux_dvbs_class_delsys_get linuxdvb_mux_class_delsys_get +#define linuxdvb_mux_dvbs_class_delsys_set linuxdvb_mux_class_delsys_set +static htsmsg_t * +linuxdvb_mux_dvbs_class_delsys_enum (void *o) +{ + htsmsg_t *list = htsmsg_create_list(); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_DVBS)); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_DVBS2)); + return list; +} + const idclass_t linuxdvb_mux_dvbs_class = { .ic_super = &linuxdvb_mux_class, .ic_class = "linuxdvb_mux_dvbs", .ic_caption = "Linux DVB-S Multiplex", .ic_properties = (const property_t[]){ + { + MUX_PROP_STR("delsys", "Delivery System", dvbs, delsys), + }, { .type = PT_U32, .id = "frequency", @@ -288,12 +346,26 @@ const idclass_t linuxdvb_mux_dvbs_class = } }; +#define linuxdvb_mux_atsc_class_delsys_get linuxdvb_mux_class_delsys_get +#define linuxdvb_mux_atsc_class_delsys_set linuxdvb_mux_class_delsys_set +static htsmsg_t * +linuxdvb_mux_atsc_class_delsys_enum (void *o) +{ + htsmsg_t *list = htsmsg_create_list(); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_ATSC)); + htsmsg_add_str(list, NULL, dvb_delsys2str(SYS_ATSCMH)); + return list; +} + const idclass_t linuxdvb_mux_atsc_class = { .ic_super = &linuxdvb_mux_class, .ic_class = "linuxdvb_mux_atsc", .ic_caption = "Linux ATSC Multiplex", .ic_properties = (const property_t[]){ + { + MUX_PROP_STR("delsys", "Delivery System", atsc, delsys), + }, {} } }; diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index c83c4ccd..4e251b24 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -171,8 +171,10 @@ linuxdvb_frontend_added void linuxdvb_frontend_add_network ( linuxdvb_frontend_t *lfe, linuxdvb_network_t *net ); -int linuxdvb_frontend_tune - ( linuxdvb_frontend_t *lfe, linuxdvb_mux_t *lm, uint32_t freq ); +int linuxdvb_frontend_tune0 + ( linuxdvb_frontend_t *lfe, mpegts_mux_instance_t *mmi, uint32_t freq ); +int linuxdvb_frontend_tune1 + ( linuxdvb_frontend_t *lfe, mpegts_mux_instance_t *mmi, uint32_t freq ); /* * Network @@ -233,7 +235,7 @@ struct linuxdvb_lnb */ struct linuxdvb_satconf { - mpegts_input_t; + linuxdvb_frontend_t; /* Links */ mpegts_input_t *ls_frontend; diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index d3171f22..61544f72 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -19,6 +19,7 @@ #include "tvheadend.h" #include "linuxdvb_private.h" +#include "diseqc.h" #include #include @@ -33,7 +34,7 @@ * Class definition * *************************************************************************/ -extern const idclass_t linuxdvb_hardware_class; +extern const idclass_t mpegts_input_class; static const char* linuxdvb_satconf_class_network_get(void *o) @@ -47,19 +48,21 @@ linuxdvb_satconf_class_network_get(void *o) static int linuxdvb_satconf_class_network_set(void *o, const char *s) { + extern const idclass_t linuxdvb_network_class; mpegts_input_t *mi = o; mpegts_network_t *mn = mi->mi_network; - linuxdvb_network_t *ln = (linuxdvb_network_t*)mn; if (mi->mi_network && !strcmp(idnode_uuid_as_str(&mn->mn_id), s ?: "")) return 0; - if (ln->ln_type != FE_QPSK) { + mn = s ? idnode_find(s, &linuxdvb_network_class) : NULL; + + if (mn && ((linuxdvb_network_t*)mn)->ln_type != FE_QPSK) { tvherror("linuxdvb", "attempt to set network of wrong type"); return 0; } - mpegts_input_set_network(mi, s ? mpegts_network_find(s) : NULL); + mpegts_input_set_network(mi, mn); return 1; } @@ -130,7 +133,7 @@ linuxdvb_satconf_class_frontend_enum (void *o) const idclass_t linuxdvb_satconf_class = { - .ic_super = &linuxdvb_hardware_class, + .ic_super = &mpegts_input_class, .ic_class = "linuxdvb_satconf", .ic_caption = "Linux DVB Satconf", //.ic_get_title = linuxdvb_satconf_class_get_title, @@ -164,7 +167,7 @@ static void linuxdvb_satconf_display_name ( mpegts_input_t* mi, char *buf, size_t len ) { linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)mi; - ls->mi_display_name(ls->ls_frontend, buf, len); + ls->ls_frontend->mi_display_name(ls->ls_frontend, buf, len); } static const idclass_t * @@ -192,7 +195,8 @@ static int linuxdvb_satconf_is_free ( mpegts_input_t *mi ) { linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)mi; - return ls->ls_frontend->mi_is_free(ls->ls_frontend); + int r = ls->ls_frontend->mi_is_free(ls->ls_frontend); + return r; } static int @@ -218,7 +222,7 @@ linuxdvb_satconf_start_mux uint32_t f; linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)mi; linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)(mi = ls->ls_frontend); - linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mmi; + linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mmi->mmi_mux; /* Test run */ // Note: basically this ensures the tuning params are acceptable @@ -227,9 +231,9 @@ linuxdvb_satconf_start_mux if (!ls->ls_lnb) return SM_CODE_TUNING_FAILED; f = ls->ls_lnb->lnb_frequency(ls->ls_lnb, lm); - if (f < 0) + if (f == (uint32_t)-1) return SM_CODE_TUNING_FAILED; - r = linuxdvb_frontend_tune(lfe, lm, f); + r = linuxdvb_frontend_tune0(lfe, mmi, f); if (r) return r; /* Switch */ @@ -241,7 +245,7 @@ linuxdvb_satconf_start_mux return SM_CODE_TUNING_FAILED; /* Tune */ - return mi->mi_start_mux(mi, mmi); + return linuxdvb_frontend_tune1(lfe, mmi, f); } static void @@ -261,16 +265,52 @@ linuxdvb_satconf_close_service } static void -linuxdvb_satconf_create_mux_instance - ( mpegts_input_t *mi, mpegts_mux_t *mm ) +linuxdvb_satconf_started_mux + ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi ) { linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)mi; - ls->ls_frontend->mi_create_mux_instance(ls->ls_frontend, mm); + ls->ls_frontend->mi_started_mux(ls->ls_frontend, mmi); +} + +static void +linuxdvb_satconf_stopped_mux + ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi ) +{ + linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)mi; + ls->ls_frontend->mi_stopped_mux(ls->ls_frontend, mmi); +} + +static int +linuxdvb_satconf_open_pid + ( linuxdvb_frontend_t *lfe, int pid, const char *name ) +{ + linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)lfe; + lfe = (linuxdvb_frontend_t*)ls->ls_frontend; + return lfe->lfe_open_pid(lfe, pid, name); } /* ************************************************************************** * Creation/Config * *************************************************************************/ + +static uint32_t uni_freq + ( linuxdvb_lnb_t *lnb, linuxdvb_mux_t *lm ) +{ + dvb_mux_conf_t *dmc = &lm->lm_tuning; + struct dvb_frontend_parameters *p = &dmc->dmc_fe_params; + if (p->frequency > 11700000) + return abs(p->frequency - 10600000); + else + return abs(p->frequency - 9750000); +} + +static int uni_tune + ( linuxdvb_lnb_t *lnb, linuxdvb_mux_t *lm, int fd ) +{ + dvb_mux_conf_t *dmc = &lm->lm_tuning; + struct dvb_frontend_parameters *p = &dmc->dmc_fe_params; + return diseqc_setup(fd, 0, 0, p->frequency > 11700000, 0, 0); +} linuxdvb_satconf_t * linuxdvb_satconf_create0 @@ -289,7 +329,14 @@ linuxdvb_satconf_create0 ls->mi_close_service = linuxdvb_satconf_close_service; ls->mi_network_class = linuxdvb_satconf_network_class; ls->mi_network_create = linuxdvb_satconf_network_create; - ls->mi_create_mux_instance = linuxdvb_satconf_create_mux_instance; + ls->mi_started_mux = linuxdvb_satconf_started_mux; + ls->mi_stopped_mux = linuxdvb_satconf_stopped_mux; + ls->lfe_open_pid = linuxdvb_satconf_open_pid; + + /* Unoversal LMB */ + ls->ls_lnb = calloc(1, sizeof(linuxdvb_lnb_t)); + ls->ls_lnb->lnb_frequency = uni_freq; + ls->ls_lnb->lnb_tune = uni_tune; return ls; }