summaryrefslogtreecommitdiff
path: root/firmware/drivers/rds.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/rds.c')
-rw-r--r--firmware/drivers/rds.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/firmware/drivers/rds.c b/firmware/drivers/rds.c
new file mode 100644
index 0000000000..09bc33807c
--- /dev/null
+++ b/firmware/drivers/rds.c
@@ -0,0 +1,192 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (c) 2011 by Bertrik Sikken
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdbool.h>
22#include <stdint.h>
23#include <string.h>
24#include <strlcpy.h>
25#include "rds.h"
26
27/* programme identification */
28static uint16_t pi;
29/* program service name */
30static char ps_data[9];
31static char ps_copy[9];
32static int ps_segment;
33/* radio text */
34static char rt_data[65];
35static char rt_copy[65];
36static int rt_segment;
37static int rt_abflag;
38
39/* resets the rds parser */
40void rds_reset(void)
41{
42 ps_copy[0] = '\0';
43 ps_segment = 0;
44 rt_copy[0] = '\0';
45 rt_segment = 0;
46 pi = 0;
47}
48
49/* initialises the rds parser */
50void rds_init(void)
51{
52 rds_reset();
53}
54
55/* handles a group 0 packet, returns true if a new message was received */
56static bool handle_group0(uint16_t data[4])
57{
58 int segment, pos;
59
60 segment = data[1] & 3;
61
62 /* reset parsing if not in expected order */
63 if (segment != ps_segment) {
64 ps_segment = 0;
65 if (segment != 0) {
66 return false;
67 }
68 }
69
70 /* store data */
71 pos = segment * 2;
72 ps_data[pos++] = (data[3] >> 8) & 0xFF;
73 ps_data[pos++] = (data[3] >> 0) & 0xFF;
74 if (++ps_segment == 4) {
75 ps_data[pos] = '\0';
76 if (strcmp(ps_copy, ps_data) != 0) {
77 /* we got an updated message */
78 strcpy(ps_copy, ps_data);
79 return true;
80 }
81 }
82 return false;
83}
84
85/* handles a radio text characters, returns true if end-of-line found */
86static bool handle_rt(int pos, char c)
87{
88 switch (c) {
89 case 0x0A:
90 /* line break hint */
91 rt_data[pos] = ' ';
92 return false;
93 case 0x0D:
94 /* end of line */
95 rt_data[pos] = '\0';
96 return true;
97 default:
98 rt_data[pos] = c;
99 return false;
100 }
101}
102
103/* handles a group 2 packet, returns true if a new message was received */
104static bool handle_group2(uint16_t data[4])
105{
106 int abflag, segment, version, pos;
107 bool done;
108
109 /* reset parsing if not in expected order */
110 abflag = (data[1] >> 4) & 1;
111 segment = data[1] & 0xF;
112 if ((abflag != rt_abflag) || (segment != rt_segment)) {
113 rt_abflag = abflag;
114 rt_segment = 0;
115 if (segment != 0) {
116 return false;
117 }
118 }
119
120 /* store data */
121 version = (data[1] >> 11) & 1;
122 done = false;
123 if (version == 0) {
124 pos = segment * 4;
125 done = done || handle_rt(pos++, (data[2] >> 8) & 0xFF);
126 done = done || handle_rt(pos++, (data[2] >> 0) & 0xFF);
127 done = done || handle_rt(pos++, (data[3] >> 8) & 0xFF);
128 done = done || handle_rt(pos++, (data[3] >> 0) & 0xFF);
129 } else {
130 pos = segment * 2;
131 done = done || handle_rt(pos++, (data[3] >> 8) & 0xFF);
132 done = done || handle_rt(pos++, (data[3] >> 0) & 0xFF);
133 }
134 if ((++rt_segment == 16) || done) {
135 rt_data[pos] = '\0';
136 if (strcmp(rt_copy, rt_data) != 0) {
137 /* we got an updated message */
138 strcpy(rt_copy, rt_data);
139 return true;
140 }
141 }
142
143 return false;
144}
145
146/* processes one rds packet, returns true if a new message was received */
147bool rds_process(uint16_t data[4])
148{
149 int group;
150
151 /* get programme identification */
152 if (pi == 0) {
153 pi = data[0];
154 }
155
156 /* handle rds data based on group */
157 group = (data[1] >> 11) & 0x1F;
158 switch (group) {
159
160 case 0: /* group 0A: basic info */
161 case 1: /* group 0B: basic info */
162 return handle_group0(data);
163
164 case 4: /* group 2A: radio text */
165 case 5: /* group 2B: radio text */
166 return handle_group2(data);
167
168 default:
169 break;
170 }
171
172 return false;
173}
174
175/* returns the programme identification code */
176uint16_t rds_get_pi(void)
177{
178 return pi;
179}
180
181/* returns the most recent valid programme service name */
182char* rds_get_ps(void)
183{
184 return ps_copy;
185}
186
187/* returns the most recent valid RadioText message */
188char* rds_get_rt(void)
189{
190 return rt_copy;
191}
192