]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
linuxdvb: unicable - add support for Unicable II (untested)
authorJaroslav Kysela <perex@perex.cz>
Tue, 20 Sep 2016 15:07:25 +0000 (17:07 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 20 Sep 2016 15:07:25 +0000 (17:07 +0200)
src/input/mpegts/linuxdvb/linuxdvb_en50494.c
src/input/mpegts/linuxdvb/linuxdvb_private.h
src/input/mpegts/linuxdvb/linuxdvb_satconf.c

index 8f36c2cd20ee675baef96df61090a42a70cfe51f..688d5736bfb2ab60c035e85eb6778b3f44e0066c 100644 (file)
@@ -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; */
   }
 
index 76e4577d5f8c3249880343eb2ec1c262acb42d7d..133be6c31099872ecb13ec889dc25e99fee4cf84 100644 (file)
@@ -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, ...);
index 89df12fd8927b7ef871c0fca73b571b99aa9fc52..bcfd4eadfc787ec96dbf00d1fa3ffb3c66004b35 100644 (file)
@@ -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);