summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-05-10 18:57:13 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2012-05-31 19:04:38 +0200
commitf7b2e3153b8ee1ca925da9ff99df863987bb2ec1 (patch)
tree13e498a431abe2ba7c6b9cc4bfb10a6e3f27ea85 /firmware/drivers
parentcc59ea453d0a1a53808bbe967d4dbfb2f670cb75 (diff)
downloadrockbox-f7b2e3153b8ee1ca925da9ff99df863987bb2ec1.tar.gz
rockbox-f7b2e3153b8ee1ca925da9ff99df863987bb2ec1.zip
rds: implement more robust PS/RT parsing
Our current PS and RT parser is very strict: it requires all segments to be received in order. This is too strong of an assumption even when the reception in good, particularly for long RT messages. This parser handles segments in any order and completes a message only when all segments are present. To avoid keeping obsolete segments, each segment has an associated timeout and is trashed if not updated for a certain period. Change-Id: I79841bb5ab1f838c7702d8281044e226f6510199 Reviewed-on: http://gerrit.rockbox.org/237 Tested-by: Bertrik Sikken <bertrik@sikken.nl> Reviewed-by: Bertrik Sikken <bertrik@sikken.nl>
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/rds.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/firmware/drivers/rds.c b/firmware/drivers/rds.c
index eb14cfb009..df766094de 100644
--- a/firmware/drivers/rds.c
+++ b/firmware/drivers/rds.c
@@ -22,20 +22,27 @@
22#include <stdint.h> 22#include <stdint.h>
23#include <string.h> 23#include <string.h>
24#include <strlcpy.h> 24#include <strlcpy.h>
25#include <kernel.h>
25#include "rds.h" 26#include "rds.h"
26#include "time.h" 27#include "time.h"
27 28
29// timeout before segment obsolescence
30#define PS_SEGMENT_TIMEOUT (HZ / 2)
31#define RT_SEGMENT_TIMEOUT (10 * HZ)
32
28/* programme identification */ 33/* programme identification */
29static uint16_t pi_code; 34static uint16_t pi_code;
30static uint16_t pi_last; 35static uint16_t pi_last;
31/* program service name */ 36/* program service name */
32static char ps_data[9]; 37static char ps_data[9];
33static char ps_copy[9]; 38static char ps_copy[9];
34static int ps_segment; 39static long ps_segment_timeout[4];
40static int ps_segment;// bitmap of received segments
35/* radio text */ 41/* radio text */
36static char rt_data[65]; 42static char rt_data[65];
37static char rt_copy[65]; 43static char rt_copy[65];
38static int rt_segment; 44static long rt_segment_timeout[16];
45static int rt_segment;// bitmap of received segments
39static int rt_abflag; 46static int rt_abflag;
40/* date/time */ 47/* date/time */
41static time_t ct_data; 48static time_t ct_data;
@@ -95,22 +102,21 @@ static bool handle_group0(uint16_t data[4])
95{ 102{
96 int segment, pos; 103 int segment, pos;
97 104
98 segment = data[1] & 3; 105 /* remove obsolete segments */
106 for(int i = 0; i < 4; i++)
107 if(TIME_AFTER(current_tick, ps_segment_timeout[i]))
108 ps_segment &= ~(1 << i);
99 109
100 /* reset parsing if not in expected order */ 110 segment = data[1] & 3;
101 if (segment != ps_segment) {
102 ps_segment = 0;
103 if (segment != 0) {
104 return false;
105 }
106 }
107 111
108 /* store data */ 112 /* store data */
109 pos = segment * 2; 113 pos = segment * 2;
110 ps_data[pos++] = (data[3] >> 8) & 0xFF; 114 ps_data[pos++] = (data[3] >> 8) & 0xFF;
111 ps_data[pos++] = (data[3] >> 0) & 0xFF; 115 ps_data[pos++] = (data[3] >> 0) & 0xFF;
112 if (++ps_segment == 4) { 116 ps_segment |= 1 << segment;
113 ps_data[pos] = '\0'; 117 ps_segment_timeout[segment] = current_tick + PS_SEGMENT_TIMEOUT;
118 if (ps_segment == 0xf) {
119 ps_data[8] = '\0';
114 if (strcmp(ps_copy, ps_data) != 0) { 120 if (strcmp(ps_copy, ps_data) != 0) {
115 /* we got an updated message */ 121 /* we got an updated message */
116 strcpy(ps_copy, ps_data); 122 strcpy(ps_copy, ps_data);
@@ -143,21 +149,25 @@ static bool handle_group2(uint16_t data[4])
143{ 149{
144 int abflag, segment, version, pos; 150 int abflag, segment, version, pos;
145 bool done; 151 bool done;
152
153 /* remove obsolete segments */
154 for(int i = 0; i < 16; i++)
155 if(TIME_AFTER(current_tick, rt_segment_timeout[i]))
156 rt_segment &= ~(1 << i);
146 157
147 /* reset parsing if not in expected order */ 158 /* reset parsing if the message type changed */
148 abflag = (data[1] >> 4) & 1; 159 abflag = (data[1] >> 4) & 1;
149 segment = data[1] & 0xF; 160 segment = data[1] & 0xF;
150 if ((abflag != rt_abflag) || (segment != rt_segment)) { 161 if (abflag != rt_abflag) {
151 rt_abflag = abflag; 162 rt_abflag = abflag;
152 rt_segment = 0; 163 rt_segment = 0;
153 if (segment != 0) {
154 return false;
155 }
156 } 164 }
157 165
166 rt_segment |= 1 << segment;
167 rt_segment_timeout[segment] = current_tick + RT_SEGMENT_TIMEOUT;
168
158 /* store data */ 169 /* store data */
159 version = (data[1] >> 11) & 1; 170 version = (data[1] >> 11) & 1;
160 done = false;
161 if (version == 0) { 171 if (version == 0) {
162 pos = segment * 4; 172 pos = segment * 4;
163 done = done || handle_rt(pos++, (data[2] >> 8) & 0xFF); 173 done = done || handle_rt(pos++, (data[2] >> 8) & 0xFF);
@@ -169,7 +179,10 @@ static bool handle_group2(uint16_t data[4])
169 done = done || handle_rt(pos++, (data[3] >> 8) & 0xFF); 179 done = done || handle_rt(pos++, (data[3] >> 8) & 0xFF);
170 done = done || handle_rt(pos++, (data[3] >> 0) & 0xFF); 180 done = done || handle_rt(pos++, (data[3] >> 0) & 0xFF);
171 } 181 }
172 if ((++rt_segment == 16) || done) { 182 /* there are two cases for completion:
183 * - we got all 16 segments
184 * - we found a end of line AND we got all segments before it */
185 if (rt_segment == 0xffff || (done && rt_segment == (1 << segment) - 1)) {
173 rt_data[pos] = '\0'; 186 rt_data[pos] = '\0';
174 if (strcmp(rt_copy, rt_data) != 0) { 187 if (strcmp(rt_copy, rt_data) != 0) {
175 /* we got an updated message */ 188 /* we got an updated message */