1 /*
2 * Copyright (C) 2014 Bastian Bloessl <bloessl@ccs-labs.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define dout debug && std::cout
19 #define lout log && std::cout
20
21 #include "decoder_impl.h"
22 #include "constants.h"
23 #include <gnuradio/io_signature.h>
24
25 using namespace gr::rds;
26
27 decoder::sptr
make(bool log,bool debug)28 decoder::make(bool log, bool debug) {
29 return gnuradio::get_initial_sptr(new decoder_impl(log, debug));
30 }
31
decoder_impl(bool log,bool debug)32 decoder_impl::decoder_impl(bool log, bool debug)
33 : gr::sync_block ("gr_rds_decoder",
34 gr::io_signature::make (1, 1, sizeof(char)),
35 gr::io_signature::make (0, 0, 0)),
36 log(log),
37 debug(debug)
38 {
39 set_output_multiple(104); // 1 RDS datagroup = 104 bits
40 message_port_register_out(pmt::mp("out"));
41 enter_no_sync();
42 }
43
~decoder_impl()44 decoder_impl::~decoder_impl() {
45 }
46
47
48 ////////////////////////// HELPER FUNCTIONS /////////////////////////
49
enter_no_sync()50 void decoder_impl::enter_no_sync() {
51 presync = false;
52 d_state = NO_SYNC;
53 }
54
enter_sync(unsigned int sync_block_number)55 void decoder_impl::enter_sync(unsigned int sync_block_number) {
56 wrong_blocks_counter = 0;
57 blocks_counter = 0;
58 block_bit_counter = 0;
59 block_number = (sync_block_number + 1) % 4;
60 group_assembly_started = false;
61 d_state = SYNC;
62 }
63
64 /* see Annex B, page 64 of the standard */
calc_syndrome(unsigned long message,unsigned char mlen)65 unsigned int decoder_impl::calc_syndrome(unsigned long message,
66 unsigned char mlen) {
67 unsigned long reg = 0;
68 unsigned int i;
69 const unsigned long poly = 0x5B9;
70 const unsigned char plen = 10;
71
72 for (i = mlen; i > 0; i--) {
73 reg = (reg << 1) | ((message >> (i-1)) & 0x01);
74 if (reg & (1 << plen)) reg = reg ^ poly;
75 }
76 for (i = plen; i > 0; i--) {
77 reg = reg << 1;
78 if (reg & (1<<plen)) reg = reg ^ poly;
79 }
80 return (reg & ((1<<plen)-1)); // select the bottom plen bits of reg
81 }
82
decode_group(unsigned int * group)83 void decoder_impl::decode_group(unsigned int *group) {
84 // raw data bytes, as received from RDS.
85 // 8 info bytes, followed by 4 RDS offset chars: ABCD/ABcD/EEEE (in US)
86 unsigned char bytes[12];
87
88 // RDS information words
89 bytes[0] = (group[0] >> 8U) & 0xffU;
90 bytes[1] = (group[0] ) & 0xffU;
91 bytes[2] = (group[1] >> 8U) & 0xffU;
92 bytes[3] = (group[1] ) & 0xffU;
93 bytes[4] = (group[2] >> 8U) & 0xffU;
94 bytes[5] = (group[2] ) & 0xffU;
95 bytes[6] = (group[3] >> 8U) & 0xffU;
96 bytes[7] = (group[3] ) & 0xffU;
97
98 // RDS offset words
99 bytes[8] = offset_chars[0];
100 bytes[9] = offset_chars[1];
101 bytes[10] = offset_chars[2];
102 bytes[11] = offset_chars[3];
103
104 pmt::pmt_t data(pmt::make_blob(bytes, 12));
105 pmt::pmt_t meta(pmt::PMT_NIL);
106
107 pmt::pmt_t pdu(pmt::cons(meta, data)); // make PDU: (metadata, data) pair
108 message_port_pub(pmt::mp("out"), pdu);
109 }
110
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)111 int decoder_impl::work (int noutput_items,
112 gr_vector_const_void_star &input_items,
113 gr_vector_void_star &output_items)
114 {
115 const bool *in = (const bool *) input_items[0];
116 (void) output_items;
117
118 dout << "RDS data decoder at work: input_items = "
119 << noutput_items << ", /104 = "
120 << noutput_items / 104 << std::endl;
121
122 int i=0,j;
123 unsigned long bit_distance, block_distance;
124 unsigned int block_calculated_crc, block_received_crc, checkword,dataword;
125 unsigned int reg_syndrome;
126 unsigned char offset_char('x'); // x = error while decoding the word offset
127
128 /* the synchronization process is described in Annex C, page 66 of the standard */
129 while (i<noutput_items) {
130 reg=(reg<<1)|in[i]; // reg contains the last 26 rds bits
131 switch (d_state) {
132 case NO_SYNC:
133 reg_syndrome = calc_syndrome(reg,26);
134 for (j=0;j<5;j++) {
135 if (reg_syndrome==syndrome[j]) {
136 if (!presync) {
137 lastseen_offset=j;
138 lastseen_offset_counter=bit_counter;
139 presync=true;
140 }
141 else {
142 bit_distance=bit_counter-lastseen_offset_counter;
143 if (offset_pos[lastseen_offset]>=offset_pos[j])
144 block_distance=offset_pos[j]+4-offset_pos[lastseen_offset];
145 else
146 block_distance=offset_pos[j]-offset_pos[lastseen_offset];
147 if ((block_distance*26)!=bit_distance) presync=false;
148 else {
149 lout << "@@@@@ Sync State Detected" << std::endl;
150 enter_sync(j);
151 }
152 }
153 break; //syndrome found, no more cycles
154 }
155 }
156 break;
157 case SYNC:
158 /* wait until 26 bits enter the buffer */
159 if (block_bit_counter<25) block_bit_counter++;
160 else {
161 good_block=false;
162 dataword=(reg>>10) & 0xffff;
163 block_calculated_crc=calc_syndrome(dataword,16);
164 checkword=reg & 0x3ff;
165 /* manage special case of C or C' offset word */
166 if (block_number==2) {
167 block_received_crc=checkword^offset_word[block_number];
168 if (block_received_crc==block_calculated_crc) {
169 good_block=true;
170 offset_char = 'C';
171 } else {
172 block_received_crc=checkword^offset_word[4];
173 if (block_received_crc==block_calculated_crc) {
174 good_block=true;
175 offset_char = 'c'; // C' (C-Tag)
176 } else {
177 wrong_blocks_counter++;
178 good_block=false;
179 }
180 }
181 }
182 else {
183 block_received_crc=checkword^offset_word[block_number];
184 if (block_received_crc==block_calculated_crc) {
185 good_block=true;
186 if (block_number==0) offset_char = 'A';
187 else if (block_number==1) offset_char = 'B';
188 else if (block_number==3) offset_char = 'D';
189 } else {
190 wrong_blocks_counter++;
191 good_block=false;
192 }
193 }
194 /* done checking CRC */
195 if (block_number==0 && good_block) {
196 group_assembly_started=true;
197 group_good_blocks_counter=1;
198 }
199 if (group_assembly_started) {
200 if (!good_block) group_assembly_started=false;
201 else {
202 group[block_number]=dataword;
203 offset_chars[block_number] = offset_char;
204 group_good_blocks_counter++;
205 }
206 if (group_good_blocks_counter==5) decode_group(group);
207 }
208 block_bit_counter=0;
209 block_number=(block_number+1) % 4;
210 blocks_counter++;
211 /* 1187.5 bps / 104 bits = 11.4 groups/sec, or 45.7 blocks/sec */
212 if (blocks_counter==50) {
213 if (wrong_blocks_counter>35) {
214 lout << "@@@@@ Lost Sync (Got " << wrong_blocks_counter
215 << " bad blocks on " << blocks_counter
216 << " total)" << std::endl;
217 enter_no_sync();
218 } else {
219 lout << "@@@@@ Still Sync-ed (Got " << wrong_blocks_counter
220 << " bad blocks on " << blocks_counter
221 << " total)" << std::endl;
222 }
223 blocks_counter=0;
224 wrong_blocks_counter=0;
225 }
226 }
227 break;
228 default:
229 d_state=NO_SYNC;
230 break;
231 }
232 i++;
233 bit_counter++;
234 }
235 return noutput_items;
236 }
237