Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Cleanup, fixes and improvements of linuxdvb frontend statistics code,
including webui improvements and fixes.
  • Loading branch information
ksooo authored and perexg committed Aug 1, 2014
1 parent bcb8373 commit 1858323
Show file tree
Hide file tree
Showing 8 changed files with 382 additions and 106 deletions.
4 changes: 2 additions & 2 deletions src/htsp_server.c
Expand Up @@ -2798,9 +2798,9 @@ htsp_subscription_signal_status(htsp_subscription_t *hs, signal_status_t *sig)
htsmsg_add_str(m, "method", "signalStatus");
htsmsg_add_u32(m, "subscriptionId", hs->hs_sid);
htsmsg_add_str(m, "feStatus", sig->status_text);
if(sig->snr != -2)
if((sig->snr != -2) && (sig->snr_scale == SIGNAL_STATUS_SCALE_RELATIVE))
htsmsg_add_u32(m, "feSNR", sig->snr);
if(sig->signal != -2)
if((sig->signal != -2) && (sig->signal_scale == SIGNAL_STATUS_SCALE_RELATIVE))
htsmsg_add_u32(m, "feSignal", sig->signal);
if(sig->ber != -2)
htsmsg_add_u32(m, "feBER", sig->ber);
Expand Down
6 changes: 6 additions & 0 deletions src/input.c
Expand Up @@ -80,12 +80,18 @@ tvh_input_stream_create_msg
htsmsg_add_u32(m, "subs", st->subs_count);
htsmsg_add_u32(m, "weight", st->max_weight);
htsmsg_add_u32(m, "signal", st->stats.signal);
htsmsg_add_u32(m, "signal_scale", st->stats.signal_scale);
htsmsg_add_u32(m, "ber", st->stats.ber);
htsmsg_add_u32(m, "snr", st->stats.snr);
htsmsg_add_u32(m, "snr_scale", st->stats.snr_scale);
htsmsg_add_u32(m, "unc", st->stats.unc);
htsmsg_add_u32(m, "bps", st->stats.bps);
htsmsg_add_u32(m, "te", st->stats.te);
htsmsg_add_u32(m, "cc", st->stats.cc);
htsmsg_add_u32(m, "ec_bit", st->stats.ec_bit);
htsmsg_add_u32(m, "tc_bit", st->stats.tc_bit);
htsmsg_add_u32(m, "ec_block", st->stats.ec_block);
htsmsg_add_u32(m, "tc_block", st->stats.tc_block);
return m;
}

Expand Down
38 changes: 31 additions & 7 deletions src/input.h
Expand Up @@ -34,18 +34,42 @@ typedef LIST_HEAD(,tvh_hardware) tvh_hardware_list_t;
typedef LIST_HEAD(,tvh_input) tvh_input_list_t;
typedef LIST_HEAD(,tvh_input_stream) tvh_input_stream_list_t;

/*
* Scales for input stream statistics values
*/
typedef enum {
INPUT_STREAM_STATS_SCALE_UNKNOWN = 0,
INPUT_STREAM_STATS_SCALE_RELATIVE, // value is unsigned, where 0 means 0% and 65535 means 100%
INPUT_STREAM_STATS_SCALE_DECIBEL // value is measured in dB
} tvh_input_stream_stats_scale_t;

/*
* Input stream structure - used for getting statistics about active streams
*/
struct tvh_input_stream_stats
{
int signal; ///< Signal level (0-100)
int ber; ///< Bit error rate (0-100?)
int unc; ///< Uncorrectable errors
int snr; ///< Signal 2 Noise (dB)
int bps; ///< Bandwidth (bps)
int cc; ///< Continuity errors
int te; ///< Transport errors
int signal; ///< signal strength, value depending on signal_scale value:
///< - SCALE_RELATIVE : 0...65535 (which means 0%...100%)
///< - SCALE DECIBEL : 0.0001 dBm units. This value is generally negative.
int snr; ///< signal to noise ratio, value depending on snr_scale value:
///< - SCALE_RELATIVE : 0...65535 (which means 0%...100%)
///< - SCALE DECIBEL : 0.0001 dB units.
int ber; ///< bit error rate (driver/vendor specific value!)
int unc; ///< number of uncorrected blocks
int bps; ///< bandwidth (bps)
int cc; ///< number of continuity errors
int te; ///< number of transport errors

tvh_input_stream_stats_scale_t signal_scale;
tvh_input_stream_stats_scale_t snr_scale;

/* Note: if tc_bit > 0, BER = ec_bit / tc_bit (0...1) else BER = ber (driver specific value) */
int ec_bit; ///< ERROR_BIT_COUNT (same as unc?)
int tc_bit; ///< TOTAL_BIT_COUNT

/* Note: PER = ec_block / tc_block (0...1) */
int ec_block; ///< ERROR_BLOCK_COUNT
int tc_block; ///< TOTAL_BLOCK_COUNT
};

struct tvh_input_stream {
Expand Down
177 changes: 145 additions & 32 deletions src/input/mpegts/linuxdvb/linuxdvb_frontend.c
Expand Up @@ -432,6 +432,7 @@ linuxdvb_frontend_monitor ( void *aux )
#if DVB_VER_ATLEAST(5,10)
struct dtv_property fe_properties[6];
struct dtv_properties dtv_prop;
int gotprop;
#endif

lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf));
Expand Down Expand Up @@ -536,82 +537,194 @@ linuxdvb_frontend_monitor ( void *aux )
/* Statistics - New API */
#if DVB_VER_ATLEAST(5,10)
memset(&fe_properties, 0, sizeof(fe_properties));

/* Signal strength */
fe_properties[0].cmd = DTV_STAT_SIGNAL_STRENGTH;

/* BER */
fe_properties[1].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
fe_properties[2].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT;

/* SNR */
fe_properties[3].cmd = DTV_STAT_CNR;

/* PER */
/* PER / UNC */
fe_properties[4].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
fe_properties[5].cmd = DTV_STAT_TOTAL_BLOCK_COUNT;
dtv_prop.num = 6;
dtv_prop.props = fe_properties;

if(!ioctl(lfe->lfe_fe_fd, FE_GET_PROPERTY, &dtv_prop)) {
/* Signal strength */
gotprop = 0;
if(fe_properties[0].u.st.len > 0) {
if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_RELATIVE)
mmi->mmi_stats.signal = (fe_properties[0].u.st.stat[0].uvalue * 100) / 0xffff;
/* TODO: handle other scales */
if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_RELATIVE) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.signal = fe_properties[0].u.st.stat[0].uvalue;
gotprop = 1;
}
else if(fe_properties[0].u.st.stat[0].scale == FE_SCALE_DECIBEL) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_DECIBEL;
mmi->mmi_stats.signal = fe_properties[0].u.st.stat[0].svalue;
gotprop = 1;
}
else {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled signal scale: %d",
fe_properties[0].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.signal = u16;
}
else {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide signal strength value.");
}
}

/* Calculate BER from PRE_ERROR and TOTAL_BIT_COUNT */
/* ERROR_BIT_COUNT */
gotprop = 0;
if(fe_properties[1].u.st.len > 0) {
if(fe_properties[1].u.st.stat[0].scale == FE_SCALE_COUNTER)
u16 = fe_properties[1].u.st.stat[0].uvalue;
if(fe_properties[1].u.st.stat[0].scale == FE_SCALE_COUNTER) {
mmi->mmi_stats.ec_bit = fe_properties[1].u.st.stat[0].uvalue;
gotprop = 1;
}
else
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled ERROR_BIT_COUNT scale: %d",
fe_properties[1].u.st.stat[0].scale);
}
if(fe_properties[2].u.st.len > 0) {
/* TOTAL_BIT_COUNT */
if(gotprop && (fe_properties[2].u.st.len > 0)) {
gotprop = 0;
if(fe_properties[2].u.st.stat[0].scale == FE_SCALE_COUNTER) {
if(fe_properties[2].u.st.stat[0].uvalue > 0 )
mmi->mmi_stats.ber = u16 / fe_properties[2].u.st.stat[0].uvalue;
else
mmi->mmi_stats.ber = 0;
mmi->mmi_stats.tc_bit = fe_properties[2].u.st.stat[0].uvalue;
gotprop = 1;
}
else {
mmi->mmi_stats.ec_bit = 0; /* both values or none */
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled TOTAL_BIT_COUNT scale: %d",
fe_properties[2].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_BER, &u32))
mmi->mmi_stats.ber = u32;
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide BER value.");
}

/* SNR */
gotprop = 0;
if(fe_properties[3].u.st.len > 0) {
/* note that decibel scale means 1 = 0.0001 dB units here */
if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_DECIBEL)
mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].svalue * 0.0001;
/* TODO: handle other scales */
if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_RELATIVE) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].uvalue;
gotprop = 1;
}
else if(fe_properties[3].u.st.stat[0].scale == FE_SCALE_DECIBEL) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_DECIBEL;
mmi->mmi_stats.snr = fe_properties[3].u.st.stat[0].svalue;
gotprop = 1;
}
else {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled SNR scale: %d",
fe_properties[3].u.st.stat[0].scale);
}
}
if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.snr = u16;
}
else {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide SNR value.");
}
}

/* Calculate PER from PRE_ERROR and TOTAL_BIT_COUNT */
/* ERROR_BLOCK_COUNT == Uncorrected blocks (UNC) */
gotprop = 0;
if(fe_properties[4].u.st.len > 0) {
if(fe_properties[4].u.st.stat[0].scale == FE_SCALE_COUNTER)
u16 = fe_properties[4].u.st.stat[0].uvalue;
if(fe_properties[4].u.st.stat[0].scale == FE_SCALE_COUNTER) {
mmi->mmi_stats.unc = mmi->mmi_stats.ec_block = fe_properties[4].u.st.stat[0].uvalue;
gotprop = 1;
}
else
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled ERROR_BLOCK_COUNT scale: %d",
fe_properties[4].u.st.stat[0].scale);
}
if(fe_properties[5].u.st.len > 0) {

/* TOTAL_BLOCK_COUNT */
if(gotprop && (fe_properties[5].u.st.len > 0)) {
gotprop = 0;
if(fe_properties[5].u.st.stat[0].scale == FE_SCALE_COUNTER) {
if(fe_properties[5].u.st.stat[0].uvalue > 0 )
mmi->mmi_stats.unc = u16 / fe_properties[5].u.st.stat[0].uvalue;
else
mmi->mmi_stats.unc = 0;
mmi->mmi_stats.tc_block = fe_properties[5].u.st.stat[0].uvalue;
gotprop = 1;
}
else {
mmi->mmi_stats.ec_block = mmi->mmi_stats.unc = 0; /* both values or none */
tvhlog(LOG_WARNING, "linuxdvb", "Unhandled TOTAL_BLOCK_COUNT scale: %d",
fe_properties[5].u.st.stat[0].scale);
}
}

if(!gotprop) {
/* try old API */
if (!ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32)) {
mmi->mmi_stats.unc = u32;
gotprop = 1;
}
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide UNC value.");
}
/* Older API */
} else
#endif
{
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16))
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SIGNAL_STRENGTH, &u16)) {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.signal = u16;
}
else {
mmi->mmi_stats.signal_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide signal strength value.");
}
if (!ioctl(lfe->lfe_fe_fd, FE_READ_BER, &u32))
mmi->mmi_stats.ber = u32;
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16))
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide BER value.");
if (!ioctl(lfe->lfe_fe_fd, FE_READ_SNR, &u16)) {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_RELATIVE;
mmi->mmi_stats.snr = u16;
}
else {
mmi->mmi_stats.snr_scale = INPUT_STREAM_STATS_SCALE_UNKNOWN;
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide SNR value.");
}
if (!ioctl(lfe->lfe_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &u32))
mmi->mmi_stats.unc = u32;
else
tvhlog(LOG_WARNING, "linuxdvb", "Unable to provide UNC value.");
}

/* Send message */
sigstat.status_text = signal2str(status);
sigstat.snr = mmi->mmi_stats.snr;
sigstat.signal = mmi->mmi_stats.signal;
sigstat.ber = mmi->mmi_stats.ber;
sigstat.unc = mmi->mmi_stats.unc;
sigstat.status_text = signal2str(status);
sigstat.snr = mmi->mmi_stats.snr;
sigstat.signal = mmi->mmi_stats.signal;
sigstat.ber = mmi->mmi_stats.ber;
sigstat.unc = mmi->mmi_stats.unc;
sigstat.signal_scale = mmi->mmi_stats.signal_scale;
sigstat.snr_scale = mmi->mmi_stats.snr_scale;
sigstat.ec_bit = mmi->mmi_stats.ec_bit;
sigstat.tc_bit = mmi->mmi_stats.tc_bit;
sigstat.ec_block = mmi->mmi_stats.ec_block;
sigstat.tc_block = mmi->mmi_stats.tc_block;
sm.sm_type = SMT_SIGNAL_STATUS;
sm.sm_data = &sigstat;
LIST_FOREACH(s, &lfe->mi_transports, s_active_link) {
Expand Down
34 changes: 26 additions & 8 deletions src/input/mpegts/satip/satip_frontend.c
Expand Up @@ -712,15 +712,19 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name,
if (atoi(argv[0]) != lfe->sf_number)
return;
mmi->mmi_stats.signal =
(atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale;
((atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale) * 65535 / 100;
mmi->mmi_stats.signal_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (atoi(argv[2]) > 0)
status = SIGNAL_GOOD;
mmi->mmi_stats.snr = atoi(argv[3]);
mmi->mmi_stats.snr = atoi(argv[3]) * 65535 / 100;
mmi->mmi_stats.snr_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (status == SIGNAL_GOOD &&
mmi->mmi_stats.signal == 0 && mmi->mmi_stats.snr == 0) {
/* some values that we're tuned */
mmi->mmi_stats.signal = 50;
mmi->mmi_stats.snr = 12;
mmi->mmi_stats.signal = 50 * 65535 / 100;
mmi->mmi_stats.snr = 12 * 65535 / 100;
}
goto ok;
} else if (strncmp(s, "ver=1.0;", 8) == 0) {
Expand All @@ -733,10 +737,14 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name,
if (atoi(argv[0]) != lfe->sf_number)
return;
mmi->mmi_stats.signal =
(atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale;
((atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale) * 65535 / 100;
mmi->mmi_stats.signal_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (atoi(argv[2]) > 0)
status = SIGNAL_GOOD;
mmi->mmi_stats.snr = atoi(argv[3]);
mmi->mmi_stats.snr = atoi(argv[3]) * 65535 / 100;
mmi->mmi_stats.snr_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
goto ok;
} else if (strncmp(s, "ver=1.1;tuner=", 14) == 0) {
n = http_tokenize(s + 14, argv, 4, ',');
Expand All @@ -745,10 +753,14 @@ satip_frontend_decode_rtcp( satip_frontend_t *lfe, const char *name,
if (atoi(argv[0]) != lfe->sf_number)
return;
mmi->mmi_stats.signal =
(atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale;
((atoi(argv[1]) * 100) / lfe->sf_device->sd_sig_scale) * 65535 / 100;
mmi->mmi_stats.signal_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
if (atoi(argv[2]) > 0)
status = SIGNAL_GOOD;
mmi->mmi_stats.snr = atoi(argv[3]);
mmi->mmi_stats.snr = atoi(argv[3]) * 65535 / 100;
mmi->mmi_stats.snr_scale =
INPUT_STREAM_STATS_SCALE_RELATIVE;
goto ok;
}
}
Expand Down Expand Up @@ -1260,6 +1272,12 @@ satip_frontend_signal_cb( void *aux )
sigstat.signal = mmi->mmi_stats.signal;
sigstat.ber = mmi->mmi_stats.ber;
sigstat.unc = mmi->mmi_stats.unc;
sigstat.signal_scale = mmi->mmi_stats.signal_scale;
sigstat.snr_scale = mmi->mmi_stats.snr_scale;
sigstat.ec_bit = mmi->mmi_stats.ec_bit;
sigstat.tc_bit = mmi->mmi_stats.tc_bit;
sigstat.ec_block = mmi->mmi_stats.ec_block;
sigstat.tc_block = mmi->mmi_stats.tc_block;
sm.sm_type = SMT_SIGNAL_STATUS;
sm.sm_data = &sigstat;
LIST_FOREACH(svc, &lfe->mi_transports, s_active_link) {
Expand Down

0 comments on commit 1858323

Please sign in to comment.