1 /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 /* 3 * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 4 * Author: Konke Radlow <koradlow@gmail.com> 5 */ 6 7 #ifndef __LIBV4L2RDS 8 #define __LIBV4L2RDS 9 10 11 #include <stdbool.h> 12 #include <stdint.h> 13 14 #if defined(__OpenBSD__) 15 #include <sys/videoio.h> 16 #else 17 #include <linux/videodev2.h> 18 #endif 19 20 #ifdef __cplusplus 21 extern "C" { 22 #endif /* __cplusplus */ 23 24 #if HAVE_VISIBILITY 25 #define LIBV4L_PUBLIC __attribute__ ((visibility("default"))) 26 #else 27 #define LIBV4L_PUBLIC 28 #endif 29 30 /* used to define the current version (version field) of the v4l2_rds struct */ 31 #define V4L2_RDS_VERSION (2) 32 33 /* Constants used to define the size of arrays used to store RDS information */ 34 #define MAX_ODA_CNT 18 /* there are 16 groups each with type a or b. Of these 35 * 32 distinct groups, 18 can be used for ODA purposes */ 36 #define MAX_AF_CNT 25 /* AF Method A allows a maximum of 25 AFs to be defined 37 * AF Method B does not impose a limit on the number of AFs 38 * but it is not fully supported at the moment and will 39 * not receive more than 25 AFs */ 40 #define MAX_TMC_ADDITIONAL 28 /* 28 is the maximal possible number of fields. 41 * Additional data is limited to 112 bit, and the smallest 42 * optional tuple has a size of 4 bit (4 bit identifier + 43 * 0 bits of data) */ 44 #define MAX_TMC_ALT_STATIONS 32 /* defined by ISO 14819-1:2003, 7.5.3.3 */ 45 #define MAX_TMC_AF_CNT 4 /* limit for the numbers of AFs stored per alternative TMC 46 * station. This value is not defined by the standard, but based on observation 47 * of real-world RDS-TMC streams. The maximum encountered number of AFs per 48 * station during testing was 2 */ 49 #define MAX_EON_CNT 20 /* Maximal number of entries in the EON table (for storing 50 * information about other radio stations, broadcasted by the current station). 51 * This value is not defined by the standard, but based on observation 52 * of real-world RDS-TMC streams. EON doesn't seem to be a widely used feature 53 * and the maximum number of EON encountered during testing was 8 */ 54 55 /* Define Constants for the possible types of RDS information 56 * used to address the relevant bit in the valid_fields bitmask */ 57 #define V4L2_RDS_PI 0x01 /* Program Identification */ 58 #define V4L2_RDS_PTY 0x02 /* Program Type */ 59 #define V4L2_RDS_TP 0x04 /* Traffic Program */ 60 #define V4L2_RDS_PS 0x08 /* Program Service Name */ 61 #define V4L2_RDS_TA 0x10 /* Traffic Announcement */ 62 #define V4L2_RDS_DI 0x20 /* Decoder Information */ 63 #define V4L2_RDS_MS 0x40 /* Music / Speech flag */ 64 #define V4L2_RDS_PTYN 0x80 /* Program Type Name */ 65 #define V4L2_RDS_RT 0x100 /* Radio-Text */ 66 #define V4L2_RDS_TIME 0x200 /* Date and Time information */ 67 #define V4L2_RDS_TMC 0x400 /* TMC availability */ 68 #define V4L2_RDS_AF 0x800 /* AF (alternative freq) available */ 69 #define V4L2_RDS_ECC 0x1000 /* Extended County Code */ 70 #define V4L2_RDS_LC 0x2000 /* Language Code */ 71 #define V4L2_RDS_TMC_SG 0x4000 /* RDS-TMC single group */ 72 #define V4L2_RDS_TMC_MG 0x8000 /* RDS-TMC multi group */ 73 #define V4L2_RDS_TMC_SYS 0x10000 /* RDS-TMC system information */ 74 #define V4L2_RDS_EON 0x20000 /* Enhanced Other Network Info */ 75 #define V4L2_RDS_LSF 0x40000 /* Linkage information */ 76 #define V4L2_RDS_TMC_TUNING 0x80000 /* RDS-TMC tuning information */ 77 78 /* Define Constants for the state of the RDS decoding process 79 * used to address the relevant bit in the decode_information bitmask */ 80 #define V4L2_RDS_GROUP_NEW 0x01 /* New group received */ 81 #define V4L2_RDS_ODA 0x02 /* Open Data Group announced */ 82 83 /* Decoder Information (DI) codes 84 * used to decode the DI information according to the RDS standard */ 85 #define V4L2_RDS_FLAG_STEREO 0x01 86 #define V4L2_RDS_FLAG_ARTIFICIAL_HEAD 0x02 87 #define V4L2_RDS_FLAG_COMPRESSED 0x04 88 #define V4L2_RDS_FLAG_DYNAMIC_PTY 0x08 89 90 /* TMC related codes 91 * used to extract TMC fields from RDS-TMC groups 92 * see ISO 14819-1:2003, Figure 2 - RDS-TMC single-grp full message structure */ 93 #define V4L2_TMC_TUNING_INFO 0x10 /* Bit 4 indicates Tuning Info / User msg */ 94 #define V4L2_TMC_SINGLE_GROUP 0x08 /* Bit 3 indicates Single / Multi-group msg */ 95 96 /* struct to encapsulate one complete RDS group */ 97 /* This structure is used internally to store data until a complete RDS 98 * group was received and group id dependent decoding can be done. 99 * It is also used to provide external access to uninterpreted RDS groups 100 * when manual decoding is required (e.g. special ODA types) */ 101 struct v4l2_rds_group { 102 uint16_t pi; /* Program Identification */ 103 char group_version; /* group version ('A' / 'B') */ 104 uint8_t group_id; /* group number (0..16) */ 105 106 /* uninterpreted data blocks for decoding (e.g. ODA) */ 107 uint8_t data_b_lsb; 108 uint8_t data_c_msb; 109 uint8_t data_c_lsb; 110 uint8_t data_d_msb; 111 uint8_t data_d_lsb; 112 }; 113 114 /* struct to encapsulate some statistical information about the decoding process */ 115 struct v4l2_rds_statistics { 116 uint32_t block_cnt; /* total amount of received blocks */ 117 uint32_t group_cnt; /* total amount of successfully 118 * decoded groups */ 119 uint32_t block_error_cnt; /* blocks that were marked as erroneous 120 * and had to be dropped */ 121 uint32_t group_error_cnt; /* group decoding processes that had to be 122 * aborted because of erroneous blocks 123 * or wrong order of blocks */ 124 uint32_t block_corrected_cnt; /* blocks that contained 1-bit errors 125 * which were corrected */ 126 uint32_t group_type_cnt[16]; /* number of occurrence for each 127 * defined RDS group */ 128 }; 129 130 /* struct to encapsulate the definition of one ODA (Open Data Application) type */ 131 struct v4l2_rds_oda { 132 uint8_t group_id; /* RDS group used to broadcast this ODA */ 133 char group_version; /* group version (A / B) for this ODA */ 134 uint16_t aid; /* Application Identification for this ODA, 135 * AIDs are centrally administered by the 136 * RDS Registration Office (rds.org.uk) */ 137 }; 138 139 /* struct to encapsulate an array of all defined ODA types for a channel */ 140 /* This structure will grow with ODA announcements broadcasted in type 3A 141 * groups, that were verified not to be no duplicates or redefinitions */ 142 struct v4l2_rds_oda_set { 143 uint8_t size; /* number of ODAs defined by this channel */ 144 struct v4l2_rds_oda oda[MAX_ODA_CNT]; 145 }; 146 147 /* struct to encapsulate an array of Alternative Frequencies for a channel */ 148 /* Every channel can send out AFs for his program. The number of AFs that 149 * will be broadcasted is announced by the channel */ 150 struct v4l2_rds_af_set { 151 uint8_t size; /* size of the set (might be smaller 152 * than the announced size) */ 153 uint8_t announced_af; /* number of announced AF */ 154 uint32_t af[MAX_AF_CNT]; /* AFs defined in Hz */ 155 }; 156 157 /* struct to encapsulate one entry in the EON table (Enhanced Other Network) */ 158 struct v4l2_rds_eon { 159 uint32_t valid_fields; 160 uint16_t pi; 161 uint8_t ps[9]; 162 uint8_t pty; 163 bool ta; 164 bool tp; 165 uint16_t lsf; /* Linkage Set Number */ 166 struct v4l2_rds_af_set af; 167 }; 168 169 /* struct to encapsulate a table of EON information */ 170 struct v4l2_rds_eon_set { 171 uint8_t size; /* size of the table */ 172 uint8_t index; /* current position in the table */ 173 struct v4l2_rds_eon eon[MAX_EON_CNT]; /* Information about other 174 * radio channels */ 175 }; 176 177 /* struct to encapsulate alternative frequencies (AFs) for RDS-TMC stations. 178 * AFs listed in af[] can be used unconditionally. 179 * AFs listed in mapped_af[n] should only be used if the current 180 * tuner frequency matches the value in mapped_af_tuning[n] */ 181 struct v4l2_tmc_alt_freq { 182 uint8_t af_size; /* number of known AFs */ 183 uint8_t af_index; 184 uint8_t mapped_af_size; /* number of mapped AFs */ 185 uint8_t mapped_af_index; 186 uint32_t af[MAX_TMC_AF_CNT]; /* AFs defined in Hz */ 187 uint32_t mapped_af[MAX_TMC_AF_CNT]; /* mapped AFs defined in Hz */ 188 uint32_t mapped_af_tuning[MAX_TMC_AF_CNT]; /* mapped AFs defined in Hz */ 189 }; 190 191 /* struct to encapsulate information about stations carrying RDS-TMC services */ 192 struct v4l2_tmc_station { 193 uint16_t pi; 194 uint8_t ltn; /* database-ID of ON */ 195 uint8_t msg; /* msg parameters of ON */ 196 uint8_t sid; /* service-ID of ON */ 197 struct v4l2_tmc_alt_freq afi; 198 }; 199 200 /* struct to encapsulate tuning information for TMC */ 201 struct v4l2_tmc_tuning { 202 uint8_t station_cnt; /* number of announced alternative stations */ 203 uint8_t index; 204 struct v4l2_tmc_station station[MAX_TMC_ALT_STATIONS]; /* information 205 * about other stations carrying the same RDS-TMC service */ 206 }; 207 208 /* struct to encapsulate an additional data field in a TMC message */ 209 struct v4l2_tmc_additional { 210 uint8_t label; 211 uint16_t data; 212 }; 213 214 /* struct to encapsulate an arbitrary number of additional data fields 215 * belonging to one TMC message */ 216 struct v4l2_tmc_additional_set { 217 uint8_t size; 218 struct v4l2_tmc_additional fields[MAX_TMC_ADDITIONAL]; 219 }; 220 221 /* struct to encapsulate a decoded TMC message with optional additional 222 * data field (in case of a multi-group TMC message) */ 223 struct v4l2_rds_tmc_msg { 224 uint8_t length; /* length of multi-group message (0..4) */ 225 uint8_t sid; /* service identifier at time of reception */ 226 uint8_t extent; 227 uint8_t dp; /* duration and persistence */ 228 uint16_t event; /* TMC event code */ 229 uint16_t location; /* TMC event location */ 230 bool follow_diversion; /* indicates if the driver is adviced to 231 * follow the diversion */ 232 bool neg_direction; /* indicates negative / positive direction */ 233 234 /* decoded additional information (only available in multi-group 235 * messages) */ 236 struct v4l2_tmc_additional_set additional; 237 }; 238 239 /* struct to encapsulate all TMC related information, including TMC System 240 * Information, TMC Tuning information and a buffer for the last decoded 241 * TMC messages */ 242 struct v4l2_rds_tmc { 243 uint8_t ltn; /* location_table_number */ 244 bool afi; /* alternative frequency indicator */ 245 bool enhanced_mode; /* mode of transmission, 246 * if false -> basic => gaps between tmc groups 247 * gap defines timing behavior 248 * if true -> enhanced => t_a, t_w and t_d 249 * define timing behavior of tmc groups */ 250 uint8_t mgs; /* message geographical scope */ 251 uint8_t sid; /* service identifier (unique ID on national level) */ 252 uint8_t gap; /* Gap parameters */ 253 uint8_t t_a; /* activity time (only if mode = enhanced) */ 254 uint8_t t_w; /* window time (only if mode = enhanced */ 255 uint8_t t_d; /* delay time (only if mode = enhanced */ 256 uint8_t spn[9]; /* service provider name */ 257 struct v4l2_rds_tmc_msg tmc_msg; 258 259 /* tuning information for alternative service providers */ 260 struct v4l2_tmc_tuning tuning; 261 }; 262 263 /* struct to encapsulate state and RDS information for current decoding process */ 264 /* This is the structure that will be used by external applications, to 265 * communicate with the library and get access to RDS data */ 266 struct v4l2_rds { 267 /** state information **/ 268 uint32_t decode_information; /* state of decoding process */ 269 uint32_t valid_fields; /* currently valid info fields 270 * of this structure */ 271 272 /** RDS info fields **/ 273 bool is_rbds; /* use RBDS standard version of LUTs */ 274 uint16_t pi; /* Program Identification */ 275 uint8_t ps[9]; /* Program Service Name, UTF-8 encoding, 276 * '\0' terminated */ 277 uint8_t pty; /* Program Type */ 278 uint8_t ptyn[9]; /* Program Type Name, UTF-8 encoding, 279 * '\0' terminated */ 280 bool ptyn_ab_flag; /* PTYN A/B flag (toggled), to signal 281 * change of PTYN */ 282 uint8_t rt_length; /* length of RT string */ 283 uint8_t rt[65]; /* Radio-Text string, UTF-8 encoding, 284 * '\0' terminated */ 285 bool rt_ab_flag; /* RT A/B flag (toggled), to signal 286 * transmission of new RT */ 287 bool ta; /* Traffic Announcement */ 288 bool tp; /* Traffic Program */ 289 bool ms; /* Music / Speech flag */ 290 uint8_t di; /* Decoder Information */ 291 uint8_t ecc; /* Extended Country Code */ 292 uint8_t lc; /* Language Code */ 293 time_t time; /* local time and date of transmission */ 294 295 struct v4l2_rds_statistics rds_statistics; 296 struct v4l2_rds_oda_set rds_oda; /* Open Data Services */ 297 struct v4l2_rds_af_set rds_af; /* Alternative Frequencies */ 298 struct v4l2_rds_eon_set rds_eon; /* EON information */ 299 struct v4l2_rds_tmc tmc; /* TMC information */ 300 }; 301 302 /* v4l2_rds_init() - initializes a new decoding process 303 * @is_rbds: defines which standard is used: true=RBDS, false=RDS 304 * 305 * initialize a new instance of the RDS-decoding struct and return 306 * a handle containing state and RDS information, used to interact 307 * with the library functions */ 308 LIBV4L_PUBLIC struct v4l2_rds *v4l2_rds_create(bool is_rbds); 309 310 /* frees all memory allocated for the RDS-decoding struct */ 311 LIBV4L_PUBLIC void v4l2_rds_destroy(struct v4l2_rds *handle); 312 313 /* resets the RDS information in the handle to initial values 314 * e.g. can be used when radio channel is changed 315 * @reset_statistics: true = set all statistic values to 0, false = keep them untouched */ 316 LIBV4L_PUBLIC void v4l2_rds_reset(struct v4l2_rds *handle, bool reset_statistics); 317 318 /* adds a raw RDS block to decode it into RDS groups 319 * @return: bitmask with with updated fields set to 1 320 * @rds_data: 3 bytes of raw RDS data, obtained by calling read() 321 * on RDS capable V4L2 devices */ 322 LIBV4L_PUBLIC uint32_t v4l2_rds_add(struct v4l2_rds *handle, struct v4l2_rds_data *rds_data); 323 324 /* 325 * group of functions to translate numerical RDS data into strings 326 * 327 * return program description string defined in the RDS/RBDS Standard 328 * ! return value depends on selected Standard !*/ 329 LIBV4L_PUBLIC const char *v4l2_rds_get_pty_str(const struct v4l2_rds *handle); 330 LIBV4L_PUBLIC const char *v4l2_rds_get_language_str(const struct v4l2_rds *handle); 331 LIBV4L_PUBLIC const char *v4l2_rds_get_country_str(const struct v4l2_rds *handle); 332 LIBV4L_PUBLIC const char *v4l2_rds_get_coverage_str(const struct v4l2_rds *handle); 333 334 /* returns a pointer to the last decoded RDS group, in order to give raw 335 * access to RDS data if it is required (e.g. ODA decoding) */ 336 LIBV4L_PUBLIC const struct v4l2_rds_group *v4l2_rds_get_group 337 (const struct v4l2_rds *handle); 338 339 340 #ifdef __cplusplus 341 } 342 #endif /* __cplusplus */ 343 #endif 344