]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
EN50494: first commit
authorInuSasha <inu@inusasha.de>
Sun, 5 Jan 2014 16:54:49 +0000 (17:54 +0100)
committerInuSasha <inu@inusasha.de>
Sun, 5 Jan 2014 16:54:49 +0000 (17:54 +0100)
- works with same hardcoded values (needs to setup)
- setup via gui is missing

.gitignore
Makefile
src/input/mpegts/linuxdvb/linuxdvb_en50494.c [new file with mode: 0644]
src/input/mpegts/linuxdvb/linuxdvb_private.h
src/input/mpegts/linuxdvb/linuxdvb_satconf.c

index 217c99613ef5a907c5602a22cc50d539259cfc12..949dbf6694537d29ba3e3cbd3858ad30c71cc406 100644 (file)
@@ -19,3 +19,4 @@ debian/tvheadend
 debian/tvheadend-dbg
 debian/tvheadend*substvars
 debian/tvheadend*.debhelper*
+/etc
index 5d7bfb19717e003478720b55f971a39c6ed038b6..a2e5c65cc48573320add0481118d40bac85c89ef 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ PROG    := $(BUILDDIR)/tvheadend
 
 CFLAGS  += -Wall -Werror -Wwrite-strings -Wno-deprecated-declarations
 CFLAGS  += -Wmissing-prototypes -fms-extensions
-CFLAGS  += -g -funsigned-char -O2 
+CFLAGS  += -g -funsigned-char
 CFLAGS  += -D_FILE_OFFSET_BITS=64
 CFLAGS  += -I${BUILDDIR} -I${ROOTDIR}/src -I${ROOTDIR}
 LDFLAGS += -lrt -ldl -lpthread -lm
@@ -195,6 +195,7 @@ SRCS-${CONFIG_LINUXDVB} += \
         src/input/mpegts/linuxdvb/linuxdvb_lnb.c \
         src/input/mpegts/linuxdvb/linuxdvb_switch.c \
         src/input/mpegts/linuxdvb/linuxdvb_rotor.c \
+        src/input/mpegts/linuxdvb/linuxdvb_en50494.c \
         src/input/mpegts/linuxdvb/scanfile.c \
 
 # IPTV
diff --git a/src/input/mpegts/linuxdvb/linuxdvb_en50494.c b/src/input/mpegts/linuxdvb/linuxdvb_en50494.c
new file mode 100644 (file)
index 0000000..fe07370
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ *  Tvheadend - Linux DVB EN50494
+ *              (known under trademark "UniCable")
+ *
+ *  Copyright (C) 2013 Sascha "InuSasha" Kuehndel
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Open things:
+ *    - make linuxdvb_en50494_tune thread safe
+ *      avoiding self-raised collisions
+ *    - collision dectection
+ *      when a diseqc-command wasn't executed succesful, retry.
+ *      delay time is easly random, but in standard is special (complicated) way described (cap 8).
+ */
+
+#include "tvheadend.h"
+#include "linuxdvb_private.h"
+#include "settings.h"
+
+#include <unistd.h>
+#include <math.h>
+
+/* **************************************************************************
+ * Static definition
+ * *************************************************************************/
+#define LINUXDVB_EN50494_NAME                  "en50494"
+
+#define LINUXDVB_EN50494_NOPIN                 256
+
+#define LINUXDVB_EN50494_FRAME                 0xE0
+/* adresses 0x00, 0x10 and 0x11 are possible */
+#define LINUXDVB_EN50494_ADDRESS               0x10
+
+#define LINUXDVB_EN50494_CMD_NORMAL            0x5A
+#define LINUXDVB_EN50494_CMD_NORMAL_MULTIHOME  0x5C
+/* special modes not implemented yet */
+#define LINUXDVB_EN50494_CMD_SPECIAL           0x5B
+#define LINUXDVB_EN50494_CMD_SPECIAL_MULTIHOME 0x5D
+
+#define LINUXDVB_EN50494_SAT_A                 0x00
+#define LINUXDVB_EN50494_SAT_B                 0x01
+
+
+/* **************************************************************************
+ * Class definition
+ * *************************************************************************/
+
+typedef struct linuxdvb_en50494
+{
+  linuxdvb_diseqc_t;
+
+  /* en50494 configuration*/
+  uint8_t   le_position;  /* satelitte A(0) or B(1) */
+  uint16_t  le_frequency; /* user band frequency in MHz */
+  uint8_t   le_id;        /* user band id 0-7 */
+  uint16_t  le_pin;       /* 0-255 or LINUXDVB_EN50494_NOPIN */
+
+  /* runtime */
+  uint32_t  (*lnb_freq)(linuxdvb_lnb_t*, linuxdvb_mux_t*);
+
+} linuxdvb_en50494_t;
+
+static const char *
+linuxdvb_en50494_class_get_title ( idnode_t *o )
+{
+  static char buf[256];
+  linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o;
+  snprintf(buf, sizeof(buf), "%s: %s", LINUXDVB_EN50494_NAME, ld->ld_type);
+  return buf;
+}
+
+static htsmsg_t *
+linuxdvb_en50494_class_position_list ( void *o )
+{
+  htsmsg_t *m = htsmsg_create_list();
+  htsmsg_add_u32(m, NULL, LINUXDVB_EN50494_SAT_A);
+  htsmsg_add_u32(m, NULL, LINUXDVB_EN50494_SAT_B);
+  return m;
+}
+
+static htsmsg_t *
+linuxdvb_en50494_class_id_list ( void *o )
+{
+  uint32_t i;
+
+  htsmsg_t *m = htsmsg_create_list();
+  for (i = 0; i < 8; i++) {
+    htsmsg_add_u32(m, NULL, i);
+  }
+  return m;
+}
+
+static htsmsg_t *
+linuxdvb_en50494_class_pin_list ( void *o )
+{
+  int32_t i;
+
+  htsmsg_t *m = htsmsg_create_list();
+  for (i = -1; i < 256; i++) {
+    htsmsg_add_s32(m, NULL, i);
+  }
+  return m;
+}
+
+extern const idclass_t linuxdvb_diseqc_class;
+const idclass_t linuxdvb_en50494_class =
+{
+  .ic_super       = &linuxdvb_diseqc_class,
+  .ic_class       = "linuxdvb_en50494",
+  .ic_caption     = LINUXDVB_EN50494_NAME,
+  .ic_get_title   = linuxdvb_en50494_class_get_title,
+  .ic_properties  = (const property_t[]) {
+    {
+      .type   = PT_INT,
+      .id     = "position",
+      .name   = "Position",
+      .off    = offsetof(linuxdvb_en50494_t, le_position),
+      .list   = linuxdvb_en50494_class_position_list
+    },
+    {
+      .type   = PT_INT,
+      .id     = "frequency",
+      .name   = "Frequency",
+      .off    = offsetof(linuxdvb_en50494_t, le_frequency),
+    },
+    {
+      .type   = PT_INT,
+      .id     = "id",
+      .name   = "ID",
+      .off    = offsetof(linuxdvb_en50494_t, le_id),
+      .list   = linuxdvb_en50494_class_id_list
+    },
+    {
+      .type   = PT_INT,
+      .id     = "pin",
+      .name   = "Pin",
+      .off    = offsetof(linuxdvb_en50494_t, le_pin),
+      .list   = linuxdvb_en50494_class_pin_list
+    },
+    {}
+  }
+};
+
+
+/* **************************************************************************
+ * Class methods
+ * *************************************************************************/
+
+static int
+linuxdvb_en50494_tune
+  ( linuxdvb_diseqc_t *ld, linuxdvb_mux_t *lm, linuxdvb_satconf_ele_t *sc, int fd )
+{
+  int ret = 0;
+  linuxdvb_en50494_t *le = (linuxdvb_en50494_t*) ld;
+  linuxdvb_lnb_t *lnb = sc->ls_lnb;
+
+  /* band & polarisation */
+  uint8_t pol  = lnb->lnb_pol(lnb, lm);
+  uint8_t band = lnb->lnb_band(lnb, lm);
+  uint32_t freq = lnb->lnb_freq(lnb, lm);
+
+  /* transponder value - t*/
+  uint16_t t = round((( (freq / 1000) + 2 + le->le_frequency) / 4) - 350);
+  if ( t > 1024) {
+    tvhlog(LOG_ERR, LINUXDVB_EN50494_NAME, "transponder value bigger then 1024");
+    return -1;
+  }
+//  uint32_t tunefreq = (t + 350) * 4000 - freq; /* real used en50494 frequency */
+
+  /* 2 data fields (16bit) */
+  uint8_t data1, data2;
+  data1  = le->le_id << 5;        /* 3bit user-band */
+  data1 |= le->le_position << 4;  /* 1bit position (satelitte A(0)/B(0)) */
+  data1 |= pol << 3;              /* 1bit polarisation v(0)/h(1) */
+  data1 |= band << 2;             /* 1bit band lower(0)/upper(1) */
+  data1 |= t >> 8;                /* 2bit transponder value bit 1-2 */
+  data2  = t & 0xFF;              /* 8bit transponder value bit 3-10 */
+  tvhlog(LOG_INFO, LINUXDVB_EN50494_NAME,
+         "lnb=%i, id=%i, freq=%i, pin=%i, v/h=%i, l/u=%i, f=%i, data=0x%02X%02X",
+         le->le_position, le->le_id, le->le_frequency, le->le_pin, pol, band, freq, data1, data2);
+
+  /* use 18V */
+  if (linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_18)) {
+    tvhlog(LOG_ERR, LINUXDVB_EN50494_NAME, "error setting lnb voltage to 18V");
+    return -1;
+  }
+  usleep(15000); /* standard: 4ms < x < 22ms */
+
+   /* send tune command (with/with pin) */
+  if (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 {
+    ret = linuxdvb_diseqc_send(fd,
+                               LINUXDVB_EN50494_FRAME,
+                               LINUXDVB_EN50494_ADDRESS,
+                               LINUXDVB_EN50494_CMD_NORMAL,
+                               2,
+                               data1, data2);
+  }
+  if (ret != 0) {
+    tvhlog(LOG_ERR, LINUXDVB_EN50494_NAME, "error send tune command");
+    return -1;
+  }
+  usleep(50000); /* standard: 2ms < x < 60ms */
+
+  /* return to 13V */
+  if (linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_13)) {
+    tvhlog(LOG_ERR, LINUXDVB_EN50494_NAME, "error setting lnb voltage back to 13V");
+    return -1;
+  }
+
+  return 0;
+}
+
+
+/* **************************************************************************
+ * Create / Config
+ * *************************************************************************/
+
+htsmsg_t *
+linuxdvb_en50494_list ( void *o )
+{
+  htsmsg_t *m = htsmsg_create_list();
+  htsmsg_add_str(m, NULL, "None");
+  htsmsg_add_str(m, NULL, "EN50494/UniCable");
+  return m;
+}
+
+linuxdvb_diseqc_t *
+linuxdvb_en50494_create0
+  ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls)
+{
+  linuxdvb_diseqc_t *ld;
+//  linuxdvb_en50494_t *le;
+
+  ld = linuxdvb_diseqc_create0(
+      calloc(1, sizeof(linuxdvb_en50494_t)),
+      NULL,
+      &linuxdvb_en50494_class,
+      conf,
+      LINUXDVB_EN50494_NAME,
+      ls);
+//  le = (linuxdvb_en50494_t*)ld;
+  if (ld) {
+    ld->ld_tune  = linuxdvb_en50494_tune;
+    /* May not needed: ld->ld_grace = linuxdvb_en50494_grace; */
+  }
+
+  return (linuxdvb_diseqc_t*)ld;
+}
+
+void
+linuxdvb_en50494_destroy ( linuxdvb_diseqc_t *le )
+{
+  linuxdvb_diseqc_destroy(le);
+  free(le);
+}
index 06a44fff15d1eab759fd753780e4df113d53c604..35683d78a7fb10a3a0970f03bddb0543b305b390 100644 (file)
@@ -199,6 +199,7 @@ struct linuxdvb_satconf_ele
   linuxdvb_lnb_t        *ls_lnb;
   linuxdvb_diseqc_t     *ls_switch;
   linuxdvb_diseqc_t     *ls_rotor;
+  linuxdvb_diseqc_t     *ls_en50494;
 };
 
 struct linuxdvb_diseqc
@@ -329,14 +330,18 @@ linuxdvb_diseqc_t *linuxdvb_switch_create0
   ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls, int u, int c );
 linuxdvb_diseqc_t *linuxdvb_rotor_create0
   ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls );
+linuxdvb_diseqc_t *linuxdvb_en50494_create0
+  ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls );
 
-void linuxdvb_lnb_destroy    ( linuxdvb_lnb_t    *lnb );
-void linuxdvb_switch_destroy ( linuxdvb_diseqc_t *ld );
-void linuxdvb_rotor_destroy  ( linuxdvb_diseqc_t *ld );
+void linuxdvb_lnb_destroy     ( linuxdvb_lnb_t    *lnb );
+void linuxdvb_switch_destroy  ( linuxdvb_diseqc_t *ld );
+void linuxdvb_rotor_destroy   ( linuxdvb_diseqc_t *ld );
+void linuxdvb_en50494_destroy ( linuxdvb_diseqc_t *ld );
 
-htsmsg_t *linuxdvb_lnb_list    ( void *o );
-htsmsg_t *linuxdvb_switch_list ( void *o );
-htsmsg_t *linuxdvb_rotor_list  ( void *o );
+htsmsg_t *linuxdvb_lnb_list     ( void *o );
+htsmsg_t *linuxdvb_switch_list  ( void *o );
+htsmsg_t *linuxdvb_rotor_list   ( void *o );
+htsmsg_t *linuxdvb_en50494_list ( void *o );
 
 int
 linuxdvb_diseqc_send
index 99fbaeedba80845c0774c8ad301d0d18b318c19d..de1b1bbd02f9c08759df5959bb2c8ac677bf18ef 100644 (file)
@@ -209,7 +209,7 @@ const idclass_t linuxdvb_satconf_lnbonly_class =
       .type     = PT_STR,
       .id       = "network",
       .name     = "Network",
-      .get       = linuxdvb_satconf_class_network_get0,
+      .get      = linuxdvb_satconf_class_network_get0,
       .set      = linuxdvb_satconf_class_network_set0,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -231,7 +231,7 @@ const idclass_t linuxdvb_satconf_2port_class =
       .type     = PT_STR,
       .id       = "network_a",
       .name     = "A",
-      .get       = linuxdvb_satconf_class_network_get0,
+      .get      = linuxdvb_satconf_class_network_get0,
       .set      = linuxdvb_satconf_class_network_set0,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -240,7 +240,7 @@ const idclass_t linuxdvb_satconf_2port_class =
       .type     = PT_STR,
       .id       = "network_b",
       .name     = "B",
-      .get       = linuxdvb_satconf_class_network_get1,
+      .get      = linuxdvb_satconf_class_network_get1,
       .set      = linuxdvb_satconf_class_network_set1,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -262,7 +262,7 @@ const idclass_t linuxdvb_satconf_4port_class =
       .type     = PT_STR,
       .id       = "network_aa",
       .name     = "AA",
-      .get       = linuxdvb_satconf_class_network_get0,
+      .get      = linuxdvb_satconf_class_network_get0,
       .set      = linuxdvb_satconf_class_network_set0,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -271,7 +271,7 @@ const idclass_t linuxdvb_satconf_4port_class =
       .type     = PT_STR,
       .id       = "network_ab",
       .name     = "AB",
-      .get       = linuxdvb_satconf_class_network_get1,
+      .get      = linuxdvb_satconf_class_network_get1,
       .set      = linuxdvb_satconf_class_network_set1,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -280,7 +280,7 @@ const idclass_t linuxdvb_satconf_4port_class =
       .type     = PT_STR,
       .id       = "network_ba",
       .name     = "BA",
-      .get       = linuxdvb_satconf_class_network_get2,
+      .get      = linuxdvb_satconf_class_network_get2,
       .set      = linuxdvb_satconf_class_network_set2,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -289,7 +289,7 @@ const idclass_t linuxdvb_satconf_4port_class =
       .type     = PT_STR,
       .id       = "network_bb",
       .name     = "BB",
-      .get       = linuxdvb_satconf_class_network_get3,
+      .get      = linuxdvb_satconf_class_network_get3,
       .set      = linuxdvb_satconf_class_network_set3,
       .list     = linuxdvb_satconf_ele_class_network_enum,
       .opts     = PO_NOSAVE,
@@ -298,6 +298,37 @@ const idclass_t linuxdvb_satconf_4port_class =
   }
 };
 
+/*
+ * en50494
+ */
+const idclass_t linuxdvb_satconf_en50494_class =
+{
+  .ic_super      = &linuxdvb_satconf_class,
+  .ic_class      = "linuxdvb_satconf_en50494",
+  .ic_caption    = "DVB-S EN50494 (UniCable)",
+  .ic_properties = (const property_t[]) {
+    {
+      .type     = PT_STR,
+      .id       = "network_a",
+      .name     = "Network A",
+      .get      = linuxdvb_satconf_class_network_get0,
+      .set      = linuxdvb_satconf_class_network_set0,
+      .list     = linuxdvb_satconf_ele_class_network_enum,
+      .opts     = PO_NOSAVE,
+    },
+    {
+      .type     = PT_STR,
+      .id       = "network_b",
+      .name     = "Netwotk B",
+      .get      = linuxdvb_satconf_class_network_get1,
+      .set      = linuxdvb_satconf_class_network_set1,
+      .list     = linuxdvb_satconf_ele_class_network_enum,
+      .opts     = PO_NOSAVE,
+    },
+    {}
+  }
+};
+
 /*
  * Advanced
  */
@@ -344,6 +375,12 @@ static struct linuxdvb_satconf_type linuxdvb_satconf_types[] = {
     .idc   = &linuxdvb_satconf_4port_class,
     .ports = 4, 
   },
+  {
+    .type  = "en50494",
+    .name  = "EN50494/UniCable Switch (Universal LNB)",
+    .idc   = &linuxdvb_satconf_en50494_class,
+    .ports = 2,
+  },
   {
     .type  = "advanced",
     .name  = "Advanced",
@@ -566,6 +603,26 @@ linuxdvb_satconf_ele_class_lnbtype_get ( void *o )
   return &s;
 }
 
+static int
+linuxdvb_satconf_ele_class_en50494type_set ( void *o, const void *p )
+{
+  linuxdvb_satconf_ele_t *ls  = o;
+  const char             *str = p;
+  if (ls->ls_en50494)
+    linuxdvb_en50494_destroy(ls->ls_en50494);
+  ls->ls_en50494 = linuxdvb_en50494_create0(str, NULL, ls);
+  return 1;
+}
+
+static const void *
+linuxdvb_satconf_ele_class_en50494type_get ( void *o )
+{
+  static const char *s;
+  linuxdvb_satconf_ele_t *ls = o;
+  s = ls->ls_en50494 ? ls->ls_en50494->ld_type : NULL;
+  return &s;
+}
+
 static int
 linuxdvb_satconf_ele_class_switchtype_set ( void *o, const void *p )
 {
@@ -631,6 +688,8 @@ linuxdvb_satconf_ele_class_get_childs ( idnode_t *o )
     idnode_set_add(is, &ls->ls_switch->ld_id, NULL);
   if (ls->ls_rotor)
     idnode_set_add(is, &ls->ls_rotor->ld_id, NULL);
+  if (ls->ls_en50494)
+    idnode_set_add(is, &ls->ls_en50494->ld_id, NULL);
   return is;
 }
 
@@ -661,8 +720,8 @@ const idclass_t linuxdvb_satconf_ele_class =
       .type     = PT_STR,
       .id       = "network",
       .name     = "Network",
-      .get       = linuxdvb_satconf_ele_class_network_get,
-      .set       = linuxdvb_satconf_ele_class_network_set,
+      .get      = linuxdvb_satconf_ele_class_network_get,
+      .set      = linuxdvb_satconf_ele_class_network_set,
       .list        = linuxdvb_satconf_ele_class_network_enum,
       .rend     = linuxdvb_satconf_ele_class_network_rend,
     },
@@ -693,6 +752,15 @@ const idclass_t linuxdvb_satconf_ele_class =
       .list     = linuxdvb_rotor_list,
       .def.s    = "None",
     },
+    {
+      .type     = PT_STR,
+      .id       = "en50494_type",
+      .name     = "EN50494 Type",
+      .set      = linuxdvb_satconf_ele_class_en50494type_set,
+      .get      = linuxdvb_satconf_ele_class_en50494type_get,
+      .list     = linuxdvb_en50494_list,
+      .def.s    = "None",
+    },
     {}
   }
 };
@@ -760,6 +828,7 @@ linuxdvb_satconf_ele_tune ( linuxdvb_satconf_ele_t *lse )
     lse->ls_rotor ? (linuxdvb_diseqc_t*)lse->ls_switch : NULL,
     (linuxdvb_diseqc_t*)lse->ls_rotor,
     (linuxdvb_diseqc_t*)lse->ls_switch,
+    (linuxdvb_diseqc_t*)lse->ls_en50494,
     (linuxdvb_diseqc_t*)lse->ls_lnb
   };
   // TODO: really need to understand whether or not we need to pre configure
@@ -798,7 +867,8 @@ linuxdvb_satconf_ele_tune ( linuxdvb_satconf_ele_t *lse )
   usleep(20000); // Allow LNB to settle before tuning
 
   /* Frontend */
-  f = lse->ls_lnb->lnb_freq(lse->ls_lnb, lm);
+  // TODO: get en50494 tuning frequency, not channel frequency
+  f = 2040500;// lse->ls_lnb->lnb_freq(lse->ls_lnb, lm);
   return linuxdvb_frontend_tune1(lfe, mmi, f);
 }
 
@@ -891,6 +961,7 @@ linuxdvb_satconf_ele_get_grace
   linuxdvb_satconf_ele_t *lse = (linuxdvb_satconf_ele_t*)mi;
   linuxdvb_satconf_t     *ls  = lse->ls_parent;
   linuxdvb_diseqc_t      *lds[] = {
+    (linuxdvb_diseqc_t*)lse->ls_en50494,
     (linuxdvb_diseqc_t*)lse->ls_switch,
     (linuxdvb_diseqc_t*)lse->ls_rotor,
     (linuxdvb_diseqc_t*)lse->ls_lnb
@@ -928,9 +999,10 @@ void
 linuxdvb_satconf_ele_destroy ( linuxdvb_satconf_ele_t *ls )
 {
   TAILQ_REMOVE(&ls->ls_parent->ls_elements, ls, ls_link);
-  if (ls->ls_lnb)    linuxdvb_lnb_destroy(ls->ls_lnb);
-  if (ls->ls_switch) linuxdvb_switch_destroy(ls->ls_switch);
-  if (ls->ls_rotor)  linuxdvb_rotor_destroy(ls->ls_rotor);
+  if (ls->ls_lnb)     linuxdvb_lnb_destroy(ls->ls_lnb);
+  if (ls->ls_switch)  linuxdvb_switch_destroy(ls->ls_switch);
+  if (ls->ls_rotor)   linuxdvb_rotor_destroy(ls->ls_rotor);
+  if (ls->ls_en50494) linuxdvb_switch_destroy(ls->ls_en50494);
   mpegts_input_delete((mpegts_input_t*)ls);
 }
 
@@ -974,7 +1046,11 @@ linuxdvb_satconf_ele_create0
     /* Rotor */
     if (lse->ls_rotor && (e = htsmsg_get_map(conf, "rotor_conf")))
       idnode_load(&lse->ls_rotor->ld_id, e);
-  }
+
+    /* EN50494 */
+    if (lse->ls_en50494 && (e = htsmsg_get_map(conf, "en50494_conf")))
+      idnode_load(&lse->ls_en50494->ld_id, e);
+}
 
   /* Create default LNB */
   if (!lse->ls_lnb)
@@ -995,6 +1071,8 @@ linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls )
     linuxdvb_switch_destroy(ls->ls_switch);
   if (ls->ls_rotor)
     linuxdvb_rotor_destroy(ls->ls_rotor);
+  if (ls->ls_en50494)
+    linuxdvb_en50494_destroy(ls->ls_en50494);
   mpegts_input_delete((mpegts_input_t*)ls);
 #endif
 }