From: Mauro Carvalho Chehab Date: Tue, 15 Jan 2013 01:25:41 +0000 (-0200) Subject: dvb-fe: add support for DVBv5 stats X-Git-Tag: v4l-utils-0.9.4~91 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=455ac4b16338dbfe992f7ba75c17ebee841e97bd;p=platform%2Fupstream%2Fv4l-utils.git dvb-fe: add support for DVBv5 stats In order to avoid breakage on packages that depend on this library, backward support was preserved. Of course, the backward call dvb_fe_retrieve_stats() won't bring anything new; it will only return what it was provided already by the old API. In order to get full benefit of the new API, the new DVBv5 library call should be used: dvb_fe_retrieve_stats_layer(). Signed-off-by: Mauro Carvalho Chehab --- diff --git a/lib/include/dvb-fe.h b/lib/include/dvb-fe.h index 46615cf..27b9aed 100644 --- a/lib/include/dvb-fe.h +++ b/lib/include/dvb-fe.h @@ -43,12 +43,14 @@ * code to v5 style, if such change gets merged upstream. */ -#define DTV_MAX_STATS 5 -#define DTV_STATUS (DTV_MAX_COMMAND + 100) -#define DTV_BER (DTV_MAX_COMMAND + 101) -#define DTV_SIGNAL_STRENGTH (DTV_MAX_COMMAND + 102) -#define DTV_SNR (DTV_MAX_COMMAND + 103) -#define DTV_UNCORRECTED_BLOCKS (DTV_MAX_COMMAND + 104) +/* + * Those are needed to avoid breaking apps that depend on the library + * but shoudn't be used anymore + */ +#define DTV_MAX_STATS DTV_NUM_STATS_PROPS +#define DTV_SIGNAL_STRENGTH DTV_STAT_SIGNAL_STRENGTH +#define DTV_SNR DTV_STAT_CNR +#define DTV_UNCORRECTED_BLOCKS DTV_STAT_ERROR_BLOCK_COUNT enum dvbv3_emulation_type { DVBV3_UNKNOWN = -1, @@ -59,11 +61,9 @@ enum dvbv3_emulation_type { }; struct dvb_v5_stats { - struct dtv_property prop[DTV_MAX_STATS]; - int valid[DTV_MAX_STATS]; + struct dtv_property prop[DTV_NUM_STATS_PROPS]; }; - struct dvb_v5_fe_parms { int fd; char *fname; @@ -130,6 +130,8 @@ int dvb_fe_get_parms(struct dvb_v5_fe_parms *parms); /* Get statistics */ +struct dtv_stats *dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms *parms, + unsigned cmd, unsigned layer); int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *parms, unsigned cmd, uint32_t *value); int dvb_fe_get_stats(struct dvb_v5_fe_parms *parms); diff --git a/lib/include/dvb-v5-std.h b/lib/include/dvb-v5-std.h index 0b454a1..351ed88 100644 --- a/lib/include/dvb-v5-std.h +++ b/lib/include/dvb-v5-std.h @@ -53,8 +53,18 @@ extern const void *dvb_v5_attr_names[]; #define DTV_DISEQC_WAIT (DTV_USER_COMMAND_START + 7) #define DTV_DISEQC_LNB (DTV_USER_COMMAND_START + 8) #define DTV_FREQ_BPF (DTV_USER_COMMAND_START + 9) + #define DTV_MAX_USER_COMMAND DTV_FREQ_BPF +/* For status and statistics */ + +#define DTV_STATUS (DTV_MAX_USER_COMMAND + 1) +#define DTV_BER (DTV_MAX_USER_COMMAND + 2) + +#define DTV_MAX_STAT_COMMAND DTV_BER + +#define DTV_NUM_STATS_PROPS 8 /* 6 from DVBv5.10 API plus Status and BER */ + enum dvb_sat_polarization { POLARIZATION_OFF = 0, POLARIZATION_H = 1, @@ -64,7 +74,7 @@ enum dvb_sat_polarization { }; extern const char *dvb_sat_pol_name[6]; -extern const char *dvb_user_name[2]; +extern const char *dvb_user_name[13]; extern const void *dvb_user_attr_names[]; #endif diff --git a/lib/libdvbv5/dvb-fe.c b/lib/libdvbv5/dvb-fe.c index e1abe86..ec35922 100644 --- a/lib/libdvbv5/dvb-fe.c +++ b/lib/libdvbv5/dvb-fe.c @@ -199,12 +199,19 @@ struct dvb_v5_fe_parms *dvb_fe_open2(int adapter, int frontend, unsigned verbose /* Prepare to use the delivery system */ dvb_set_sys(parms, parms->current_sys); - /* Prepare the status struct */ - parms->stats.prop[0].cmd = DTV_STATUS; - parms->stats.prop[1].cmd = DTV_BER; - parms->stats.prop[2].cmd = DTV_SIGNAL_STRENGTH; - parms->stats.prop[3].cmd = DTV_SNR; - parms->stats.prop[4].cmd = DTV_UNCORRECTED_BLOCKS; + /* + * Prepare the status struct - DVBv5.10 parameters should + * come first, as they'll be read together. + */ + parms->stats.prop[0].cmd = DTV_STAT_SIGNAL_STRENGTH; + parms->stats.prop[1].cmd = DTV_STAT_CNR; + parms->stats.prop[2].cmd = DTV_STAT_POST_BIT_ERROR_COUNT; + parms->stats.prop[3].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT; + parms->stats.prop[4].cmd = DTV_STAT_ERROR_BLOCK_COUNT; + parms->stats.prop[5].cmd = DTV_STAT_TOTAL_BLOCK_COUNT; + + parms->stats.prop[6].cmd = DTV_STATUS; + parms->stats.prop[7].cmd = DTV_BER; return parms; } @@ -410,7 +417,7 @@ const char *dvb_cmd_name(int cmd) { if (cmd >= 0 && cmd < DTV_USER_COMMAND_START) return dvb_v5_name[cmd]; - else if (cmd >= 0 && cmd <= DTV_MAX_USER_COMMAND) + else if (cmd >= 0 && cmd <= DTV_MAX_STAT_COMMAND) return dvb_user_name[cmd - DTV_USER_COMMAND_START]; return NULL; } @@ -419,7 +426,7 @@ const char *const *dvb_attr_names(int cmd) { if (cmd >= 0 && cmd < DTV_USER_COMMAND_START) return dvb_v5_attr_names[cmd]; - else if (cmd >= 0 && cmd <= DTV_MAX_USER_COMMAND) + else if (cmd >= 0 && cmd <= DTV_MAX_STAT_COMMAND) return dvb_user_attr_names[cmd - DTV_USER_COMMAND_START]; return NULL; } @@ -659,39 +666,68 @@ ret: return 0; } -int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *parms, - unsigned cmd, uint32_t *value) +struct dtv_stats *dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms *parms, + unsigned cmd, unsigned layer) { - int i, valid; - for (i = 0; i < DTV_MAX_STATS; i++) { + int i; + + for (i = 0; i < DTV_NUM_STATS_PROPS; i++) { if (parms->stats.prop[i].cmd != cmd) continue; - *value = parms->stats.prop[i].u.data; - valid = parms->stats.valid[i]; - if (!valid) - return EINVAL; - return 0; + if (layer >= parms->stats.prop[2].u.st.len) + return NULL; + return &parms->stats.prop[i].u.st.stat[layer]; } - dvb_logerr("%s not found on retrieve", - dvb_cmd_name(cmd)); + dvb_logerr("%s not found on retrieve", dvb_cmd_name(cmd)); - return EINVAL; + return NULL; +} + +int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *parms, + unsigned cmd, uint32_t *value) +{ + struct dtv_stats *stat; + enum fecap_scale_params scale; + + stat = dvb_fe_retrieve_stats_layer(parms, cmd, 0); + if (!stat) { + if (parms->verbose) + dvb_logdbg("%s not found on retrieve", dvb_cmd_name(cmd)); + return EINVAL; + } + + scale = stat->scale; + if (scale == FE_SCALE_NOT_AVAILABLE) { + if (parms->verbose) + dvb_logdbg("%s not available", dvb_cmd_name(cmd)); + return EINVAL; + } + + *value = stat->uvalue; + + if (parms->verbose) + dvb_logdbg("Stats for %s = %d", dvb_cmd_name(cmd), *value); + + return 0; } static int dvb_fe_store_stats(struct dvb_v5_fe_parms *parms, - unsigned cmd, uint32_t value, - int valid) + unsigned cmd, + enum fecap_scale_params scale, + unsigned layer, + uint32_t value) { int i; - for (i = 0; i < DTV_MAX_STATS; i++) { + for (i = 0; i < DTV_NUM_STATS_PROPS; i++) { if (parms->stats.prop[i].cmd != cmd) continue; - parms->stats.prop[i].u.data = value; - parms->stats.valid[i] = valid; + parms->stats.prop[i].u.st.stat[layer].scale = scale; + parms->stats.prop[i].u.st.stat[layer].uvalue = value; + if (parms->stats.prop[i].u.st.len < layer + 1) + parms->stats.prop[i].u.st.len = layer + 1; return 0; } - dvb_logerr("%s not found on store", - dvb_cmd_name(cmd)); + dvb_logerr("%s not found on store", dvb_cmd_name(cmd)); return EINVAL; } @@ -701,38 +737,87 @@ int dvb_fe_get_stats(struct dvb_v5_fe_parms *parms) fe_status_t status = 0; uint32_t ber= 0, ucb = 0; uint16_t strength = 0, snr = 0; - int i, valid; + int i; + enum fecap_scale_params scale; if (ioctl(parms->fd, FE_READ_STATUS, &status) == -1) { dvb_perror("FE_READ_STATUS"); return EINVAL; } - dvb_fe_store_stats(parms, DTV_STATUS, status, 1); + dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status); + + if (parms->version >= 0x50a) { + struct dtv_properties props; + struct dtv_stats *st_bec, *st_bc; + + props.num = 6; + props.props = parms->stats.prop; + + /* Do a DVBv5.10 stats call */ + if (ioctl(parms->fd, FE_GET_PROPERTY, &props) == -1) + goto dvbv3_fallback; + + /* If no stats i returned, fallback to the legacy API */ + for (i = 0; i < props.num; i++) + if (parms->stats.prop[i].u.st.len) + break; + if (i == props.num) + goto dvbv3_fallback; + + /* Calculate and store BER */ + for (i = 0; i < 4; i++) { + uint64_t ber64; + + st_bec = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_POST_BIT_ERROR_COUNT, i); + if (!st_bec) + goto no_ber; + + st_bc = dvb_fe_retrieve_stats_layer(parms, DTV_STAT_POST_TOTAL_BIT_COUNT, i); + if (!st_bc || !st_bc->uvalue) + goto no_ber; + + ber64 = (1E9 * st_bec->uvalue) / st_bc->uvalue; + + dvb_fe_store_stats(parms, DTV_BER, FE_SCALE_COUNTER, i, ber64); + continue; +no_ber: + dvb_fe_store_stats(parms, DTV_BER, FE_SCALE_NOT_AVAILABLE, i, 0); + } + + return 0; + } +dvbv3_fallback: + /* DVB v3 stats*/ if (ioctl(parms->fd, FE_READ_BER, &ber) == -1) - valid = 0; + scale = FE_SCALE_NOT_AVAILABLE; else - valid = 1; - dvb_fe_store_stats(parms, DTV_BER, ber, valid); + scale = FE_SCALE_RELATIVE; + + /* + * BER scale on DVBv3 is not defined - different drivers use + * different scales, even weird ones, like multiples of 1/65280 + */ + dvb_fe_store_stats(parms, DTV_BER, scale, 0, ber); if (ioctl(parms->fd, FE_READ_SIGNAL_STRENGTH, &strength) == -1) - valid = 0; + scale = FE_SCALE_NOT_AVAILABLE; else - valid = 1; + scale = FE_SCALE_RELATIVE; - dvb_fe_store_stats(parms, DTV_SIGNAL_STRENGTH, strength, valid); + dvb_fe_store_stats(parms, DTV_STAT_SIGNAL_STRENGTH, scale, 0, strength); if (ioctl(parms->fd, FE_READ_SNR, &snr) == -1) - valid = 0; + scale = FE_SCALE_NOT_AVAILABLE; else - valid = 1; - dvb_fe_store_stats(parms, DTV_SNR, snr, valid); + scale = FE_SCALE_RELATIVE; + dvb_fe_store_stats(parms, DTV_STAT_CNR, scale, 0, snr); if (ioctl(parms->fd, FE_READ_UNCORRECTED_BLOCKS, &ucb) == -1) - valid = 0; + scale = FE_SCALE_NOT_AVAILABLE; else - valid = 1; - dvb_fe_store_stats(parms, DTV_UNCORRECTED_BLOCKS, snr, valid); + scale = FE_SCALE_COUNTER; + dvb_fe_store_stats(parms, DTV_STAT_ERROR_BLOCK_COUNT, scale, 0, snr); if (parms->verbose > 1) { dvb_log("Status: "); @@ -770,7 +855,7 @@ int dvb_fe_get_event(struct dvb_v5_fe_parms *parms) dvb_log (" %s", fe_status_name[i].name); } } - dvb_fe_store_stats(parms, DTV_STATUS, status, 1); + dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status); dvb_fe_retrieve_parm(parms, DTV_FREQUENCY, &event.parameters.frequency); dvb_fe_retrieve_parm(parms, DTV_INVERSION, &event.parameters.inversion); diff --git a/lib/libdvbv5/dvb-file.c b/lib/libdvbv5/dvb-file.c index 31db74c..d8d583c 100644 --- a/lib/libdvbv5/dvb-file.c +++ b/lib/libdvbv5/dvb-file.c @@ -27,26 +27,6 @@ #include "dvb-v5-std.h" #include "dvb-scan.h" -static const char *parm_name(const struct parse_table *table) -{ - if (table->prop < DTV_MAX_COMMAND) - return dvb_v5_name[table->prop]; - switch (table->prop) { - case DTV_CH_NAME: - return ("CHANNEL"); - case DTV_POLARIZATION: - return ("POLARIZATION"); - case DTV_VIDEO_PID: - return ("VIDEO PID"); - case DTV_AUDIO_PID: - return ("AUDIO PID"); - case DTV_SERVICE_ID: - return ("SERVICE ID"); - default: - return ("unknown"); - } -} - /* * Generic parse function for all formats each channel is contained into * just one line. @@ -145,7 +125,7 @@ struct dvb_file *parse_format_oneline(const char *fname, p = strtok(NULL, delimiter); if (!p) { sprintf(err_msg, "parameter %i (%s) missing", - i, parm_name(table)); + i, dvb_cmd_name(table->prop)); goto error; } if (table->size) { @@ -154,7 +134,7 @@ struct dvb_file *parse_format_oneline(const char *fname, break; if (j == table->size) { sprintf(err_msg, "parameter %s invalid: %s", - parm_name(table), p); + dvb_cmd_name(table->prop), p); goto error; } if (table->prop == DTV_BANDWIDTH_HZ) diff --git a/lib/libdvbv5/dvb-v5-std.c b/lib/libdvbv5/dvb-v5-std.c index 7cb23d5..c7101eb 100644 --- a/lib/libdvbv5/dvb-v5-std.c +++ b/lib/libdvbv5/dvb-v5-std.c @@ -221,13 +221,24 @@ const char *dvb_sat_pol_name[6] = { [5] = NULL, }; -const char *dvb_user_name[2] = { - [DTV_POLARIZATION - DTV_USER_COMMAND_START] = "POLARIZATION", - [1] = NULL, +const char *dvb_user_name[13] = { + [DTV_POLARIZATION - DTV_USER_COMMAND_START] = "POLARIZATION", + [DTV_VIDEO_PID - DTV_USER_COMMAND_START] = "VIDEO PID", + [DTV_AUDIO_PID - DTV_USER_COMMAND_START] = "AUDIO PID", + [DTV_SERVICE_ID - DTV_USER_COMMAND_START] = "SERVICE ID", + [DTV_CH_NAME - DTV_USER_COMMAND_START] = "CHANNEL", + [DTV_VCHANNEL - DTV_USER_COMMAND_START] = "VCHANNEL", + [DTV_SAT_NUMBER - DTV_USER_COMMAND_START] = "SAT NUMBER", + [DTV_DISEQC_WAIT - DTV_USER_COMMAND_START] = "DISEQC WAIT", + [DTV_DISEQC_LNB - DTV_USER_COMMAND_START] = "DISEQC LNB", + [DTV_FREQ_BPF - DTV_USER_COMMAND_START] = "FREQ BPF", + [DTV_STATUS - DTV_USER_COMMAND_START] = "STATUS", + [DTV_BER - DTV_USER_COMMAND_START] = "BER", + [12] = NULL, }; const void *dvb_user_attr_names[] = { - [0 ... DTV_MAX_USER_COMMAND - DTV_USER_COMMAND_START] = NULL, + [0 ... DTV_MAX_STAT_COMMAND - DTV_USER_COMMAND_START] = NULL, [DTV_POLARIZATION - DTV_USER_COMMAND_START] = dvb_sat_pol_name, };