From: Jaroslav Kysela Date: Tue, 20 Sep 2016 15:07:25 +0000 (+0200) Subject: linuxdvb: unicable - add support for Unicable II (untested) X-Git-Tag: v4.2.1~308 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=766f2fdac4f872ec0a4f7520f3fd6b4c5c604798;p=thirdparty%2Ftvheadend.git linuxdvb: unicable - add support for Unicable II (untested) --- diff --git a/src/input/mpegts/linuxdvb/linuxdvb_en50494.c b/src/input/mpegts/linuxdvb/linuxdvb_en50494.c index 8f36c2cd2..688d5736b 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_en50494.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_en50494.c @@ -53,6 +53,9 @@ #define LINUXDVB_EN50494_SAT_A 0x00 #define LINUXDVB_EN50494_SAT_B 0x01 +/* EN50607 */ +#define LINUXDVB_EN50607_FRAME_NORMAL 0x70 +#define LINUXDVB_EN50607_FRAME_MULTIHOME 0x71 /* ************************************************************************** * Class definition @@ -64,7 +67,14 @@ static pthread_mutex_t linuxdvb_en50494_lock; static const char * linuxdvb_en50494_class_get_title ( idnode_t *o, const char *lang ) { - static const char *title = N_("Unicable"); + static const char *title = N_("Unicable I (EN50494)"); + return tvh_gettext_lang(lang, title); +} + +static const char * +linuxdvb_en50607_class_get_title ( idnode_t *o, const char *lang ) +{ + static const char *title = N_("Unicable II (EN50607)"); return tvh_gettext_lang(lang, title); } @@ -91,6 +101,17 @@ linuxdvb_en50494_id_list ( void *o, const char *lang ) } htsmsg_t * +linuxdvb_en50607_id_list ( void *o, const char *lang ) +{ + uint32_t i; + htsmsg_t *m = htsmsg_create_list(); + for (i = 0; i < 32; i++) { + htsmsg_add_u32(m, NULL, i); + } + return m; +} + +static htsmsg_t * linuxdvb_en50494_pin_list ( void *o, const char *lang ) { int32_t i; @@ -113,6 +134,7 @@ linuxdvb_en50494_pin_list ( void *o, const char *lang ) } extern const idclass_t linuxdvb_diseqc_class; + const idclass_t linuxdvb_en50494_class = { .ic_super = &linuxdvb_diseqc_class, @@ -151,6 +173,44 @@ const idclass_t linuxdvb_en50494_class = } }; +const idclass_t linuxdvb_en50607_class = +{ + .ic_super = &linuxdvb_diseqc_class, + .ic_class = "linuxdvb_en50607", + .ic_caption = N_("en50607"), + .ic_get_title = linuxdvb_en50607_class_get_title, + .ic_properties = (const property_t[]) { + { + .type = PT_U16, + .id = "position", + .name = N_("Position"), + .off = offsetof(linuxdvb_en50494_t, le_position), + .list = linuxdvb_en50494_position_list, + }, + { + .type = PT_U16, + .id = "frequency", + .name = N_("Frequency"), + .off = offsetof(linuxdvb_en50494_t, le_frequency), + }, + { + .type = PT_U16, + .id = "id", + .name = N_("SCR (ID)"), + .off = offsetof(linuxdvb_en50494_t, le_id), + .list = linuxdvb_en50607_id_list, + }, + { + .type = PT_U16, + .id = "pin", + .name = N_("PIN"), + .off = offsetof(linuxdvb_en50494_t, le_pin), + .list = linuxdvb_en50494_pin_list, + }, + {} + } +}; + /* ************************************************************************** * Class methods * *************************************************************************/ @@ -198,7 +258,9 @@ linuxdvb_en50494_tune int vol, int pol, int band, int freq ) { int ret = 0, i, fd = linuxdvb_satconf_fe_fd(lsp), rfreq; + int ver2 = linuxdvb_unicable_is_en50607(ld->ld_type); linuxdvb_en50494_t *le = (linuxdvb_en50494_t*) ld; + uint8_t data1, data2, data3; uint16_t t; /* tune frequency for the frontend */ @@ -206,14 +268,24 @@ linuxdvb_en50494_tune return -1; le->le_tune_freq = rfreq; - /* 2 data fields (16bit) */ - uint8_t data1, data2; - data1 = (le->le_id & 7) << 5; /* 3bit user-band */ - data1 |= (le->le_position & 1) << 4; /* 1bit position (satellite A(0)/B(1)) */ - data1 |= (pol & 1) << 3; /* 1bit polarization v(0)/h(1) */ - data1 |= (band & 1) << 2; /* 1bit band lower(0)/upper(1) */ - data1 |= (t >> 8) & 3; /* 2bit transponder value bit 1-2 */ - data2 = t & 0xFF; /* 8bit transponder value bit 3-10 */ + if (!ver2) { + /* 2 data fields (16bit) */ + data1 = (le->le_id & 7) << 5; /* 3bit user-band */ + data1 |= (le->le_position & 1) << 4; /* 1bit position (satellite A(0)/B(1)) */ + data1 |= (pol & 1) << 3; /* 1bit polarization v(0)/h(1) */ + data1 |= (band & 1) << 2; /* 1bit band lower(0)/upper(1) */ + data1 |= (t >> 8) & 3; /* 2bit transponder value bit 1-2 */ + data2 = t & 0xff; /* 8bit transponder value bit 3-10 */ + data3 = 0; + } else { + /* 3 data fields (24bit) */ + data1 = (le->le_id & 0x1f) << 3; /* 5bit user-band */ + data1 |= (t >> 8) & 7; /* 3bit transponder value bit 1-3 */ + data2 = t & 0xff; /* 8bit transponder value bit 4-11 */ + data3 = (le->le_position & 0x3f) << 2; /* 6bit position */ + data3 |= (pol & 1) << 1; /* 1bit polarization v(0)/h(1) */ + data3 |= band & 1; /* 1bit band lower(0)/upper(1) */ + } /* wait until no other thread is setting up switch. * when an other thread was blocking, waiting 20ms. @@ -247,23 +319,33 @@ linuxdvb_en50494_tune /* send tune command (with/without pin) */ tvhdebug(LS_EN50494, - "lnb=%i id=%i freq=%i pin=%i v/h=%i l/u=%i f=%i, data=0x%02X%02X", + "lnb=%i id=%i freq=%i pin=%i v/h=%i l/u=%i f=%i, data=0x%02X%02X%02X", le->le_position, le->le_id, le->le_frequency, le->le_pin, pol, - band, freq, data1, data2); - if (le->le_pin != LINUXDVB_EN50494_NOPIN) { + band, freq, data1, data2, data3); + if (!ver2 && le->le_pin != LINUXDVB_EN50494_NOPIN) { ret = linuxdvb_diseqc_send(fd, LINUXDVB_EN50494_FRAME, LINUXDVB_EN50494_ADDRESS, LINUXDVB_EN50494_CMD_NORMAL_MULTIHOME, 3, data1, data2, (uint8_t)le->le_pin); - } else { + } else if (!ver2) { ret = linuxdvb_diseqc_send(fd, LINUXDVB_EN50494_FRAME, LINUXDVB_EN50494_ADDRESS, LINUXDVB_EN50494_CMD_NORMAL, 2, data1, data2); + } else if (ver2 && le->le_pin != LINUXDVB_EN50494_NOPIN) { + ret = linuxdvb_diseqc_raw_send(fd, + LINUXDVB_EN50607_FRAME_MULTIHOME, + 4, + data1, data2, data3, (uint8_t)le->le_pin); + } else if (ver2) { + ret = linuxdvb_diseqc_raw_send(fd, + LINUXDVB_EN50607_FRAME_NORMAL, + 3, + data1, data2, data3); } if (ret != 0) { tvherror(LS_EN50494, "error send tune command"); @@ -301,7 +383,8 @@ linuxdvb_en50494_list ( void *o, const char *lang ) { htsmsg_t *m = htsmsg_create_list(); htsmsg_add_str(m, NULL, tvh_gettext_lang(lang, N_("None"))); - htsmsg_add_str(m, NULL, tvh_gettext_lang(lang, N_("Generic"))); + htsmsg_add_str(m, NULL, tvh_gettext_lang(lang, N_(UNICABLE_I_NAME))); + htsmsg_add_str(m, NULL, tvh_gettext_lang(lang, N_(UNICABLE_II_NAME))); return m; } @@ -312,14 +395,21 @@ linuxdvb_en50494_create0 linuxdvb_diseqc_t *ld; linuxdvb_en50494_t *le; - if (strcmp(name ?: "", "Generic")) + if (strcmp(name ?: "", "Generic") && + strcmp(name ?: "", UNICABLE_I_NAME) && + strcmp(name ?: "", UNICABLE_II_NAME)) return NULL; - if (port > 1) { + if (linuxdvb_unicable_is_en50494(name) && port > 1) { tvherror(LS_EN50494, "only 2 ports/positions are possible. given %i", port); port = 0; } + if (linuxdvb_unicable_is_en50607(name) && port > 63) { + tvherror(LS_EN50494, "only 64 ports/positions are possible. given %i", port); + port = 0; + } + le = calloc(1, sizeof(linuxdvb_en50494_t)); if (le == NULL) return NULL; @@ -331,10 +421,13 @@ linuxdvb_en50494_create0 le->ld_match = linuxdvb_en50494_match; ld = linuxdvb_diseqc_create0((linuxdvb_diseqc_t *)le, - NULL, &linuxdvb_en50494_class, conf, - "Generic", ls); + NULL, + linuxdvb_unicable_is_en50607(name) ? + &linuxdvb_en50607_class : + &linuxdvb_en50494_class, + conf, name, ls); if (ld) { - ld->ld_tune = linuxdvb_en50494_tune; + ld->ld_tune = linuxdvb_en50494_tune; /* May not needed: ld->ld_grace = linuxdvb_en50494_grace; */ } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index 76e4577d5..133be6c31 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -329,6 +329,9 @@ struct linuxdvb_lnb int (*lnb_pol) (linuxdvb_lnb_t*, dvb_mux_t*); }; +#define UNICABLE_EN50494 50494 +#define UNICABLE_EN50607 50607 + struct linuxdvb_en50494 { linuxdvb_diseqc_t; @@ -448,6 +451,10 @@ linuxdvb_diseqc_t *linuxdvb_switch_create0 ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls, int c, int u ); linuxdvb_diseqc_t *linuxdvb_rotor_create0 ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls ); + +#define UNICABLE_I_NAME "Unicable I (EN50494)" +#define UNICABLE_II_NAME "Unicable II (EN50607)" + linuxdvb_diseqc_t *linuxdvb_en50494_create0 ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls, int port ); @@ -461,11 +468,18 @@ htsmsg_t *linuxdvb_switch_list ( void *o, const char *lang ); htsmsg_t *linuxdvb_rotor_list ( void *o, const char *lang ); htsmsg_t *linuxdvb_en50494_list ( void *o, const char *lang ); -htsmsg_t *linuxdvb_en50494_id_list ( void *o, const char *lang ); +htsmsg_t *linuxdvb_en50494_id_list ( void *o, const char *lang ); +htsmsg_t *linuxdvb_en50607_id_list ( void *o, const char *lang ); htsmsg_t *linuxdvb_en50494_pin_list ( void *o, const char *lang ); +static inline int linuxdvb_unicable_is_en50607( const char *str ) + { return strcmp(str, UNICABLE_II_NAME) == 0; } +static inline int linuxdvb_unicable_is_en50494( const char *str ) + { return !linuxdvb_unicable_is_en50607(str); } + void linuxdvb_en50494_init (void); +int linuxdvb_diseqc_raw_send (int fd, uint8_t len, ...); int linuxdvb_diseqc_send (int fd, uint8_t framing, uint8_t addr, uint8_t cmd, uint8_t len, ...); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index 89df12fd8..bcfd4eadf 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -464,7 +464,7 @@ const idclass_t linuxdvb_satconf_en50494_class = .ic_super = &linuxdvb_satconf_class, .ic_class = "linuxdvb_satconf_en50494", .ic_doc = tvh_doc_linuxdvb_satconf_class, - .ic_caption = N_("TV Adapters - SatConfig - EN50494/UniCable (experimental)"), + .ic_caption = N_("TV Adapters - SatConfig - EN50494/UniCable I"), .ic_properties = (const property_t[]) { { .type = PT_U16, @@ -523,6 +523,94 @@ const idclass_t linuxdvb_satconf_en50494_class = } }; +const idclass_t linuxdvb_satconf_en50607_class = +{ + .ic_super = &linuxdvb_satconf_class, + .ic_class = "linuxdvb_satconf_en50607", + .ic_doc = tvh_doc_linuxdvb_satconf_class, + .ic_caption = N_("TV Adapters - SatConfig - EN50607/UniCable II"), + .ic_properties = (const property_t[]) { + { + .type = PT_U16, + .id = "id", + .name = N_("SCR (ID)"), + .desc = N_("SCR (Satellite Channel Router) ID."), + .get = linuxdvb_satconf_class_en50494_id_get, + .set = linuxdvb_satconf_class_en50494_id_set, + .list = linuxdvb_en50607_id_list, + .opts = PO_NOSAVE, + }, + { + .type = PT_U16, + .id = "pin", + .name = N_("PIN"), + .desc = N_("PIN."), + .get = linuxdvb_satconf_class_en50494_pin_get, + .set = linuxdvb_satconf_class_en50494_pin_set, + .list = linuxdvb_en50494_pin_list, + .opts = PO_NOSAVE, + }, + { + .type = PT_U16, + .id = "frequency", + .name = N_("Frequency (MHz)"), + .desc = N_("Frequency (in MHz)."), + .get = linuxdvb_satconf_class_en50494_freq_get, + .set = linuxdvb_satconf_class_en50494_freq_set, + .opts = PO_NOSAVE, + }, + { + .type = PT_STR, + .id = "network_a", + .name = N_("Network A"), + .desc = N_("Network for port A."), + .islist = 1, + .get = linuxdvb_satconf_class_network_get0, + .set = linuxdvb_satconf_class_network_set0, + .list = linuxdvb_satconf_class_network_enum, + .rend = linuxdvb_satconf_class_network_rend0, + .opts = PO_NOSAVE, + }, + { + .type = PT_STR, + .id = "network_b", + .name = N_("Network B"), + .desc = N_("Network for port B."), + .islist = 1, + .get = linuxdvb_satconf_class_network_get1, + .set = linuxdvb_satconf_class_network_set1, + .list = linuxdvb_satconf_class_network_enum, + .rend = linuxdvb_satconf_class_network_rend1, + .opts = PO_NOSAVE, + }, + { + .type = PT_STR, + .id = "network_c", + .name = N_("Network C"), + .desc = N_("Network for port C."), + .islist = 1, + .get = linuxdvb_satconf_class_network_get2, + .set = linuxdvb_satconf_class_network_set2, + .list = linuxdvb_satconf_class_network_enum, + .rend = linuxdvb_satconf_class_network_rend2, + .opts = PO_NOSAVE, + }, + { + .type = PT_STR, + .id = "network_d", + .name = N_("Network D"), + .desc = N_("Network for port D."), + .islist = 1, + .get = linuxdvb_satconf_class_network_get3, + .set = linuxdvb_satconf_class_network_set3, + .list = linuxdvb_satconf_class_network_enum, + .rend = linuxdvb_satconf_class_network_rend3, + .opts = PO_NOSAVE, + }, + {} + } +}; + /* * Advanced */ @@ -653,10 +741,16 @@ static struct linuxdvb_satconf_type linuxdvb_satconf_types[] = { }, { .type = "en50494", - .name = N_("Unicable switch (universal LNB, experimental)"), + .name = N_("Unicable I switch (universal LNB)"), .idc = &linuxdvb_satconf_en50494_class, .ports = 2, }, + { + .type = "en50607", + .name = N_("Unicable II switch (universal LNB)"), + .idc = &linuxdvb_satconf_en50607_class, + .ports = 4, + }, { .type = "advanced", .name = N_("Advanced (non-universal LNBs, rotors, etc.)"), @@ -1078,7 +1172,10 @@ linuxdvb_satconf_create if (lst->ports > 1) { if (!strcmp(lst->type, "en50494")) { if (!lse->lse_en50494) - lse->lse_en50494 = linuxdvb_en50494_create0("Generic", NULL, lse, i); + lse->lse_en50494 = linuxdvb_en50494_create0(UNICABLE_I_NAME, NULL, lse, i); + } else if (!strcmp(lst->type, "en50607")) { + if (!lse->lse_en50494) + lse->lse_en50494 = linuxdvb_en50494_create0(UNICABLE_II_NAME, NULL, lse, i); } else { if (!lse->lse_switch) lse->lse_switch = linuxdvb_switch_create0("Generic", NULL, lse, i, -1); @@ -1537,6 +1634,37 @@ linuxdvb_diseqc_destroy ( linuxdvb_diseqc_t *ld ) free((void *)ld->ld_type); } +int +linuxdvb_diseqc_raw_send + (int fd, uint8_t len, ...) +{ + int i; + va_list ap; + struct dvb_diseqc_master_cmd message; + char buf[256]; + size_t c = 0; + + /* Build message */ + message.msg_len = len; + va_start(ap, len); + for (i = 0; i < len; i++) { + message.msg[i] = (uint8_t)va_arg(ap, int); + if (tvhtrace_enabled()) + tvh_strlcatf(buf, sizeof(buf), c, "%02X ", message.msg[3 + i]); + } + va_end(ap); + + if (tvhtrace_enabled()) + tvhtrace(LS_DISEQC, "sending raw diseqc (len %d) %s", len, buf); + + /* Send */ + if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &message)) { + tvherror(LS_DISEQC, "failed to send diseqc cmd (e=%s)", strerror(errno)); + return -1; + } + return 0; +} + int linuxdvb_diseqc_send (int fd, uint8_t framing, uint8_t addr, uint8_t cmd, uint8_t len, ...) @@ -1546,7 +1674,6 @@ linuxdvb_diseqc_send struct dvb_diseqc_master_cmd message; char buf[256]; size_t c = 0; - int tr = tvhtrace_enabled(); /* Build message */ message.msg_len = len + 3; @@ -1556,12 +1683,12 @@ linuxdvb_diseqc_send va_start(ap, len); for (i = 0; i < len; i++) { message.msg[3 + i] = (uint8_t)va_arg(ap, int); - if (tr) + if (tvhtrace_enabled()) tvh_strlcatf(buf, sizeof(buf), c, "%02X ", message.msg[3 + i]); } va_end(ap); - if (tr) + if (tvhtrace_enabled()) tvhtrace(LS_DISEQC, "sending diseqc (len %d) %02X %02X %02X %s", len + 3, framing, addr, cmd, buf);