diff --git a/Makefile b/Makefile index 479b8bb2..bfe7abd1 100644 --- 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 -O2 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.c b/src/input/mpegts/linuxdvb/linuxdvb.c index 56457423..4c4d5a3a 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb.c +++ b/src/input/mpegts/linuxdvb/linuxdvb.c @@ -32,6 +32,9 @@ void linuxdvb_init ( int adapter_mask ) /* Load list of mux charset global overrides */ dvb_charset_init(); + /* Initialise en50494 locks */ + linuxdvb_en50494_init(); + /* Initialise networks */ linuxdvb_network_init(); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_en50494.c b/src/input/mpegts/linuxdvb/linuxdvb_en50494.c new file mode 100644 index 00000000..e2ca8678 --- /dev/null +++ b/src/input/mpegts/linuxdvb/linuxdvb_en50494.c @@ -0,0 +1,270 @@ +/* + * 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 . + * + * Open things: + * - TODO: collision dectection + * when a en50494-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 +#include + +/* ************************************************************************** + * 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 le_tune_freq; /* the real frequency to tune to */ +//} linuxdvb_en50494_t; +/* prevention of self raised DiSEqC collisions */ +static pthread_mutex_t linuxdvb_en50494_lock; + +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; +} + +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_U16, + .id = "position", + .name = "Position", + .off = offsetof(linuxdvb_en50494_t, le_position), + }, + { + .type = PT_U16, + .id = "frequency", + .name = "Frequency", + .off = offsetof(linuxdvb_en50494_t, le_frequency), + }, + { + .type = PT_U16, + .id = "id", + .name = "ID", + .off = offsetof(linuxdvb_en50494_t, le_id), + }, + { + .type = PT_U16, + .id = "pin", + .name = "Pin", + .off = offsetof(linuxdvb_en50494_t, le_pin), + }, + {} + } +}; + + +/* ************************************************************************** + * 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; + int i; + 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) { + tvherror(LINUXDVB_EN50494_NAME, "transponder value bigger then 1024"); + return -1; + } + + /* tune frequency for the frontend */ + le->le_tune_freq = (t + 350) * 4000 - freq; + + /* 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(1)) */ + 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 */ + tvhdebug(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); + + pthread_mutex_lock(&linuxdvb_en50494_lock); + for (i = 0; i <= sc->ls_parent->ls_diseqc_repeats; i++) { + /* to avoid repeated collision, wait a random time (5-25ms) */ + if (i != 0) { + int ms = rand()%20 + 5; + usleep(ms*1000); + } + + /* use 18V */ + ret = linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_18); + if (ret) { + tvherror(LINUXDVB_EN50494_NAME, "error setting lnb voltage to 18V"); + break; + } + usleep(15000); /* standard: 4ms < x < 22ms */ + + /* send tune command (with/without 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) { + tvherror(LINUXDVB_EN50494_NAME, "error send tune command"); + break; + } + usleep(50000); /* standard: 2ms < x < 60ms */ + + /* return to 13V */ + ret = linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_13); + if (ret) { + tvherror(LINUXDVB_EN50494_NAME, "error setting lnb voltage back to 13V"); + break; + } + } + pthread_mutex_unlock(&linuxdvb_en50494_lock); + + return ret == 0 ? 0 : -1; +} + + +/* ************************************************************************** + * Create / Config + * *************************************************************************/ + +void +linuxdvb_en50494_init (void) +{ + if (pthread_mutex_init(&linuxdvb_en50494_lock, NULL) != 0) { + tvherror(LINUXDVB_EN50494_NAME, "failed to init lock mutex"); + } +} + +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, int port ) +{ + linuxdvb_diseqc_t *ld; + linuxdvb_en50494_t *le; + + if (port > 1) { + tvherror(LINUXDVB_EN50494_NAME, "only 2 ports/positions are posible. given %i", port); + port = 0; + } + + 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; */ + + le->le_position = port; + le->le_id = 0; + le->le_frequency = 0; + le->le_pin = LINUXDVB_EN50494_NOPIN; + } + + return (linuxdvb_diseqc_t*)ld; +} + +void +linuxdvb_en50494_destroy ( linuxdvb_diseqc_t *le ) +{ + linuxdvb_diseqc_destroy(le); + free(le); +} diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index 0b37f977..5bf584b6 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -34,6 +34,7 @@ typedef struct linuxdvb_diseqc linuxdvb_diseqc_t; typedef struct linuxdvb_lnb linuxdvb_lnb_t; typedef struct linuxdvb_network linuxdvb_network_t; typedef struct linuxdvb_mux linuxdvb_mux_t; +typedef struct linuxdvb_en50494 linuxdvb_en50494_t; typedef LIST_HEAD(,linuxdvb_hardware) linuxdvb_hardware_list_t; typedef TAILQ_HEAD(linuxdvb_satconf_ele_list,linuxdvb_satconf_ele) linuxdvb_satconf_ele_list_t; @@ -157,6 +158,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 @@ -177,6 +179,20 @@ struct linuxdvb_lnb int (*lnb_pol) (linuxdvb_lnb_t*, linuxdvb_mux_t*); }; +struct linuxdvb_en50494 +{ + linuxdvb_diseqc_t; + + /* en50494 configuration*/ + uint16_t le_position; /* satelitte A(0) or B(1) */ + uint16_t le_frequency; /* user band frequency in MHz */ + uint16_t le_id; /* user band id 0-7 */ + uint16_t le_pin; /* 0-255 or LINUXDVB_EN50494_NOPIN */ + + /* runtime */ + uint32_t le_tune_freq; /* the real frequency to tune to */ +}; + /* * Methods */ @@ -273,14 +289,20 @@ 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, int port ); -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 ); + +void linuxdvb_en50494_init (void); int linuxdvb_diseqc_send diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index d376621e..a7f23617 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -165,6 +165,150 @@ linuxdvb_satconf_class_orbitalpos_set return 1; } +static htsmsg_t * +linuxdvb_satconf_class_en50494_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 const void * +linuxdvb_satconf_class_en50494_id_get ( void *p ) +{ + linuxdvb_satconf_t *ls = p; + linuxdvb_satconf_ele_t *lse = TAILQ_FIRST(&ls->ls_elements); + linuxdvb_en50494_t *le; + static uint16_t default_value = 0; + + if (!lse && !lse->ls_en50494) + return &default_value; + + le = (linuxdvb_en50494_t*)lse->ls_en50494; + return &le->le_id; +} + +static int +linuxdvb_satconf_class_en50494_id_set + ( void *p, const void *v ) +{ + linuxdvb_satconf_t *ls = p; + linuxdvb_satconf_ele_t *lse; + linuxdvb_en50494_t *le; + uint16_t new_value = *(uint16_t*)v; + + if (new_value < 0 || new_value > 7) + return 1; + + TAILQ_FOREACH(lse, &ls->ls_elements, ls_link) { + if (!lse && !lse->ls_en50494) + continue; + + le = (linuxdvb_en50494_t*)lse->ls_en50494; + le->le_id = new_value; + } + return 0; + +} + +static const void * +linuxdvb_satconf_class_en50494_freq_get ( void *p ) +{ + linuxdvb_satconf_t *ls = p; + linuxdvb_satconf_ele_t *lse = TAILQ_FIRST(&ls->ls_elements); + linuxdvb_en50494_t *le; + static uint16_t default_value = 0; + + if (!lse && !lse->ls_en50494) + return &default_value; + + le = (linuxdvb_en50494_t*)lse->ls_en50494; + return &le->le_frequency; +} + +static int +linuxdvb_satconf_class_en50494_freq_set + ( void *p, const void *v ) +{ + linuxdvb_satconf_t *ls = p; + linuxdvb_satconf_ele_t *lse; + linuxdvb_en50494_t *le; + uint16_t new_value = *(uint16_t*)v; + + TAILQ_FOREACH(lse, &ls->ls_elements, ls_link) { + if (!lse && !lse->ls_en50494) + continue; + + le = (linuxdvb_en50494_t*)lse->ls_en50494; + le->le_frequency = new_value; + } + return 0; +} + +static htsmsg_t * +linuxdvb_satconf_class_en50494_pin_list ( void *o ) +{ + int32_t i; + + htsmsg_t *m = htsmsg_create_list(); + htsmsg_t *e; + + e = htsmsg_create_map(); + htsmsg_add_u32(e, "key", 256); + htsmsg_add_str(e, "val", "no Pin"); + htsmsg_add_msg(m, NULL, e); + + for (i = 0; i < 256; i++) { + e = htsmsg_create_map(); + htsmsg_add_u32(e, "key", i); + htsmsg_add_u32(e, "val", i); + htsmsg_add_msg(m, NULL, e); + } + return m; +} + + +static const void * +linuxdvb_satconf_class_en50494_pin_get ( void *p ) +{ + linuxdvb_satconf_t *ls = p; + linuxdvb_satconf_ele_t *lse = TAILQ_FIRST(&ls->ls_elements); + linuxdvb_en50494_t *le; + static uint16_t default_value = 256; + + if (!lse && !lse->ls_en50494) + return &default_value; + + le = (linuxdvb_en50494_t*)lse->ls_en50494; + return &le->le_pin; +} + +static int +linuxdvb_satconf_class_en50494_pin_set + ( void *p, const void *v ) +{ + linuxdvb_satconf_t *ls = p; + linuxdvb_satconf_ele_t *lse; + linuxdvb_en50494_t *le; + uint16_t new_value = *(uint16_t*)v; + + if (new_value < 0 || new_value > 256) + return 1; + + TAILQ_FOREACH(lse, &ls->ls_elements, ls_link) { + if (!lse && !lse->ls_en50494) + continue; + + le = (linuxdvb_en50494_t*)lse->ls_en50494; + le->le_pin = new_value; + } + return 0; +} + static idnode_set_t * linuxdvb_satconf_class_get_childs ( idnode_t *o ) { @@ -211,7 +355,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, @@ -233,7 +377,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, @@ -242,7 +386,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, @@ -264,7 +408,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, @@ -273,7 +417,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, @@ -282,7 +426,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, @@ -291,7 +435,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, @@ -300,6 +444,63 @@ 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, + }, + { + .type = PT_U16, + .id = "id", + .name = "ID", + .get = linuxdvb_satconf_class_en50494_id_get, + .set = linuxdvb_satconf_class_en50494_id_set, + .list = linuxdvb_satconf_class_en50494_id_list, + .opts = PO_NOSAVE, + }, + { + .type = PT_U16, + .id = "freqency", + .name = "Freqency (MHz)", + .get = linuxdvb_satconf_class_en50494_freq_get, + .set = linuxdvb_satconf_class_en50494_freq_set, + .opts = PO_NOSAVE, + }, + { + .type = PT_U16, + .id = "pin", + .name = "Pin", + .get = linuxdvb_satconf_class_en50494_pin_get, + .set = linuxdvb_satconf_class_en50494_pin_set, + .list = linuxdvb_satconf_class_en50494_pin_list, + .opts = PO_NOSAVE, + }, + {} + } +}; + /* * Advanced */ @@ -346,6 +547,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", @@ -430,15 +637,24 @@ linuxdvb_satconf_create TAILQ_FOREACH(lse, &ls->ls_elements, ls_link) { if (!lse->ls_lnb) lse->ls_lnb = linuxdvb_lnb_create0(NULL, NULL, lse); - if (lst->ports > 1 && !lse->ls_switch) - lse->ls_switch = linuxdvb_switch_create0("Generic", NULL, lse, i, -1); + /* create multi port elements (2/4port & en50494) */ + if (lst->ports > 1) { + if( !lse->ls_en50494 && !strcmp("en50494",lst->type)) + lse->ls_en50494 = linuxdvb_en50494_create0("en50494", NULL, lse, i); + if( !lse->ls_switch && (!strcmp("2port",lst->type) || !strcmp("4port",lst->type))) + lse->ls_switch = linuxdvb_switch_create0("Generic", NULL, lse, i, -1); + } i++; } for (; i < lst->ports; i++) { lse = linuxdvb_satconf_ele_create0(NULL, NULL, ls); lse->ls_lnb = linuxdvb_lnb_create0(NULL, NULL, lse); + /* create multi port elements (2/4port & en50494) */ if (lst->ports > 1) { - lse->ls_switch = linuxdvb_switch_create0("Generic", NULL, lse, i, -1); + if( !strcmp("en50494",lst->type)) + lse->ls_en50494 = linuxdvb_en50494_create0("en50494", NULL, lse, i); + if( !strcmp("2port",lst->type) || !strcmp("4port",lst->type)) + lse->ls_switch = linuxdvb_switch_create0("Generic", NULL, lse, i, -1); } } @@ -472,6 +688,11 @@ linuxdvb_satconf_save ( linuxdvb_satconf_t *ls, htsmsg_t *m ) idnode_save(&lse->ls_rotor->ld_id, c); htsmsg_add_msg(e, "rotor_conf", c); } + if (lse->ls_en50494) { + c = htsmsg_create_map(); + idnode_save(&lse->ls_en50494->ld_id, c); + htsmsg_add_msg(e, "en50494_conf", c); + } htsmsg_add_msg(l, NULL, e); } htsmsg_add_msg(m, "elements", l); @@ -562,6 +783,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, 0); + 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 ) { @@ -627,6 +868,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; } @@ -650,9 +893,9 @@ 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, - .list = linuxdvb_satconf_ele_class_network_enum, + .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, }, { @@ -682,6 +925,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", + }, {} } }; @@ -749,6 +1001,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 @@ -787,7 +1040,10 @@ 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); + /* use en50494 tuning frequency, if needed (not channel frequency) */ + f = lse->ls_en50494 + ? ((linuxdvb_en50494_t*)lse->ls_en50494)->le_tune_freq + : lse->ls_lnb->lnb_freq(lse->ls_lnb, lm); return linuxdvb_frontend_tune1(lfe, mmi, f); } @@ -880,6 +1136,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 @@ -917,9 +1174,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_en50494_destroy(ls->ls_en50494); mpegts_input_delete((mpegts_input_t*)ls); } @@ -963,7 +1221,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) @@ -989,6 +1251,8 @@ linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls, int delconf ) linuxdvb_switch_destroy(lse->ls_switch); if (lse->ls_rotor) linuxdvb_rotor_destroy(lse->ls_rotor); + if (lse->ls_en50494) + linuxdvb_en50494_destroy(lse->ls_en50494); mpegts_input_delete((mpegts_input_t*)lse); } }