linux/drivers/media/platform/vivid/vivid-rds-gen.c
<<
>>
Prefs
   1/*
   2 * vivid-rds-gen.c - rds (radio data system) generator support functions.
   3 *
   4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
   5 *
   6 * This program is free software; you may redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; version 2 of the License.
   9 *
  10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17 * SOFTWARE.
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/ktime.h>
  22#include <linux/string.h>
  23#include <linux/videodev2.h>
  24
  25#include "vivid-rds-gen.h"
  26
  27static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp)
  28{
  29        switch (grp) {
  30        case 0:
  31                return (rds->dyn_pty << 2) | (grp & 3);
  32        case 1:
  33                return (rds->compressed << 2) | (grp & 3);
  34        case 2:
  35                return (rds->art_head << 2) | (grp & 3);
  36        case 3:
  37                return (rds->mono_stereo << 2) | (grp & 3);
  38        }
  39        return 0;
  40}
  41
  42/*
  43 * This RDS generator creates 57 RDS groups (one group == four RDS blocks).
  44 * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a
  45 * standard 0B group containing the PI code and PS name.
  46 *
  47 * Groups 4-19 and 26-41 use group 2A for the radio text.
  48 *
  49 * Group 56 contains the time (group 4A).
  50 *
  51 * All remaining groups use a filler group 15B block that just repeats
  52 * the PI and PTY codes.
  53 */
  54void vivid_rds_generate(struct vivid_rds_gen *rds)
  55{
  56        struct v4l2_rds_data *data = rds->data;
  57        unsigned grp;
  58        unsigned idx;
  59        struct tm tm;
  60        unsigned date;
  61        unsigned time;
  62        int l;
  63
  64        for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) {
  65                data[0].lsb = rds->picode & 0xff;
  66                data[0].msb = rds->picode >> 8;
  67                data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3);
  68                data[1].lsb = rds->pty << 5;
  69                data[1].msb = (rds->pty >> 3) | (rds->tp << 2);
  70                data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3);
  71                data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3);
  72
  73                switch (grp) {
  74                case 0 ... 3:
  75                case 22 ... 25:
  76                case 44 ... 47: /* Group 0B */
  77                        idx = (grp % 22) % 4;
  78                        data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
  79                        data[1].lsb |= vivid_get_di(rds, idx);
  80                        data[1].msb |= 1 << 3;
  81                        data[2].lsb = rds->picode & 0xff;
  82                        data[2].msb = rds->picode >> 8;
  83                        data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
  84                        data[3].lsb = rds->psname[2 * idx + 1];
  85                        data[3].msb = rds->psname[2 * idx];
  86                        break;
  87                case 4 ... 19:
  88                case 26 ... 41: /* Group 2A */
  89                        idx = ((grp - 4) % 22) % 16;
  90                        data[1].lsb |= idx;
  91                        data[1].msb |= 4 << 3;
  92                        data[2].msb = rds->radiotext[4 * idx];
  93                        data[2].lsb = rds->radiotext[4 * idx + 1];
  94                        data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
  95                        data[3].msb = rds->radiotext[4 * idx + 2];
  96                        data[3].lsb = rds->radiotext[4 * idx + 3];
  97                        break;
  98                case 56:
  99                        /*
 100                         * Group 4A
 101                         *
 102                         * Uses the algorithm from Annex G of the RDS standard
 103                         * EN 50067:1998 to convert a UTC date to an RDS Modified
 104                         * Julian Day.
 105                         */
 106                        time_to_tm(get_seconds(), 0, &tm);
 107                        l = tm.tm_mon <= 1;
 108                        date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 +
 109                                ((tm.tm_mon + 2 + l * 12) * 306001) / 10000;
 110                        time = (tm.tm_hour << 12) |
 111                               (tm.tm_min << 6) |
 112                               (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) |
 113                               (abs(sys_tz.tz_minuteswest) / 30);
 114                        data[1].lsb &= ~3;
 115                        data[1].lsb |= date >> 15;
 116                        data[1].msb |= 8 << 3;
 117                        data[2].lsb = (date << 1) & 0xfe;
 118                        data[2].lsb |= (time >> 16) & 1;
 119                        data[2].msb = (date >> 7) & 0xff;
 120                        data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3);
 121                        data[3].lsb = time & 0xff;
 122                        data[3].msb = (time >> 8) & 0xff;
 123                        break;
 124                default: /* Group 15B */
 125                        data[1].lsb |= (rds->ta << 4) | (rds->ms << 3);
 126                        data[1].lsb |= vivid_get_di(rds, grp % 22);
 127                        data[1].msb |= 0x1f << 3;
 128                        data[2].lsb = rds->picode & 0xff;
 129                        data[2].msb = rds->picode >> 8;
 130                        data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3);
 131                        data[3].lsb = rds->pty << 5;
 132                        data[3].lsb |= (rds->ta << 4) | (rds->ms << 3);
 133                        data[3].lsb |= vivid_get_di(rds, grp % 22);
 134                        data[3].msb |= rds->pty >> 3;
 135                        data[3].msb |= 0x1f << 3;
 136                        break;
 137                }
 138        }
 139}
 140
 141void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq,
 142                          bool alt)
 143{
 144        /* Alternate PTY between Info and Weather */
 145        if (rds->use_rbds) {
 146                rds->picode = 0x2e75; /* 'KLNX' call sign */
 147                rds->pty = alt ? 29 : 2;
 148        } else {
 149                rds->picode = 0x8088;
 150                rds->pty = alt ? 16 : 3;
 151        }
 152        rds->mono_stereo = true;
 153        rds->art_head = false;
 154        rds->compressed = false;
 155        rds->dyn_pty = false;
 156        rds->tp = true;
 157        rds->ta = alt;
 158        rds->ms = true;
 159        snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d",
 160                 freq / 16, ((freq & 0xf) * 10) / 16);
 161        if (alt)
 162                strlcpy(rds->radiotext,
 163                        " The Radio Data System can switch between different Radio Texts ",
 164                        sizeof(rds->radiotext));
 165        else
 166                strlcpy(rds->radiotext,
 167                        "An example of Radio Text as transmitted by the Radio Data System",
 168                        sizeof(rds->radiotext));
 169}
 170