Commit 3e51a496 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

media: vidtv: add basic support for DVBv5 stats

The current stats code is broken on so many ways. It ends
reporting 0 for signal strengh, and the work queue doesn't
run. If it would run, the code would crash.

Fix such issues and add the minimum stuff for DVBv5 stats.

Right now, only strength and cnr and UCB are implemented.
pre/post BER stats will always return zero.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 96230dc1
......@@ -122,6 +122,74 @@ static const struct vidtv_demod_cnr_to_qual_s
return NULL; /* not found */
}
static void vidtv_clean_stats(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
/* Fill the length of each status counter */
/* Signal is always available */
c->strength.len = 1;
c->strength.stat[0].scale = FE_SCALE_DECIBEL;
c->strength.stat[0].svalue = 0;
/* Usually available only after Viterbi lock */
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->cnr.stat[0].svalue = 0;
c->cnr.len = 1;
/* Those depends on full lock */
c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->pre_bit_error.stat[0].uvalue = 0;
c->pre_bit_error.len = 1;
c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->pre_bit_count.stat[0].uvalue = 0;
c->pre_bit_count.len = 1;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.stat[0].uvalue = 0;
c->post_bit_error.len = 1;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].uvalue = 0;
c->post_bit_count.len = 1;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].uvalue = 0;
c->block_error.len = 1;
c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_count.stat[0].uvalue = 0;
c->block_count.len = 1;
}
static void vidtv_demod_update_stats(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct vidtv_demod_state *state = fe->demodulator_priv;
u32 scale;
if (state->status & FE_HAS_LOCK) {
scale = FE_SCALE_COUNTER;
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
} else {
scale = FE_SCALE_NOT_AVAILABLE;
c->cnr.stat[0].scale = scale;
}
c->pre_bit_error.stat[0].scale = scale;
c->pre_bit_count.stat[0].scale = scale;
c->post_bit_error.stat[0].scale = scale;
c->post_bit_count.stat[0].scale = scale;
c->block_error.stat[0].scale = scale;
c->block_count.stat[0].scale = scale;
/*
* Add a 0.5% of randomness at the signal streangth and CNR,
* and make them different, as we want to have something closer
* to a real case scenario.
*/
c->strength.stat[0].svalue = state->tuner_cnr + prandom_u32_max(state->tuner_cnr / 50);
c->cnr.stat[0].svalue = state->tuner_cnr - prandom_u32_max(state->tuner_cnr / 50);
}
static void vidtv_demod_poll_snr_handler(struct work_struct *work)
{
/*
......@@ -133,33 +201,34 @@ static void vidtv_demod_poll_snr_handler(struct work_struct *work)
struct vidtv_demod_config *config;
u16 snr = 0;
state = container_of(work, struct vidtv_demod_state, poll_snr.work);
state = container_of(work, struct vidtv_demod_state, poll_snr.work);
config = &state->config;
if (!state->frontend.ops.tuner_ops.get_rf_strength)
return;
state->frontend.ops.tuner_ops.get_rf_strength(&state->frontend, &snr);
/* Simulate random lost of signal due to a bad-tuned channel */
cnr2qual = vidtv_match_cnr_s(&state->frontend);
if (!cnr2qual)
return;
if (snr < cnr2qual->cnr_ok) {
/* eventually lose the TS lock */
if (prandom_u32_max(100) < config->drop_tslock_prob_on_low_snr)
state->status = 0;
} else {
/* recover if the signal improves */
if (prandom_u32_max(100) <
config->recover_tslock_prob_on_good_snr)
state->status = FE_HAS_SIGNAL |
FE_HAS_CARRIER |
FE_HAS_VITERBI |
FE_HAS_SYNC |
FE_HAS_LOCK;
if (cnr2qual && state->tuner_cnr < cnr2qual->cnr_good &&
state->frontend.ops.tuner_ops.get_rf_strength) {
state->frontend.ops.tuner_ops.get_rf_strength(&state->frontend, &snr);
if (snr < cnr2qual->cnr_ok) {
/* eventually lose the TS lock */
if (prandom_u32_max(100) < config->drop_tslock_prob_on_low_snr)
state->status = 0;
} else {
/* recover if the signal improves */
if (prandom_u32_max(100) <
config->recover_tslock_prob_on_good_snr)
state->status = FE_HAS_SIGNAL |
FE_HAS_CARRIER |
FE_HAS_VITERBI |
FE_HAS_SYNC |
FE_HAS_LOCK;
}
}
vidtv_demod_update_stats(&state->frontend);
schedule_delayed_work(&state->poll_snr,
msecs_to_jiffies(POLL_THRD_TIME));
}
......@@ -174,28 +243,13 @@ static int vidtv_demod_read_status(struct dvb_frontend *fe,
return 0;
}
static int vidtv_demod_read_ber(struct dvb_frontend *fe, u32 *ber)
{
*ber = 0;
return 0;
}
static int vidtv_demod_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
*strength = 0;
return 0;
}
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
static int vidtv_demod_read_snr(struct dvb_frontend *fe, u16 *snr)
{
*snr = 0;
return 0;
}
*strength = c->strength.stat[0].uvalue;
static int vidtv_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
*ucblocks = 0;
return 0;
}
......@@ -216,38 +270,42 @@ static int vidtv_demod_get_frontend(struct dvb_frontend *fe,
static int vidtv_demod_set_frontend(struct dvb_frontend *fe)
{
struct vidtv_demod_state *state = fe->demodulator_priv;
const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
u32 tuner_status = 0;
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe);
/* store the CNR returned by the tuner */
fe->ops.tuner_ops.get_rf_strength(fe, &state->tuner_cnr);
fe->ops.tuner_ops.get_status(fe, &tuner_status);
state->status = (state->tuner_cnr > 0) ? FE_HAS_SIGNAL |
FE_HAS_CARRIER |
FE_HAS_VITERBI |
FE_HAS_SYNC |
FE_HAS_LOCK :
0;
cnr2qual = vidtv_match_cnr_s(fe);
/* signal isn't good: might lose the lock eventually */
if (tuner_status == TUNER_STATUS_LOCKED &&
state->tuner_cnr < cnr2qual->cnr_good) {
schedule_delayed_work(&state->poll_snr,
msecs_to_jiffies(POLL_THRD_TIME));
state->poll_snr_thread_running = true;
}
struct vidtv_demod_state *state = fe->demodulator_priv;
u32 tuner_status = 0;
int ret;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
if (!fe->ops.tuner_ops.set_params)
return 0;
fe->ops.tuner_ops.set_params(fe);
/* store the CNR returned by the tuner */
ret = fe->ops.tuner_ops.get_rf_strength(fe, &state->tuner_cnr);
if (ret < 0)
return ret;
fe->ops.tuner_ops.get_status(fe, &tuner_status);
state->status = (state->tuner_cnr > 0) ? FE_HAS_SIGNAL |
FE_HAS_CARRIER |
FE_HAS_VITERBI |
FE_HAS_SYNC |
FE_HAS_LOCK :
0;
cnr2qual = vidtv_match_cnr_s(fe);
vidtv_demod_update_stats(fe);
if (state->tuner_cnr > 0) {
schedule_delayed_work(&state->poll_snr,
msecs_to_jiffies(POLL_THRD_TIME));
state->poll_snr_thread_running = true;
}
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
return 0;
}
......@@ -372,10 +430,7 @@ static const struct dvb_frontend_ops vidtv_demod_ops = {
.get_frontend = vidtv_demod_get_frontend,
.read_status = vidtv_demod_read_status,
.read_ber = vidtv_demod_read_ber,
.read_signal_strength = vidtv_demod_read_signal_strength,
.read_snr = vidtv_demod_read_snr,
.read_ucblocks = vidtv_demod_read_ucblocks,
/* For DVB-S/S2 */
.set_voltage = vidtv_demod_set_voltage,
......@@ -411,6 +466,8 @@ static int vidtv_demod_i2c_probe(struct i2c_client *client,
state->frontend.demodulator_priv = state;
i2c_set_clientdata(client, state);
vidtv_clean_stats(&state->frontend);
return 0;
}
......
......@@ -246,7 +246,7 @@ vidtv_tuner_get_signal_strength(struct dvb_frontend *fe, u16 *strength)
* do a linear interpolation between 34dB and 10dB if we can't
* match against the table
*/
*strength = 34 - 24 * shift / 100;
*strength = 34000 - 24000 * shift / 100;
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment