From 35a2216eb8b1a79ed64b7993247ddd2d0d82269a Mon Sep 17 00:00:00 2001 From: "Sascha Kuehndel (InuSasha)" Date: Thu, 9 Jan 2014 19:23:33 +0100 Subject: [PATCH] EN50494: basic collision control - add DiSEqC repeats to en50494 tune, with random delay - avoid parallel tuning on en50494 --- src/input/mpegts/linuxdvb/linuxdvb.c | 3 + src/input/mpegts/linuxdvb/linuxdvb_en50494.c | 90 ++++++++++++-------- src/input/mpegts/linuxdvb/linuxdvb_private.h | 2 + 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/input/mpegts/linuxdvb/linuxdvb.c b/src/input/mpegts/linuxdvb/linuxdvb.c index 33287eb8..cd959400 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 index bdaa3bab..16f1e0f0 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_en50494.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_en50494.c @@ -18,8 +18,6 @@ * along with this program. If not, see . * * Open things: - * - TODO: make linuxdvb_en50494_tune thread safe - * avoid self-raised collisions * - 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). @@ -70,6 +68,8 @@ // /* 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 ) @@ -126,6 +126,7 @@ 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; @@ -142,7 +143,7 @@ linuxdvb_en50494_tune } /* tune frequency for the frontend */ - le->le_tune_freq = (t + 350) * 4000 - freq; /* real used en50494 frequency */ + le->le_tune_freq = (t + 350) * 4000 - freq; /* 2 data fields (16bit) */ uint8_t data1, data2; @@ -156,40 +157,53 @@ linuxdvb_en50494_tune "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)) { - tvherror(LINUXDVB_EN50494_NAME, "error setting lnb voltage to 18V"); - return -1; - } - usleep(15000); /* standard: 4ms < x < 22ms */ + 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); + } - /* 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"); - return -1; - } - usleep(50000); /* standard: 2ms < x < 60ms */ + /* use 18V */ + if (linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_18)) { + tvherror(LINUXDVB_EN50494_NAME, "error setting lnb voltage to 18V"); + pthread_mutex_unlock(&linuxdvb_en50494_lock); + return -1; + } + usleep(15000); /* standard: 4ms < x < 22ms */ - /* return to 13V */ - if (linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_13)) { - tvherror(LINUXDVB_EN50494_NAME, "error setting lnb voltage back to 13V"); - return -1; + /* 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"); + pthread_mutex_unlock(&linuxdvb_en50494_lock); + return -1; + } + usleep(50000); /* standard: 2ms < x < 60ms */ + + /* return to 13V */ + if (linuxdvb_diseqc_set_volt(fd, SEC_VOLTAGE_13)) { + tvherror(LINUXDVB_EN50494_NAME, "error setting lnb voltage back to 13V"); + pthread_mutex_unlock(&linuxdvb_en50494_lock); + return -1; + } } + pthread_mutex_unlock(&linuxdvb_en50494_lock); return 0; } @@ -199,6 +213,14 @@ linuxdvb_en50494_tune * 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 ) { diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index 251c727d..b1d89e56 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -358,6 +358,8 @@ 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 (int fd, uint8_t framing, uint8_t addr, uint8_t cmd, uint8_t len, ...);