dvb-fe: Improve BER measurements for DVBv5
authorMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 23 Jan 2013 19:41:46 +0000 (17:41 -0200)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 23 Jan 2013 21:18:08 +0000 (19:18 -0200)
Instead to display the BER rate calculated since the beginning of
the measurement, display the BER between two time intervals.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
lib/include/dvb-fe.h
lib/libdvbv5/dvb-fe.c

index a588d8e..026a258 100644 (file)
@@ -60,8 +60,21 @@ enum dvbv3_emulation_type {
        DVBV3_ATSC,
 };
 
+struct dvb_v5_counters {
+       uint64_t                        bit_count;
+       uint64_t                        bit_error;
+       uint64_t                        block_count;
+       uint64_t                        block_error;
+};
+
 struct dvb_v5_stats {
        struct dtv_property             prop[DTV_NUM_STATS_PROPS];
+
+       struct dvb_v5_counters          prev[MAX_DTV_STATS];
+       struct dvb_v5_counters          cur[MAX_DTV_STATS];
+
+       int                             has_ber[MAX_DTV_STATS];
+       int                             has_per[MAX_DTV_STATS];
 };
 
 struct dvb_v5_fe_parms {
index 07b40df..fed586d 100644 (file)
@@ -692,22 +692,38 @@ static struct dtv_stats *dvb_fe_store_stats(struct dvb_v5_fe_parms *parms,
        return NULL;
 }
 
+static float calculate_BER(struct dvb_v5_fe_parms *parms, unsigned layer)
+{
+       uint64_t n, d;
+
+       if (!parms->stats.has_ber[layer])
+               return -1;
+
+       d = parms->stats.cur[layer].bit_count - parms->stats.prev[layer].bit_count;
+       if (!d)
+               return -1;
+
+       n = parms->stats.cur[layer].bit_error - parms->stats.prev[layer].bit_error;
+
+       return ((float)n)/d;
+}
+
 static struct dtv_stats *dvb_fe_retrieve_v5_BER(struct dvb_v5_fe_parms *parms,
-                                               unsigned cmd, unsigned layer)
+                                               unsigned layer)
 {
-       struct dtv_stats *st_bec, *st_bc;
+       float ber;
        uint64_t ber64;
 
-       st_bec = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_POST_BIT_ERROR_COUNT, layer);
-       if (!st_bec)
-               return NULL;
-
-       st_bc = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_POST_TOTAL_BIT_COUNT, layer);
-       if (!st_bc || !st_bc->uvalue)
+       ber = calculate_BER(parms, layer);
+       if (ber < 0)
                return NULL;
 
-       ber64 = (1E9 * st_bec->uvalue) / st_bc->uvalue;
+       /*
+        * Put BER into some DVBv3 compat scale. The thing is that DVBv3 has no
+        * defined scale for BER. So, let's use 10^-7.
+        */
 
+       ber64 = 10000000 * ber;
        return dvb_fe_store_stats(parms, DTV_BER, FE_SCALE_COUNTER, layer, ber64);
 }
 
@@ -717,7 +733,7 @@ struct dtv_stats *dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms *parms,
        int i;
 
        if (cmd == DTV_BER && parms->has_v5_stats)
-               return dvb_fe_retrieve_v5_BER(parms, cmd, layer);
+               return dvb_fe_retrieve_v5_BER(parms, layer);
 
        for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
                if (parms->stats.prop[i].cmd != cmd)
@@ -759,6 +775,41 @@ int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *parms,
        return 0;
 }
 
+static void dvb_fe_update_counters(struct dvb_v5_fe_parms *parms)
+{
+       struct dtv_stats *error, *count;
+       int i;
+
+       for (i = 0; i < MAX_DTV_STATS; i++) {
+               count = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_POST_TOTAL_BIT_COUNT, i);
+               if (count) {
+                       error = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_POST_BIT_ERROR_COUNT, i);
+                       if (error && count->uvalue != parms->stats.cur[i].bit_count) {
+                               parms->stats.prev[i].bit_count = parms->stats.cur[i].bit_count;
+                               parms->stats.cur[i].bit_count = count->uvalue;
+
+                               parms->stats.prev[i].bit_error = parms->stats.cur[i].bit_error;
+                               parms->stats.cur[i].bit_error = error->uvalue;
+
+                               parms->stats.has_ber[i] = 1;
+                       }
+               }
+               count = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_TOTAL_BLOCK_COUNT, i);
+               if (count) {
+                       error = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_ERROR_BLOCK_COUNT, i);
+                       if (error && count->uvalue != parms->stats.cur[i].bit_count) {
+                               parms->stats.prev[i].block_count = parms->stats.cur[i].block_count;
+                               parms->stats.cur[i].block_count = count->uvalue;
+
+                               parms->stats.prev[i].block_error = parms->stats.cur[i].block_error;
+                               parms->stats.cur[i].block_error = error->uvalue;
+
+                               parms->stats.has_per[i] = 1;
+                       }
+               }
+       }
+}
+
 int dvb_fe_get_stats(struct dvb_v5_fe_parms *parms)
 {
        fe_status_t status = 0;
@@ -792,6 +843,10 @@ int dvb_fe_get_stats(struct dvb_v5_fe_parms *parms)
                                break;
                if (i == props.num)
                        goto dvbv3_fallback;
+
+               dvb_fe_update_counters(parms);
+
+               return 0;
        }
 
 dvbv3_fallback: