Add a few libv4l2rds patches from upstream, which bring libv4l2rds to its
final API / ABI, so that apps build against it won't need a rebuild in the future
This commit is contained in:
parent
6447e7112b
commit
fedd942e6b
49
0001-rds-ctl-fix-percentage-handling.patch
Normal file
49
0001-rds-ctl-fix-percentage-handling.patch
Normal file
@ -0,0 +1,49 @@
|
||||
From 3941ad41dc97bea2a87c3a9e165a251eb551c54f Mon Sep 17 00:00:00 2001
|
||||
From: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
Date: Sun, 2 Jun 2013 13:32:01 +0200
|
||||
Subject: [PATCH 1/6] rds-ctl: fix percentage handling.
|
||||
|
||||
The block_cnt can be 0, and in that case the percentage becomes -nan.
|
||||
Fix this.
|
||||
|
||||
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
---
|
||||
utils/rds-ctl/rds-ctl.cpp | 17 ++++++++++++-----
|
||||
1 file changed, 12 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/utils/rds-ctl/rds-ctl.cpp b/utils/rds-ctl/rds-ctl.cpp
|
||||
index de76d9f..191cfee 100644
|
||||
--- a/utils/rds-ctl/rds-ctl.cpp
|
||||
+++ b/utils/rds-ctl/rds-ctl.cpp
|
||||
@@ -523,16 +523,23 @@ static void print_rds_statistics(const struct v4l2_rds_statistics *statistics)
|
||||
printf("received blocks / received groups: %u / %u\n",
|
||||
statistics->block_cnt, statistics->group_cnt);
|
||||
|
||||
- float block_error_percentage =
|
||||
- ((float)statistics->block_error_cnt / statistics->block_cnt) * 100.0;
|
||||
+ float block_error_percentage = 0;
|
||||
+
|
||||
+ if (statistics->block_cnt)
|
||||
+ block_error_percentage =
|
||||
+ ((float)statistics->block_error_cnt / statistics->block_cnt) * 100.0;
|
||||
printf("block errors / group errors: %u (%3.2f%%) / %u \n",
|
||||
statistics->block_error_cnt,
|
||||
block_error_percentage, statistics->group_error_cnt);
|
||||
- float block_corrected_percentage =
|
||||
- ((float)statistics->block_corrected_cnt / statistics->block_cnt) * 100.0;
|
||||
+
|
||||
+ float block_corrected_percentage = 0;
|
||||
+
|
||||
+ if (statistics->block_cnt)
|
||||
+ block_corrected_percentage = (
|
||||
+ (float)statistics->block_corrected_cnt / statistics->block_cnt) * 100.0;
|
||||
printf("corrected blocks: %u (%3.2f%%)\n",
|
||||
statistics->block_corrected_cnt, block_corrected_percentage);
|
||||
- for(int i=0; i<16; i++)
|
||||
+ for (int i = 0; i < 16; i++)
|
||||
printf("Group %02d: %u\n", i, statistics->group_type_cnt[i]);
|
||||
}
|
||||
|
||||
--
|
||||
1.8.2.1
|
||||
|
||||
614
0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch
Normal file
614
0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch
Normal file
@ -0,0 +1,614 @@
|
||||
From 5d64d74fe49d0af01eea2a85db69669f45043090 Mon Sep 17 00:00:00 2001
|
||||
From: Konke Radlow <koradlow@gmail.com>
|
||||
Date: Tue, 4 Jun 2013 18:15:01 +0000
|
||||
Subject: [PATCH 2/6] libv4l2rds: support RDS-EON and TMC-tuning info
|
||||
|
||||
- added support to decode RDS-EON information
|
||||
- added support to decode RDS-TMC tuning information
|
||||
- fixing compiler warnings due to missing pointer dereferencing
|
||||
|
||||
Signed-off-by: Konke Radlow <koradlow@gmail.com>
|
||||
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
---
|
||||
lib/include/libv4l2rds.h | 79 +++++++++-
|
||||
lib/libv4l2rds/libv4l2rds.c | 363 +++++++++++++++++++++++++++++++++++++++++---
|
||||
2 files changed, 417 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/lib/include/libv4l2rds.h b/lib/include/libv4l2rds.h
|
||||
index 6a6c7f3..e1078de 100644
|
||||
--- a/lib/include/libv4l2rds.h
|
||||
+++ b/lib/include/libv4l2rds.h
|
||||
@@ -37,7 +37,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* used to define the current version (version field) of the v4l2_rds struct */
|
||||
-#define V4L2_RDS_VERSION (1)
|
||||
+#define V4L2_RDS_VERSION (2)
|
||||
|
||||
/* Constants used to define the size of arrays used to store RDS information */
|
||||
#define MAX_ODA_CNT 18 /* there are 16 groups each with type a or b. Of these
|
||||
@@ -50,6 +50,16 @@ extern "C" {
|
||||
* Additional data is limited to 112 bit, and the smallest
|
||||
* optional tuple has a size of 4 bit (4 bit identifier +
|
||||
* 0 bits of data) */
|
||||
+#define MAX_TMC_ALT_STATIONS 32 /* defined by ISO 14819-1:2003, 7.5.3.3 */
|
||||
+#define MAX_TMC_AF_CNT 4 /* limit for the numbers of AFs stored per alternative TMC
|
||||
+ * station. This value is not defined by the standard, but based on observation
|
||||
+ * of real-world RDS-TMC streams. The maximum encountered number of AFs per
|
||||
+ * station during testing was 2 */
|
||||
+#define MAX_EON_CNT 20 /* Maximal number of entries in the EON table (for storing
|
||||
+ * information about other radio stations, broadcasted by the current station).
|
||||
+ * This value is not defined by the standard, but based on observation
|
||||
+ * of real-world RDS-TMC streams. EON doesn't seem to be a widely used feature
|
||||
+ * and the maximum number of EON encountered during testing was 8 */
|
||||
|
||||
/* Define Constants for the possible types of RDS information
|
||||
* used to address the relevant bit in the valid_fields bitmask */
|
||||
@@ -69,7 +79,10 @@ extern "C" {
|
||||
#define V4L2_RDS_LC 0x2000 /* Language Code */
|
||||
#define V4L2_RDS_TMC_SG 0x4000 /* RDS-TMC single group */
|
||||
#define V4L2_RDS_TMC_MG 0x8000 /* RDS-TMC multi group */
|
||||
-#define V4L2_RDS_TMC_SYS 0x10000 /* RDS-TMC system information */
|
||||
+#define V4L2_RDS_TMC_SYS 0x10000 /* RDS-TMC system information */
|
||||
+#define V4L2_RDS_EON 0x20000 /* Enhanced Other Network Info */
|
||||
+#define V4L2_RDS_LSF 0x40000 /* Linkage information */
|
||||
+#define V4L2_RDS_TMC_TUNING 0x80000 /* RDS-TMC tuning information */
|
||||
|
||||
/* Define Constants for the state of the RDS decoding process
|
||||
* used to address the relevant bit in the decode_information bitmask */
|
||||
@@ -84,9 +97,10 @@ extern "C" {
|
||||
#define V4L2_RDS_FLAG_STATIC_PTY 0x08
|
||||
|
||||
/* TMC related codes
|
||||
- * used to extract TMC fields from RDS groups */
|
||||
-#define V4L2_TMC_TUNING_INFO 0x08
|
||||
-#define V4L2_TMC_SINGLE_GROUP 0x04
|
||||
+ * used to extract TMC fields from RDS-TMC groups
|
||||
+ * see ISO 14819-1:2003, Figure 2 - RDS-TMC single-grp full message structure */
|
||||
+#define V4L2_TMC_TUNING_INFO 0x10 /* Bit 4 indicates Tuning Info / User msg */
|
||||
+#define V4L2_TMC_SINGLE_GROUP 0x08 /* Bit 3 indicates Single / Multi-group msg */
|
||||
|
||||
/* struct to encapsulate one complete RDS group */
|
||||
/* This structure is used internally to store data until a complete RDS
|
||||
@@ -149,6 +163,57 @@ struct v4l2_rds_af_set {
|
||||
uint32_t af[MAX_AF_CNT]; /* AFs defined in Hz */
|
||||
};
|
||||
|
||||
+/* struct to encapsulate one entry in the EON table (Enhanced Other Network) */
|
||||
+struct v4l2_rds_eon {
|
||||
+ uint32_t valid_fields;
|
||||
+ uint16_t pi;
|
||||
+ uint8_t ps[9];
|
||||
+ uint8_t pty;
|
||||
+ bool ta;
|
||||
+ bool tp;
|
||||
+ uint16_t lsf; /* Linkage Set Number */
|
||||
+ struct v4l2_rds_af_set af;
|
||||
+};
|
||||
+
|
||||
+/* struct to encapsulate a table of EON information */
|
||||
+struct v4l2_rds_eon_set {
|
||||
+ uint8_t size; /* size of the table */
|
||||
+ uint8_t index; /* current position in the table */
|
||||
+ struct v4l2_rds_eon eon[MAX_EON_CNT]; /* Information about other
|
||||
+ * radio channels */
|
||||
+};
|
||||
+
|
||||
+/* struct to encapsulate alternative frequencies (AFs) for RDS-TMC stations.
|
||||
+ * AFs listed in af[] can be used unconditionally.
|
||||
+ * AFs listed in mapped_af[n] should only be used if the current
|
||||
+ * tuner frequency matches the value in mapped_af_tuning[n] */
|
||||
+struct v4l2_tmc_alt_freq {
|
||||
+ uint8_t af_size; /* number of known AFs */
|
||||
+ uint8_t af_index;
|
||||
+ uint8_t mapped_af_size; /* number of mapped AFs */
|
||||
+ uint8_t mapped_af_index;
|
||||
+ uint32_t af[MAX_TMC_AF_CNT]; /* AFs defined in Hz */
|
||||
+ uint32_t mapped_af[MAX_TMC_AF_CNT]; /* mapped AFs defined in Hz */
|
||||
+ uint32_t mapped_af_tuning[MAX_TMC_AF_CNT]; /* mapped AFs defined in Hz */
|
||||
+};
|
||||
+
|
||||
+/* struct to encapsulate information about stations carrying RDS-TMC services */
|
||||
+struct v4l2_tmc_station {
|
||||
+ uint16_t pi;
|
||||
+ uint8_t ltn; /* database-ID of ON */
|
||||
+ uint8_t msg; /* msg parameters of ON */
|
||||
+ uint8_t sid; /* service-ID of ON */
|
||||
+ struct v4l2_tmc_alt_freq afi;
|
||||
+};
|
||||
+
|
||||
+/* struct to encapsulate tuning information for TMC */
|
||||
+struct v4l2_tmc_tuning {
|
||||
+ uint8_t station_cnt; /* number of announced alternative stations */
|
||||
+ uint8_t index;
|
||||
+ struct v4l2_tmc_station station[MAX_TMC_ALT_STATIONS]; /* information
|
||||
+ * about other stations carrying the same RDS-TMC service */
|
||||
+};
|
||||
+
|
||||
/* struct to encapsulate an additional data field in a TMC message */
|
||||
struct v4l2_tmc_additional {
|
||||
uint8_t label;
|
||||
@@ -199,6 +264,9 @@ struct v4l2_rds_tmc {
|
||||
uint8_t t_d; /* delay time (only if mode = enhanced */
|
||||
uint8_t spn[9]; /* service provider name */
|
||||
struct v4l2_rds_tmc_msg tmc_msg;
|
||||
+
|
||||
+ /* tuning information for alternative service providers */
|
||||
+ struct v4l2_tmc_tuning tuning;
|
||||
};
|
||||
|
||||
/* struct to encapsulate state and RDS information for current decoding process */
|
||||
@@ -236,6 +304,7 @@ struct v4l2_rds {
|
||||
struct v4l2_rds_statistics rds_statistics;
|
||||
struct v4l2_rds_oda_set rds_oda; /* Open Data Services */
|
||||
struct v4l2_rds_af_set rds_af; /* Alternative Frequencies */
|
||||
+ struct v4l2_rds_eon_set rds_eon; /* EON information */
|
||||
struct v4l2_rds_tmc tmc; /* TMC information */
|
||||
};
|
||||
|
||||
diff --git a/lib/libv4l2rds/libv4l2rds.c b/lib/libv4l2rds/libv4l2rds.c
|
||||
index 2918061..28b78ce 100644
|
||||
--- a/lib/libv4l2rds/libv4l2rds.c
|
||||
+++ b/lib/libv4l2rds/libv4l2rds.c
|
||||
@@ -92,6 +92,11 @@ enum rds_state {
|
||||
RDS_C_RECEIVED,
|
||||
};
|
||||
|
||||
+/* function declarations to prevent the need to move large code blocks */
|
||||
+static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi);
|
||||
+static uint32_t rds_decode_af(uint8_t af, bool is_vhf);
|
||||
+static bool rds_add_tmc_af(struct rds_private_state *priv_state);
|
||||
+
|
||||
static inline uint8_t set_bit(uint8_t input, uint8_t bitmask, bool bitvalue)
|
||||
{
|
||||
return bitvalue ? input | bitmask : input & ~bitmask;
|
||||
@@ -368,7 +373,7 @@ static uint32_t rds_decode_tmc_multi_group(struct rds_private_state *priv_state)
|
||||
/* bit 15 of block 3 is the first group indicator */
|
||||
if (grp->data_c_msb & 0x80) {
|
||||
/* begine decoding of new message */
|
||||
- memset(msg, 0, sizeof(msg));
|
||||
+ memset(msg, 0, sizeof(*msg));
|
||||
memset(priv_state->optional_tmc, 0, 112*sizeof(bool));
|
||||
/* bits 0-3 of block 2 contain continuity index */
|
||||
priv_state->continuity_id = grp->data_b_lsb & 0x07;
|
||||
@@ -434,6 +439,60 @@ static uint32_t rds_decode_tmc_multi_group(struct rds_private_state *priv_state)
|
||||
return V4L2_RDS_TMC_MG;
|
||||
}
|
||||
|
||||
+/* decode the RDS-TMC tuning information that is contained in type 8A groups
|
||||
+ * (variants 4 to 9) that announce the presence alternative transmitters
|
||||
+ * providing the same RDS-TMC service */
|
||||
+static uint32_t rds_decode_tmc_tuning(struct rds_private_state *priv_state)
|
||||
+{
|
||||
+ struct v4l2_rds_group *group = &priv_state->rds_group;
|
||||
+ struct v4l2_rds_tmc *tmc = &priv_state->handle.tmc;
|
||||
+ uint8_t variant_code = group->data_b_lsb & 0x0f;
|
||||
+ uint16_t pi_on = (group->data_d_msb << 8) | group->data_d_lsb;
|
||||
+ uint8_t index;
|
||||
+
|
||||
+ /* variants 4 and 5 carry the service provider name */
|
||||
+ if (variant_code >= 4 && variant_code <= 5) {
|
||||
+ int offset = 4 * (variant_code - 4);
|
||||
+ tmc->spn[0 + offset] = group->data_c_msb;
|
||||
+ tmc->spn[1 + offset] = group->data_c_lsb;
|
||||
+ tmc->spn[2 + offset] = group->data_d_msb;
|
||||
+ tmc->spn[3 + offset] = group->data_d_lsb;
|
||||
+
|
||||
+ /* variant 6 provides specific frequencies for the same RDS-TMC service
|
||||
+ * on a network with a different PI code */
|
||||
+ /* variant 7 provides mapped frequency pair information which should only
|
||||
+ * be used if the terminal is tuned to the tuning frequency */
|
||||
+ } else if (variant_code == 6 || variant_code == 7) {
|
||||
+ rds_add_tmc_af(priv_state);
|
||||
+
|
||||
+ /* variant 8 indicates up to 2 PI codes of adjacent networks carrying
|
||||
+ * the same RDS-TMC service on all transmitters of the network */
|
||||
+ } else if (variant_code == 8) {
|
||||
+ uint16_t pi_on_2 = (group->data_c_msb << 8) | group->data_c_lsb;
|
||||
+
|
||||
+ /* try to add both transmitted PI codes to the table */
|
||||
+ rds_add_tmc_station(priv_state, pi_on);
|
||||
+ /* PI = 0 is used as a filler code */
|
||||
+ if (pi_on_2 != 0)
|
||||
+ rds_add_tmc_station(priv_state, pi_on_2);
|
||||
+
|
||||
+ /* variant 9 provides PI codes of other networks with different system
|
||||
+ * parameters */
|
||||
+ } else if (variant_code == 9) {
|
||||
+ index = rds_add_tmc_station(priv_state, pi_on);
|
||||
+
|
||||
+ /* bits 0 - 5 contain the service-ID of the ON */
|
||||
+ tmc->tuning.station[index].sid = group->data_c_lsb & 0x3F;
|
||||
+ /* bits 6-10 contain the msg parameters of the ON */
|
||||
+ tmc->tuning.station[index].msg = (group->data_c_msb & 0x03) << 2;
|
||||
+ tmc->tuning.station[index].msg |= (group->data_c_lsb >> 6) & 0x03;
|
||||
+ /* bits 11-15 contain the database-ID of the ON */
|
||||
+ tmc->tuning.station[index].ltn = group->data_c_msb >> 2;
|
||||
+ }
|
||||
+
|
||||
+ return V4L2_RDS_TMC_TUNING;
|
||||
+}
|
||||
+
|
||||
static bool rds_add_oda(struct rds_private_state *priv_state, struct v4l2_rds_oda oda)
|
||||
{
|
||||
struct v4l2_rds *handle = &priv_state->handle;
|
||||
@@ -455,20 +514,11 @@ static bool rds_add_oda(struct rds_private_state *priv_state, struct v4l2_rds_od
|
||||
/* add a new AF to the list, if it doesn't exist yet */
|
||||
static bool rds_add_af_to_list(struct v4l2_rds_af_set *af_set, uint8_t af, bool is_vhf)
|
||||
{
|
||||
- uint32_t freq = 0;
|
||||
-
|
||||
- /* AF0 -> "Not to be used" */
|
||||
- if (af == 0)
|
||||
+ /* convert the frequency to Hz, skip on errors */
|
||||
+ uint32_t freq = rds_decode_af(af, is_vhf);
|
||||
+ if (freq == 0)
|
||||
return false;
|
||||
|
||||
- /* calculate the AF values in HZ */
|
||||
- if (is_vhf)
|
||||
- freq = 87500000 + af * 100000;
|
||||
- else if (freq <= 15)
|
||||
- freq = 152000 + af * 9000;
|
||||
- else
|
||||
- freq = 531000 + af * 9000;
|
||||
-
|
||||
/* prevent buffer overflows */
|
||||
if (af_set->size >= MAX_AF_CNT || af_set->size >= af_set->announced_af)
|
||||
return false;
|
||||
@@ -505,7 +555,7 @@ static bool rds_add_af(struct rds_private_state *priv_state)
|
||||
updated_af = true;
|
||||
c_lsb = 0; /* invalidate */
|
||||
}
|
||||
- /* 224..249: announcement of AF count (224=0, 249=25)*/
|
||||
+ /* 224..249: announcement of AF count (224=0, 249=25) */
|
||||
if (c_msb >= 224 && c_msb <= 249)
|
||||
af_set->announced_af = c_msb - 224;
|
||||
/* check if the data represents an AF (for 1 =< val <= 204 the
|
||||
@@ -522,6 +572,103 @@ static bool rds_add_af(struct rds_private_state *priv_state)
|
||||
return updated_af;
|
||||
}
|
||||
|
||||
+/* checks if an entry for the given PI already exists and returns the index
|
||||
+ * of that entry if so. Else it adds a new entry to the TMC-Tuning table and returns
|
||||
+ * the index of the new field */
|
||||
+static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi)
|
||||
+{
|
||||
+ struct v4l2_tmc_tuning *tuning = &priv_state->handle.tmc.tuning;
|
||||
+ uint8_t index = tuning->index;
|
||||
+ uint8_t size = tuning->station_cnt;
|
||||
+
|
||||
+ /* check if there's an entry for the given PI key */
|
||||
+ for (int i = 0; i < tuning->station_cnt; i++) {
|
||||
+ if (tuning->station[i].pi == pi) {
|
||||
+ return i;
|
||||
+ }
|
||||
+ }
|
||||
+ /* if the the maximum table size is reached, overwrite old
|
||||
+ * entries, starting at the oldest one = 0 */
|
||||
+ tuning->station[index].pi = pi;
|
||||
+ tuning->index = (index+1 < MAX_TMC_ALT_STATIONS) ? (index+1) : 0;
|
||||
+ tuning->station_cnt = (size+1 <= MAX_TMC_ALT_STATIONS) ? (size+1) : MAX_TMC_ALT_STATIONS;
|
||||
+ return index;
|
||||
+}
|
||||
+
|
||||
+/* tries to add new AFs to the relevant entry in the list of RDS-TMC providers */
|
||||
+static bool rds_add_tmc_af(struct rds_private_state *priv_state)
|
||||
+{
|
||||
+ struct v4l2_rds_group *grp = &priv_state->rds_group;
|
||||
+ struct v4l2_tmc_alt_freq *afi;
|
||||
+ uint16_t pi_on = grp->data_d_msb << 8 | grp->data_d_lsb;
|
||||
+ uint8_t variant = grp->data_b_lsb & 0x0f;
|
||||
+ uint8_t station_index = rds_add_tmc_station(priv_state, pi_on);
|
||||
+ uint8_t af_index;
|
||||
+ uint8_t mapped_af_index;
|
||||
+ uint32_t freq_a = rds_decode_af(grp->data_c_msb, true);
|
||||
+ uint32_t freq_b = rds_decode_af(grp->data_c_lsb, true);
|
||||
+
|
||||
+ afi = &priv_state->handle.tmc.tuning.station[station_index].afi;
|
||||
+ af_index = afi->af_index;
|
||||
+ mapped_af_index = afi->mapped_af_index;
|
||||
+
|
||||
+ /* specific frequencies */
|
||||
+ if (variant == 6) {
|
||||
+ /* compare the new AFs to the stored ones, reset them to 0 if the AFs are
|
||||
+ * already known */
|
||||
+ for (int i = 0; i < afi->af_size; i++) {
|
||||
+ freq_a = (freq_a == afi->af[i]) ? 0 : freq_a;
|
||||
+ freq_b = (freq_b == afi->af[i]) ? 0 : freq_b;
|
||||
+ }
|
||||
+ /* return early if there is nothing to do */
|
||||
+ if (freq_a == 0 && freq_b == 0)
|
||||
+ return false;
|
||||
+
|
||||
+ /* add the new AFs if they were previously unknown */
|
||||
+ if (freq_a != 0) {
|
||||
+ afi->af[af_index] = freq_a;
|
||||
+ af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
|
||||
+ afi->af_size++;
|
||||
+ }
|
||||
+ if (freq_b != 0) {
|
||||
+ afi->af[af_index] = freq_b;
|
||||
+ af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
|
||||
+ afi->af_size++;
|
||||
+ }
|
||||
+ /* update the information in the handle */
|
||||
+ afi->af_index = af_index;
|
||||
+ if (afi->af_size >= MAX_TMC_AF_CNT)
|
||||
+ afi->af_size = MAX_TMC_AF_CNT;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ /* mapped frequency pair */
|
||||
+ else if (variant == 7) {
|
||||
+ /* check the if there's already a frequency mapped to the new tuning
|
||||
+ * frequency, update the mapped frequency in this case */
|
||||
+ for (int i = 0; i < afi->mapped_af_size; i++) {
|
||||
+ if (freq_a == afi->mapped_af_tuning[i])
|
||||
+ afi->mapped_af[i] = freq_b;
|
||||
+ return true;
|
||||
+ }
|
||||
+ /* new pair is unknown, add it to the list */
|
||||
+ if (freq_a != 0 && freq_b != 0) {
|
||||
+ mapped_af_index = (mapped_af_index+1 >= MAX_TMC_AF_CNT) ? 0 : mapped_af_index + 1;
|
||||
+ afi->mapped_af[mapped_af_index] = freq_b;
|
||||
+ afi->mapped_af_tuning[mapped_af_index] = freq_a;
|
||||
+ afi->mapped_af_size++;
|
||||
+ }
|
||||
+ /* update the information in the handle */
|
||||
+ afi->mapped_af_index = mapped_af_index;
|
||||
+ if (afi->mapped_af_size >= MAX_TMC_AF_CNT)
|
||||
+ afi->mapped_af_size = MAX_TMC_AF_CNT;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/* adds one char of the ps name to temporal storage, the value is validated
|
||||
* if it is received twice in a row
|
||||
* @pos: position of the char within the PS name (0..7)
|
||||
@@ -543,6 +690,44 @@ static bool rds_add_ps(struct rds_private_state *priv_state, uint8_t pos, uint8_
|
||||
return true;
|
||||
}
|
||||
|
||||
+/* checks if an entry for the given PI already exists and returns the index
|
||||
+ * of that entry if so. Else it adds a new entry to the EON table and returns
|
||||
+ * the index of the new field */
|
||||
+static uint8_t rds_add_eon_entry(struct rds_private_state *priv_state, uint16_t pi)
|
||||
+{
|
||||
+ struct v4l2_rds *handle = &priv_state->handle;
|
||||
+ uint8_t index = handle->rds_eon.index;
|
||||
+ uint8_t size = handle->rds_eon.size;
|
||||
+
|
||||
+ /* check if there's an entry for the given PI key */
|
||||
+ for (int i = 0; i < handle->rds_eon.size; i++) {
|
||||
+ if (handle->rds_eon.eon[i].pi == pi) {
|
||||
+ return i;
|
||||
+ }
|
||||
+ }
|
||||
+ /* if the the maximum table size is reached, overwrite old
|
||||
+ * entries, starting at the oldest one = 0 */
|
||||
+ handle->rds_eon.eon[index].pi = pi;
|
||||
+ handle->rds_eon.eon[index].valid_fields |= V4L2_RDS_PI;
|
||||
+ handle->rds_eon.index = (index+1 < MAX_EON_CNT) ? (index+1) : 0;
|
||||
+ handle->rds_eon.size = (size+1 <= MAX_EON_CNT) ? (size+1) : MAX_EON_CNT;
|
||||
+ return index;
|
||||
+}
|
||||
+
|
||||
+/* checks if an entry for the given PI already exists */
|
||||
+static bool rds_check_eon_entry(struct rds_private_state *priv_state, uint16_t pi)
|
||||
+{
|
||||
+ struct v4l2_rds *handle = &priv_state->handle;
|
||||
+
|
||||
+ /* check if there's an entry for the given PI key */
|
||||
+ for (int i = 0; i <= handle->rds_eon.size; i++) {
|
||||
+ if (handle->rds_eon.eon[i].pi == pi) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/* group of functions to decode successfully received RDS groups into
|
||||
* easily accessible data fields
|
||||
*
|
||||
@@ -790,6 +975,29 @@ static uint32_t rds_decode_group3(struct rds_private_state *priv_state)
|
||||
return updated_fields;
|
||||
}
|
||||
|
||||
+/* decodes the RDS radio frequency representation into Hz
|
||||
+ * @af: 8-bit AF value as transmitted in RDS groups
|
||||
+ * @is_vhf: boolean value defining which conversion table to use
|
||||
+ * @return: frequency in Hz, 0 in case of wrong input values */
|
||||
+static uint32_t rds_decode_af(uint8_t af, bool is_vhf) {
|
||||
+ uint32_t freq = 0;
|
||||
+
|
||||
+ /* AF = 0 => "not to be used"
|
||||
+ * AF >= 205 => special meanings */
|
||||
+ if (af == 0 || af >= 205)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* calculate the AF values in HZ */
|
||||
+ if (is_vhf)
|
||||
+ freq = 87500000 + af * 100000;
|
||||
+ else if (freq <= 15)
|
||||
+ freq = 152000 + af * 9000;
|
||||
+ else
|
||||
+ freq = 531000 + af * 9000;
|
||||
+
|
||||
+ return freq;
|
||||
+}
|
||||
+
|
||||
/* decodes the RDS date/time representation into a standard c representation
|
||||
* that can be used with c-library functions */
|
||||
static time_t rds_decode_mjd(const struct rds_private_state *priv_state)
|
||||
@@ -880,7 +1088,6 @@ static uint32_t rds_decode_group4(struct rds_private_state *priv_state)
|
||||
handle->time = rds_decode_mjd(priv_state);
|
||||
updated_fields |= V4L2_RDS_TIME;
|
||||
handle->valid_fields |= V4L2_RDS_TIME;
|
||||
- printf("\nLIB: time_t: %ld", handle->time);
|
||||
return updated_fields;
|
||||
}
|
||||
|
||||
@@ -916,13 +1123,13 @@ static uint32_t rds_decode_group8(struct rds_private_state *priv_state)
|
||||
!(grp->data_b_lsb & V4L2_TMC_TUNING_INFO)) {
|
||||
return rds_decode_tmc_multi_group(priv_state);
|
||||
}
|
||||
- /* -> tuning information message, defined for variants 4..9, submitted
|
||||
- * in bits 0-3 of block 2 */
|
||||
+ /* -> tuning information message, defined for variants 4..9,
|
||||
+ * submitted in bits 0-3 of block 2 */
|
||||
tuning_variant = grp->data_b_lsb & 0x0f;
|
||||
if ((grp->data_b_lsb & V4L2_TMC_TUNING_INFO) && tuning_variant >= 4 &&
|
||||
tuning_variant <= 9) {
|
||||
- /* TODO: Implement tuning information decoding */
|
||||
- return 0;
|
||||
+ priv_state->handle.valid_fields |= V4L2_RDS_TMC_TUNING;
|
||||
+ return rds_decode_tmc_tuning(priv_state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -981,6 +1188,121 @@ static uint32_t rds_decode_group10(struct rds_private_state *priv_state)
|
||||
return updated_fields;
|
||||
}
|
||||
|
||||
+/* group 14: EON (Enhanced Other Network) information */
|
||||
+static uint32_t rds_decode_group14(struct rds_private_state* priv_state)
|
||||
+{
|
||||
+ struct v4l2_rds *handle = &priv_state->handle;
|
||||
+ struct v4l2_rds_group *grp = &priv_state->rds_group;
|
||||
+ struct v4l2_rds_eon *eon_entry;
|
||||
+ uint32_t updated_fields = 0;
|
||||
+ uint16_t pi_on;
|
||||
+ uint16_t lsf_on;
|
||||
+ uint8_t variant_code;
|
||||
+ uint8_t eon_index;
|
||||
+ uint8_t pty_on;
|
||||
+ bool tp_on, ta_on;
|
||||
+ bool new_a = false, new_b = false;
|
||||
+
|
||||
+ if (grp->group_version != 'A')
|
||||
+ return 0;
|
||||
+
|
||||
+ /* bits 0-3 of group b contain the variant code */
|
||||
+ variant_code = grp->data_b_lsb & 0x0f;
|
||||
+
|
||||
+ /* group d contains the PI code of the ON (Other Network) */
|
||||
+ pi_on = (grp->data_d_msb << 8) | grp->data_d_lsb;
|
||||
+
|
||||
+ /* bit 4 of group b contains the TP status of the ON*/
|
||||
+ tp_on = grp->data_b_lsb & 0x10;
|
||||
+ if (rds_check_eon_entry(priv_state, pi_on)) {
|
||||
+ /* if there's an entry for this PI(ON) update the TP field */
|
||||
+ eon_index = rds_add_eon_entry(priv_state, pi_on);
|
||||
+ eon_entry = &handle->rds_eon.eon[eon_index];
|
||||
+ eon_entry->tp = tp_on;
|
||||
+ eon_entry->valid_fields |= V4L2_RDS_TP;
|
||||
+ updated_fields |= V4L2_RDS_EON;
|
||||
+ }
|
||||
+
|
||||
+ /* perform group variant dependent decoding */
|
||||
+ if ((variant_code >=5 && variant_code <= 11) || variant_code >= 14) {
|
||||
+ /* 5-9 = mapped FM frequencies -> unsupported
|
||||
+ * 10-11 = unallocated
|
||||
+ * 14 = PIN(ON) -> unsupported (unused RDS feature)
|
||||
+ * 15 = reserved for broadcasters use */
|
||||
+ return updated_fields;
|
||||
+ }
|
||||
+
|
||||
+ /* retrieve the EON entry corresponding to the PI(ON) code or add a new
|
||||
+ * entry to the table if no entry exists */
|
||||
+ eon_index = rds_add_eon_entry(priv_state, pi_on);
|
||||
+ eon_entry = &handle->rds_eon.eon[eon_index];
|
||||
+
|
||||
+ /* PS Name */
|
||||
+ if (variant_code < 4) {
|
||||
+ eon_entry->ps[variant_code*2] = grp->data_c_msb;
|
||||
+ eon_entry->ps[variant_code*2+1] = grp->data_c_lsb;
|
||||
+ eon_entry->valid_fields |= V4L2_RDS_PS;
|
||||
+ updated_fields |= V4L2_RDS_EON;
|
||||
+ }
|
||||
+ /* Alternative frequencies */
|
||||
+ else if (variant_code == 4) {
|
||||
+ uint8_t c_msb = grp->data_c_msb;
|
||||
+ uint8_t c_lsb = grp->data_c_lsb;
|
||||
+
|
||||
+ /* 224..249: announcement of AF count (224=0, 249=25) */
|
||||
+ if (c_msb >= 224 && c_msb <= 249)
|
||||
+ eon_entry->af.announced_af = c_msb - 224;
|
||||
+ /* check if the data represents an AF (for 1 =< val <= 204 the
|
||||
+ * value represents an AF) */
|
||||
+ if (c_msb < 205)
|
||||
+ new_a = rds_add_af_to_list(&eon_entry->af,
|
||||
+ grp->data_c_msb, true);
|
||||
+ if (c_lsb < 205)
|
||||
+ new_b = rds_add_af_to_list(&eon_entry->af,
|
||||
+ grp->data_c_lsb, true);
|
||||
+ /* check if one of the frequencies was previously unknown */
|
||||
+ if (new_a || new_b) {
|
||||
+ eon_entry->valid_fields |= V4L2_RDS_AF;
|
||||
+ updated_fields |= V4L2_RDS_EON;
|
||||
+ }
|
||||
+ }
|
||||
+ /* Linkage information */
|
||||
+ else if (variant_code == 12) {
|
||||
+ /* group c contains the lsf code */
|
||||
+ lsf_on = (grp->data_c_msb << 8) | grp->data_c_lsb;
|
||||
+ /* check if the lsf code is already known */
|
||||
+ new_a = (eon_entry->lsf == lsf_on);
|
||||
+ if (new_a) {
|
||||
+ eon_entry->lsf = lsf_on;
|
||||
+ eon_entry->valid_fields |= V4L2_RDS_LSF;
|
||||
+ updated_fields |= V4L2_RDS_EON;
|
||||
+ }
|
||||
+ }
|
||||
+ /* PTY(ON) and TA(ON) */
|
||||
+ else if (variant_code == 13) {
|
||||
+ /* bits 15-10 of group c contain the PTY(ON) */
|
||||
+ pty_on = grp->data_c_msb >> 3;
|
||||
+ /* bit 0 of group c contains the TA code */
|
||||
+ ta_on = grp->data_c_lsb & 0x01;
|
||||
+ /* check if the data is new */
|
||||
+ new_a = (eon_entry->pty == pty_on);
|
||||
+ if (new_a) {
|
||||
+ eon_entry->pty = pty_on;
|
||||
+ eon_entry->valid_fields |= V4L2_RDS_PTY;
|
||||
+ }
|
||||
+ new_b = (eon_entry->ta == ta_on);
|
||||
+ eon_entry->ta = ta_on;
|
||||
+ eon_entry->valid_fields |= V4L2_RDS_TA;
|
||||
+ if (new_a || new_b)
|
||||
+ updated_fields |= V4L2_RDS_EON;
|
||||
+ }
|
||||
+ /* set valid field for EON data, if EON table contains entries */
|
||||
+ if (handle->rds_eon.size > 0)
|
||||
+ handle->valid_fields |= V4L2_RDS_EON;
|
||||
+
|
||||
+ return updated_fields;
|
||||
+}
|
||||
+
|
||||
typedef uint32_t (*decode_group_func)(struct rds_private_state *);
|
||||
|
||||
/* array of function pointers to contain all group specific decoding functions */
|
||||
@@ -992,6 +1314,7 @@ static const decode_group_func decode_group[16] = {
|
||||
[4] = rds_decode_group4,
|
||||
[8] = rds_decode_group8,
|
||||
[10] = rds_decode_group10,
|
||||
+ [14] = rds_decode_group14
|
||||
};
|
||||
|
||||
static uint32_t rds_decode_group(struct rds_private_state *priv_state)
|
||||
@@ -1068,7 +1391,7 @@ uint32_t v4l2_rds_add(struct v4l2_rds *handle, struct v4l2_rds_data *rds_data)
|
||||
if (block_id == 0) {
|
||||
*decode_state = RDS_A_RECEIVED;
|
||||
/* begin reception of a new data group, reset raw buffer to 0 */
|
||||
- memset(rds_data_raw, 0, sizeof(rds_data_raw));
|
||||
+ memset(rds_data_raw, 0, sizeof(*rds_data_raw));
|
||||
rds_data_raw[0] = *rds_data;
|
||||
} else {
|
||||
/* ignore block if it is not the first block of a group */
|
||||
--
|
||||
1.8.2.1
|
||||
|
||||
124
0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch
Normal file
124
0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch
Normal file
@ -0,0 +1,124 @@
|
||||
From d588da4738609a921a77745ea4577f543444be48 Mon Sep 17 00:00:00 2001
|
||||
From: Konke Radlow <koradlow@gmail.com>
|
||||
Date: Tue, 4 Jun 2013 18:15:02 +0000
|
||||
Subject: [PATCH 3/6] rds-ctl: support RDS-EON and TMC-tuning info
|
||||
|
||||
- added functionality to print RDS-EON information
|
||||
- added functionality to print RDS-TMC tuning information
|
||||
- clarify option description, change
|
||||
trigger condition for printing TMC Tuning information
|
||||
|
||||
Signed-off-by: Konke Radlow <koradlow@gmail.com>
|
||||
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
---
|
||||
utils/rds-ctl/rds-ctl.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 57 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/utils/rds-ctl/rds-ctl.cpp b/utils/rds-ctl/rds-ctl.cpp
|
||||
index 191cfee..d894ec1 100644
|
||||
--- a/utils/rds-ctl/rds-ctl.cpp
|
||||
+++ b/utils/rds-ctl/rds-ctl.cpp
|
||||
@@ -130,7 +130,7 @@ static void usage_hint(void)
|
||||
static void usage_common(void)
|
||||
{
|
||||
printf("\nGeneral/Common options:\n"
|
||||
- " --all display all information available\n"
|
||||
+ " --all display all device information available\n"
|
||||
" -D, --info show driver info [VIDIOC_QUERYCAP]\n"
|
||||
" -d, --device=<dev> use device <dev>\n"
|
||||
" if <dev> is a single digit, then /dev/radio<dev> is used\n"
|
||||
@@ -172,7 +172,7 @@ static void usage_rds(void)
|
||||
" <default>: 5000 ms\n"
|
||||
" --print-block prints all valid RDS fields, whenever a value is updated\n"
|
||||
" instead of printing only updated values\n"
|
||||
- " --tmc enables decoding of TMC (Traffic Message Channel) data\n"
|
||||
+ " --tmc print information about TMC (Traffic Message Channel) messages\n"
|
||||
" --silent only set the result code, do not print any messages\n"
|
||||
" --verbose turn on verbose mode - every received RDS group\n"
|
||||
" will be printed\n"
|
||||
@@ -517,6 +517,30 @@ static void print_rds_tmc(const struct v4l2_rds *handle, uint32_t updated_fields
|
||||
}
|
||||
}
|
||||
|
||||
+static void print_rds_tmc_tuning(const struct v4l2_rds *handle, uint32_t updated_fields)
|
||||
+{
|
||||
+ const struct v4l2_tmc_tuning *tuning = &handle->tmc.tuning;
|
||||
+ const struct v4l2_tmc_station *station;
|
||||
+
|
||||
+ if (updated_fields & V4L2_RDS_TMC_TUNING) {
|
||||
+ printf("\nTMC Service provider: %s, %u alternative stations\n", handle->tmc.spn, tuning->station_cnt);
|
||||
+ for (int i = 0; i < tuning->station_cnt; i++) {
|
||||
+ station = &tuning->station[i];
|
||||
+ printf("PI(ON %02u) = %04x, AFs: %u, mapped AFs: %u \n", i, station->pi,
|
||||
+ station->afi.af_size, station->afi.mapped_af_size);
|
||||
+ for (int j = 0; j < station->afi.af_size; j++)
|
||||
+ printf(" AF%02d: %.1fMHz\n", j, station->afi.af[j] / 1000000.0);
|
||||
+ for (int k = 0; k < station->afi.mapped_af_size; k++)
|
||||
+ printf(" m_AF%02d: %.1fMHz => %.1fMHz\n", k,
|
||||
+ station->afi.mapped_af_tuning[k] / 1000000.0,
|
||||
+ station->afi.mapped_af[k] / 1000000.0);
|
||||
+ if (station->ltn != 0 || station->msg != 0 || station-> sid != 0)
|
||||
+ printf(" ltn: %02x, msg: %02x, sid: %02x\n", station->ltn,
|
||||
+ station->msg, station->sid);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void print_rds_statistics(const struct v4l2_rds_statistics *statistics)
|
||||
{
|
||||
printf("\n\nRDS Statistics: \n");
|
||||
@@ -557,6 +581,33 @@ static void print_rds_af(const struct v4l2_rds_af_set *af_set)
|
||||
}
|
||||
}
|
||||
|
||||
+static void print_rds_eon(const struct v4l2_rds_eon_set *eon_set)
|
||||
+{
|
||||
+ int counter = 0;
|
||||
+
|
||||
+ printf("\n\nEnhanced Other Network information: %u channels", eon_set->size);
|
||||
+ for (int i = 0; i < eon_set->size; i++, counter++) {
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_PI)
|
||||
+ printf("\nPI(ON %02i) = %04x", i, eon_set->eon[i].pi);
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_PS)
|
||||
+ printf("\nPS(ON %02i) = %s", i, eon_set->eon[i].ps);
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_PTY)
|
||||
+ printf("\nPTY(ON %02i) = %0u", i, eon_set->eon[i].pty);
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_LSF)
|
||||
+ printf("\nLSF(ON %02i) = %0u", i, eon_set->eon[i].lsf);
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_AF)
|
||||
+ printf("\nPTY(ON %02i) = %0u", i, eon_set->eon[i].pty);
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_TP)
|
||||
+ printf("\nTP(ON %02i): %s", i, eon_set->eon[i].tp? "yes":"no");
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_TA)
|
||||
+ printf("\nTA(ON %02i): %s", i, eon_set->eon[i].tp? "yes":"no");
|
||||
+ if (eon_set->eon[i].valid_fields & V4L2_RDS_AF) {
|
||||
+ printf("\nAF(ON %02i): size=%i", i, eon_set->eon[i].af.size);
|
||||
+ print_rds_af(&(eon_set->eon[i].af));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void print_rds_pi(const struct v4l2_rds *handle)
|
||||
{
|
||||
printf("\nArea Coverage: %s", v4l2_rds_get_coverage_str(handle));
|
||||
@@ -614,6 +665,8 @@ static void print_rds_data(const struct v4l2_rds *handle, uint32_t updated_field
|
||||
}
|
||||
if (updated_fields & V4L2_RDS_AF && handle->valid_fields & V4L2_RDS_AF)
|
||||
print_rds_af(&handle->rds_af);
|
||||
+ if (updated_fields & V4L2_RDS_TMC_TUNING && handle->valid_fields & V4L2_RDS_TMC_TUNING);
|
||||
+ print_rds_tmc_tuning(handle, updated_fields);
|
||||
if (params.options[OptPrintBlock])
|
||||
printf("\n");
|
||||
if (params.options[OptTMC])
|
||||
@@ -669,6 +722,8 @@ static void read_rds_from_fd(const int fd)
|
||||
|
||||
/* try to receive and decode RDS data */
|
||||
read_rds(rds_handle, fd, params.wait_limit);
|
||||
+ if (rds_handle->valid_fields & V4L2_RDS_EON)
|
||||
+ print_rds_eon(&rds_handle->rds_eon);
|
||||
print_rds_statistics(&rds_handle->rds_statistics);
|
||||
|
||||
v4l2_rds_destroy(rds_handle);
|
||||
--
|
||||
1.8.2.1
|
||||
|
||||
297
0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch
Normal file
297
0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch
Normal file
@ -0,0 +1,297 @@
|
||||
From d5ec86b3ed8151e05c79e69bff6dde15d5f8487c Mon Sep 17 00:00:00 2001
|
||||
From: Konke Radlow <koradlow@gmail.com>
|
||||
Date: Tue, 4 Jun 2013 18:15:03 +0000
|
||||
Subject: [PATCH 4/6] libv4l2rds.c: moving functions to get rid of declarations
|
||||
|
||||
Signed-off-by: Konke Radlow <koradlow@gmail.com>
|
||||
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
---
|
||||
lib/libv4l2rds/libv4l2rds.c | 243 ++++++++++++++++++++++----------------------
|
||||
1 file changed, 120 insertions(+), 123 deletions(-)
|
||||
|
||||
diff --git a/lib/libv4l2rds/libv4l2rds.c b/lib/libv4l2rds/libv4l2rds.c
|
||||
index 28b78ce..333bf95 100644
|
||||
--- a/lib/libv4l2rds/libv4l2rds.c
|
||||
+++ b/lib/libv4l2rds/libv4l2rds.c
|
||||
@@ -92,11 +92,6 @@ enum rds_state {
|
||||
RDS_C_RECEIVED,
|
||||
};
|
||||
|
||||
-/* function declarations to prevent the need to move large code blocks */
|
||||
-static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi);
|
||||
-static uint32_t rds_decode_af(uint8_t af, bool is_vhf);
|
||||
-static bool rds_add_tmc_af(struct rds_private_state *priv_state);
|
||||
-
|
||||
static inline uint8_t set_bit(uint8_t input, uint8_t bitmask, bool bitvalue)
|
||||
{
|
||||
return bitvalue ? input | bitmask : input & ~bitmask;
|
||||
@@ -201,6 +196,29 @@ static void rds_decode_d(struct rds_private_state *priv_state, struct v4l2_rds_d
|
||||
grp->data_d_lsb = rds_data->lsb;
|
||||
}
|
||||
|
||||
+/* decodes the RDS radio frequency representation into Hz
|
||||
+ * @af: 8-bit AF value as transmitted in RDS groups
|
||||
+ * @is_vhf: boolean value defining which conversion table to use
|
||||
+ * @return: frequency in Hz, 0 in case of wrong input values */
|
||||
+static uint32_t rds_decode_af(uint8_t af, bool is_vhf) {
|
||||
+ uint32_t freq = 0;
|
||||
+
|
||||
+ /* AF = 0 => "not to be used"
|
||||
+ * AF >= 205 => special meanings */
|
||||
+ if (af == 0 || af >= 205)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* calculate the AF values in HZ */
|
||||
+ if (is_vhf)
|
||||
+ freq = 87500000 + af * 100000;
|
||||
+ else if (freq <= 15)
|
||||
+ freq = 152000 + af * 9000;
|
||||
+ else
|
||||
+ freq = 531000 + af * 9000;
|
||||
+
|
||||
+ return freq;
|
||||
+}
|
||||
+
|
||||
/* compare two rds-groups for equality */
|
||||
/* used for decoding RDS-TMC, which has the requirement that the same group
|
||||
* is at least received twice before it is accepted */
|
||||
@@ -224,6 +242,103 @@ static bool rds_compare_group(const struct v4l2_rds_group *a,
|
||||
return true;
|
||||
}
|
||||
|
||||
+/* checks if an entry for the given PI already exists and returns the index
|
||||
+ * of that entry if so. Else it adds a new entry to the TMC-Tuning table and returns
|
||||
+ * the index of the new field */
|
||||
+static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi)
|
||||
+{
|
||||
+ struct v4l2_tmc_tuning *tuning = &priv_state->handle.tmc.tuning;
|
||||
+ uint8_t index = tuning->index;
|
||||
+ uint8_t size = tuning->station_cnt;
|
||||
+
|
||||
+ /* check if there's an entry for the given PI key */
|
||||
+ for (int i = 0; i < tuning->station_cnt; i++) {
|
||||
+ if (tuning->station[i].pi == pi) {
|
||||
+ return i;
|
||||
+ }
|
||||
+ }
|
||||
+ /* if the the maximum table size is reached, overwrite old
|
||||
+ * entries, starting at the oldest one = 0 */
|
||||
+ tuning->station[index].pi = pi;
|
||||
+ tuning->index = (index+1 < MAX_TMC_ALT_STATIONS) ? (index+1) : 0;
|
||||
+ tuning->station_cnt = (size+1 <= MAX_TMC_ALT_STATIONS) ? (size+1) : MAX_TMC_ALT_STATIONS;
|
||||
+ return index;
|
||||
+}
|
||||
+
|
||||
+/* tries to add new AFs to the relevant entry in the list of RDS-TMC providers */
|
||||
+static bool rds_add_tmc_af(struct rds_private_state *priv_state)
|
||||
+{
|
||||
+ struct v4l2_rds_group *grp = &priv_state->rds_group;
|
||||
+ struct v4l2_tmc_alt_freq *afi;
|
||||
+ uint16_t pi_on = grp->data_d_msb << 8 | grp->data_d_lsb;
|
||||
+ uint8_t variant = grp->data_b_lsb & 0x0f;
|
||||
+ uint8_t station_index = rds_add_tmc_station(priv_state, pi_on);
|
||||
+ uint8_t af_index;
|
||||
+ uint8_t mapped_af_index;
|
||||
+ uint32_t freq_a = rds_decode_af(grp->data_c_msb, true);
|
||||
+ uint32_t freq_b = rds_decode_af(grp->data_c_lsb, true);
|
||||
+
|
||||
+ afi = &priv_state->handle.tmc.tuning.station[station_index].afi;
|
||||
+ af_index = afi->af_index;
|
||||
+ mapped_af_index = afi->mapped_af_index;
|
||||
+
|
||||
+ /* specific frequencies */
|
||||
+ if (variant == 6) {
|
||||
+ /* compare the new AFs to the stored ones, reset them to 0 if the AFs are
|
||||
+ * already known */
|
||||
+ for (int i = 0; i < afi->af_size; i++) {
|
||||
+ freq_a = (freq_a == afi->af[i]) ? 0 : freq_a;
|
||||
+ freq_b = (freq_b == afi->af[i]) ? 0 : freq_b;
|
||||
+ }
|
||||
+ /* return early if there is nothing to do */
|
||||
+ if (freq_a == 0 && freq_b == 0)
|
||||
+ return false;
|
||||
+
|
||||
+ /* add the new AFs if they were previously unknown */
|
||||
+ if (freq_a != 0) {
|
||||
+ afi->af[af_index] = freq_a;
|
||||
+ af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
|
||||
+ afi->af_size++;
|
||||
+ }
|
||||
+ if (freq_b != 0) {
|
||||
+ afi->af[af_index] = freq_b;
|
||||
+ af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
|
||||
+ afi->af_size++;
|
||||
+ }
|
||||
+ /* update the information in the handle */
|
||||
+ afi->af_index = af_index;
|
||||
+ if (afi->af_size >= MAX_TMC_AF_CNT)
|
||||
+ afi->af_size = MAX_TMC_AF_CNT;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ /* mapped frequency pair */
|
||||
+ else if (variant == 7) {
|
||||
+ /* check the if there's already a frequency mapped to the new tuning
|
||||
+ * frequency, update the mapped frequency in this case */
|
||||
+ for (int i = 0; i < afi->mapped_af_size; i++) {
|
||||
+ if (freq_a == afi->mapped_af_tuning[i])
|
||||
+ afi->mapped_af[i] = freq_b;
|
||||
+ return true;
|
||||
+ }
|
||||
+ /* new pair is unknown, add it to the list */
|
||||
+ if (freq_a != 0 && freq_b != 0) {
|
||||
+ mapped_af_index = (mapped_af_index+1 >= MAX_TMC_AF_CNT) ? 0 : mapped_af_index + 1;
|
||||
+ afi->mapped_af[mapped_af_index] = freq_b;
|
||||
+ afi->mapped_af_tuning[mapped_af_index] = freq_a;
|
||||
+ afi->mapped_af_size++;
|
||||
+ }
|
||||
+ /* update the information in the handle */
|
||||
+ afi->mapped_af_index = mapped_af_index;
|
||||
+ if (afi->mapped_af_size >= MAX_TMC_AF_CNT)
|
||||
+ afi->mapped_af_size = MAX_TMC_AF_CNT;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/* decode additional information of a TMC message into handy representation */
|
||||
/* the additional information of TMC messages is submitted in (up to) 4 blocks of
|
||||
* 28 bits each, which are to be treated as a consecutive bit-array. This data
|
||||
@@ -572,102 +687,7 @@ static bool rds_add_af(struct rds_private_state *priv_state)
|
||||
return updated_af;
|
||||
}
|
||||
|
||||
-/* checks if an entry for the given PI already exists and returns the index
|
||||
- * of that entry if so. Else it adds a new entry to the TMC-Tuning table and returns
|
||||
- * the index of the new field */
|
||||
-static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi)
|
||||
-{
|
||||
- struct v4l2_tmc_tuning *tuning = &priv_state->handle.tmc.tuning;
|
||||
- uint8_t index = tuning->index;
|
||||
- uint8_t size = tuning->station_cnt;
|
||||
-
|
||||
- /* check if there's an entry for the given PI key */
|
||||
- for (int i = 0; i < tuning->station_cnt; i++) {
|
||||
- if (tuning->station[i].pi == pi) {
|
||||
- return i;
|
||||
- }
|
||||
- }
|
||||
- /* if the the maximum table size is reached, overwrite old
|
||||
- * entries, starting at the oldest one = 0 */
|
||||
- tuning->station[index].pi = pi;
|
||||
- tuning->index = (index+1 < MAX_TMC_ALT_STATIONS) ? (index+1) : 0;
|
||||
- tuning->station_cnt = (size+1 <= MAX_TMC_ALT_STATIONS) ? (size+1) : MAX_TMC_ALT_STATIONS;
|
||||
- return index;
|
||||
-}
|
||||
-
|
||||
-/* tries to add new AFs to the relevant entry in the list of RDS-TMC providers */
|
||||
-static bool rds_add_tmc_af(struct rds_private_state *priv_state)
|
||||
-{
|
||||
- struct v4l2_rds_group *grp = &priv_state->rds_group;
|
||||
- struct v4l2_tmc_alt_freq *afi;
|
||||
- uint16_t pi_on = grp->data_d_msb << 8 | grp->data_d_lsb;
|
||||
- uint8_t variant = grp->data_b_lsb & 0x0f;
|
||||
- uint8_t station_index = rds_add_tmc_station(priv_state, pi_on);
|
||||
- uint8_t af_index;
|
||||
- uint8_t mapped_af_index;
|
||||
- uint32_t freq_a = rds_decode_af(grp->data_c_msb, true);
|
||||
- uint32_t freq_b = rds_decode_af(grp->data_c_lsb, true);
|
||||
-
|
||||
- afi = &priv_state->handle.tmc.tuning.station[station_index].afi;
|
||||
- af_index = afi->af_index;
|
||||
- mapped_af_index = afi->mapped_af_index;
|
||||
-
|
||||
- /* specific frequencies */
|
||||
- if (variant == 6) {
|
||||
- /* compare the new AFs to the stored ones, reset them to 0 if the AFs are
|
||||
- * already known */
|
||||
- for (int i = 0; i < afi->af_size; i++) {
|
||||
- freq_a = (freq_a == afi->af[i]) ? 0 : freq_a;
|
||||
- freq_b = (freq_b == afi->af[i]) ? 0 : freq_b;
|
||||
- }
|
||||
- /* return early if there is nothing to do */
|
||||
- if (freq_a == 0 && freq_b == 0)
|
||||
- return false;
|
||||
-
|
||||
- /* add the new AFs if they were previously unknown */
|
||||
- if (freq_a != 0) {
|
||||
- afi->af[af_index] = freq_a;
|
||||
- af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
|
||||
- afi->af_size++;
|
||||
- }
|
||||
- if (freq_b != 0) {
|
||||
- afi->af[af_index] = freq_b;
|
||||
- af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
|
||||
- afi->af_size++;
|
||||
- }
|
||||
- /* update the information in the handle */
|
||||
- afi->af_index = af_index;
|
||||
- if (afi->af_size >= MAX_TMC_AF_CNT)
|
||||
- afi->af_size = MAX_TMC_AF_CNT;
|
||||
-
|
||||
- return true;
|
||||
- }
|
||||
|
||||
- /* mapped frequency pair */
|
||||
- else if (variant == 7) {
|
||||
- /* check the if there's already a frequency mapped to the new tuning
|
||||
- * frequency, update the mapped frequency in this case */
|
||||
- for (int i = 0; i < afi->mapped_af_size; i++) {
|
||||
- if (freq_a == afi->mapped_af_tuning[i])
|
||||
- afi->mapped_af[i] = freq_b;
|
||||
- return true;
|
||||
- }
|
||||
- /* new pair is unknown, add it to the list */
|
||||
- if (freq_a != 0 && freq_b != 0) {
|
||||
- mapped_af_index = (mapped_af_index+1 >= MAX_TMC_AF_CNT) ? 0 : mapped_af_index + 1;
|
||||
- afi->mapped_af[mapped_af_index] = freq_b;
|
||||
- afi->mapped_af_tuning[mapped_af_index] = freq_a;
|
||||
- afi->mapped_af_size++;
|
||||
- }
|
||||
- /* update the information in the handle */
|
||||
- afi->mapped_af_index = mapped_af_index;
|
||||
- if (afi->mapped_af_size >= MAX_TMC_AF_CNT)
|
||||
- afi->mapped_af_size = MAX_TMC_AF_CNT;
|
||||
-
|
||||
- return true;
|
||||
- }
|
||||
- return false;
|
||||
-}
|
||||
|
||||
/* adds one char of the ps name to temporal storage, the value is validated
|
||||
* if it is received twice in a row
|
||||
@@ -975,29 +995,6 @@ static uint32_t rds_decode_group3(struct rds_private_state *priv_state)
|
||||
return updated_fields;
|
||||
}
|
||||
|
||||
-/* decodes the RDS radio frequency representation into Hz
|
||||
- * @af: 8-bit AF value as transmitted in RDS groups
|
||||
- * @is_vhf: boolean value defining which conversion table to use
|
||||
- * @return: frequency in Hz, 0 in case of wrong input values */
|
||||
-static uint32_t rds_decode_af(uint8_t af, bool is_vhf) {
|
||||
- uint32_t freq = 0;
|
||||
-
|
||||
- /* AF = 0 => "not to be used"
|
||||
- * AF >= 205 => special meanings */
|
||||
- if (af == 0 || af >= 205)
|
||||
- return 0;
|
||||
-
|
||||
- /* calculate the AF values in HZ */
|
||||
- if (is_vhf)
|
||||
- freq = 87500000 + af * 100000;
|
||||
- else if (freq <= 15)
|
||||
- freq = 152000 + af * 9000;
|
||||
- else
|
||||
- freq = 531000 + af * 9000;
|
||||
-
|
||||
- return freq;
|
||||
-}
|
||||
-
|
||||
/* decodes the RDS date/time representation into a standard c representation
|
||||
* that can be used with c-library functions */
|
||||
static time_t rds_decode_mjd(const struct rds_private_state *priv_state)
|
||||
--
|
||||
1.8.2.1
|
||||
|
||||
43
0005-rds-ctl-support-d10-to-refer-to-radio10.patch
Normal file
43
0005-rds-ctl-support-d10-to-refer-to-radio10.patch
Normal file
@ -0,0 +1,43 @@
|
||||
From c7bdfa014bac092cc4490820708ad65da07cf15c Mon Sep 17 00:00:00 2001
|
||||
From: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
Date: Fri, 7 Jun 2013 10:22:51 +0200
|
||||
Subject: [PATCH 5/6] rds-ctl: support -d10 to refer to radio10.
|
||||
|
||||
In order to be consistent with other v4l utilities support the '-d<num>' option
|
||||
for num >= 10.
|
||||
|
||||
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
---
|
||||
utils/rds-ctl/rds-ctl.cpp | 9 +++++----
|
||||
1 file changed, 5 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/utils/rds-ctl/rds-ctl.cpp b/utils/rds-ctl/rds-ctl.cpp
|
||||
index d894ec1..a9fe2a8 100644
|
||||
--- a/utils/rds-ctl/rds-ctl.cpp
|
||||
+++ b/utils/rds-ctl/rds-ctl.cpp
|
||||
@@ -133,7 +133,7 @@ static void usage_common(void)
|
||||
" --all display all device information available\n"
|
||||
" -D, --info show driver info [VIDIOC_QUERYCAP]\n"
|
||||
" -d, --device=<dev> use device <dev>\n"
|
||||
- " if <dev> is a single digit, then /dev/radio<dev> is used\n"
|
||||
+ " If <dev> starts with a digit, then /dev/radio<dev> is used\n"
|
||||
" default: checks for RDS-capable devices,\n"
|
||||
" uses device with lowest ID\n"
|
||||
" -h, --help display this help message\n"
|
||||
@@ -763,9 +763,10 @@ static int parse_cl(int argc, char **argv)
|
||||
switch (opt) {
|
||||
case OptSetDevice:
|
||||
strncpy(params.fd_name, optarg, 80);
|
||||
- if (isdigit(optarg[0]) && optarg[1] == 0) {
|
||||
- char newdev[20];
|
||||
- sprintf(newdev, "/dev/radio%c", optarg[0]);
|
||||
+ if (optarg[0] >= '0' && optarg[0] <= '9' && strlen(optarg) <= 3) {
|
||||
+ static char newdev[20];
|
||||
+
|
||||
+ sprintf(newdev, "/dev/radio%s", optarg);
|
||||
strncpy(params.fd_name, newdev, 20);
|
||||
}
|
||||
break;
|
||||
--
|
||||
1.8.2.1
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From 38d8bf17783cda83ec05920094896c9275835529 Mon Sep 17 00:00:00 2001
|
||||
From: Hans de Goede <hdegoede@redhat.com>
|
||||
Date: Sun, 9 Jun 2013 16:31:55 +0200
|
||||
Subject: [PATCH 6/6] libv4l2: Add logging of dqbuf timestamps to debug logging
|
||||
|
||||
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
||||
---
|
||||
lib/libv4l2/log.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/lib/libv4l2/log.c b/lib/libv4l2/log.c
|
||||
index 45c0e6b..8aa5310 100644
|
||||
--- a/lib/libv4l2/log.c
|
||||
+++ b/lib/libv4l2/log.c
|
||||
@@ -173,6 +173,13 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
|
||||
req->count, (int)req->type, (int)req->memory);
|
||||
break;
|
||||
}
|
||||
+ case VIDIOC_DQBUF: {
|
||||
+ struct v4l2_buffer *buf = arg;
|
||||
+ fprintf(v4l2_log_file, " timestamp %ld.%06ld\n",
|
||||
+ (long)buf->timestamp.tv_sec,
|
||||
+ (long)buf->timestamp.tv_usec);
|
||||
+ break;
|
||||
+ }
|
||||
case VIDIOC_ENUM_FRAMESIZES: {
|
||||
struct v4l2_frmsizeenum *frmsize = arg;
|
||||
int pixfmt = frmsize->pixel_format;
|
||||
--
|
||||
1.8.2.1
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
Name: v4l-utils
|
||||
Version: 0.9.5
|
||||
Release: 1%{?dist}
|
||||
Release: 2%{?dist}
|
||||
Summary: Utilities for video4linux and DVB devices
|
||||
Group: Applications/System
|
||||
# ir-keytable and v4l2-sysfs-path are GPLv2 only
|
||||
License: GPLv2+ and GPLv2
|
||||
URL: http://www.linuxtv.org/downloads/v4l-utils/
|
||||
Source0: http://linuxtv.org/downloads/v4l-utils/v4l-utils-%{version}.tar.bz2
|
||||
Patch1: 0001-rds-ctl-fix-percentage-handling.patch
|
||||
Patch2: 0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch
|
||||
Patch3: 0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch
|
||||
Patch4: 0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch
|
||||
Patch5: 0005-rds-ctl-support-d10-to-refer-to-radio10.patch
|
||||
Patch6: 0006-libv4l2-Add-logging-of-dqbuf-timestamps-to-debug-log.patch
|
||||
BuildRequires: libjpeg-devel qt4-devel kernel-headers desktop-file-utils
|
||||
# For /lib/udev/rules.d ownership
|
||||
Requires: udev
|
||||
@ -77,6 +83,12 @@ developing applications that use libv4l.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
%patch1 -p1
|
||||
%patch2 -p1
|
||||
%patch3 -p1
|
||||
%patch4 -p1
|
||||
%patch5 -p1
|
||||
%patch6 -p1
|
||||
|
||||
|
||||
%build
|
||||
@ -155,6 +167,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Jun 14 2013 Hans de Goede <hdegoede@redhat.com> - 0.9.5-2
|
||||
- Add a few libv4l2rds patches from upstream, which bring libv4l2rds to its
|
||||
final API / ABI, so that apps build against it won't need a rebuild in the
|
||||
future
|
||||
|
||||
* Sun Jun 9 2013 Hans de Goede <hdegoede@redhat.com> - 0.9.5-1
|
||||
- New upstream release 0.9.5 (rhbz#970412)
|
||||
- Modernize specfile a bit
|
||||
|
||||
Loading…
Reference in New Issue
Block a user