Added gr-pager component to trunk by merging from r3474:r3537 in
[debian/gnuradio] / gr-pager / src / pager_flex_deframer.cc
1 /*
2  * Copyright 2004,2006 Free Software Foundation, Inc.
3  * 
4  * This file is part of GNU Radio
5  * 
6  * GNU Radio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  * 
11  * GNU Radio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with GNU Radio; see the file COPYING.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <pager_flex_deframer.h>
27 #include <pageri_flex_modes.h>
28 #include <gr_io_signature.h>
29 #include <gr_count_bits.h>
30
31 pager_flex_deframer_sptr pager_make_flex_deframer(int rate)
32 {
33     return pager_flex_deframer_sptr(new pager_flex_deframer(rate));
34 }
35
36 // FLEX deframer block takes input from symbol stream with alphabet [0, 1, 2, 3]
37 // at specified channel rate and and outputs deinterleaved 32-bit FLEX code words 
38 // at 50, 100, or 200 code words per second (based on detected mode in sync
39 // word).
40
41 pager_flex_deframer::pager_flex_deframer(int rate) :
42     gr_block ("flex_deframer",
43               gr_make_io_signature (1, 1, sizeof(unsigned char)),
44               gr_make_io_signature (1, 1, sizeof(gr_int32))),
45     d_sync(rate/1600) // Maximum samples per baud
46 {
47     d_rate = rate;
48     set_output_multiple(1);
49     enter_idle();
50 }
51
52 void pager_flex_deframer::forecast(int noutput_items, gr_vector_int &inputs_required)
53 {
54     // samples per bit X 32 bits * number of outputs needed
55     int items = noutput_items*sizeof(gr_int32)*8*d_spb;
56     for (unsigned int i = 0; i < inputs_required.size(); i++)
57         inputs_required[i] = items;
58 }
59
60 int pager_flex_deframer::index_avg(int start, int end)
61 {
62     // modulo average
63     if (start < end)
64         return (end + start)/2;
65     else
66         return ((end + start)/2 + d_spb/2) % d_spb;
67 }
68
69 bool pager_flex_deframer::test_sync(unsigned char sym)
70 {
71     // 64-bit FLEX sync code:
72     // AAAA:BBBBBBBB:CCCC
73     //
74     // Where BBBBBBBB is always 0xA6C6AAAA
75     // and AAAA^CCCC is 0xFFFF
76     // 
77     // Specific values of AAAA determine what bps and encoding the
78     // packet is beyond the frame information word
79     //
80     // First we match on the marker field with a hamming distance < 4
81     // Then we match on the outer code with a hamming distance < 4
82
83     d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2);
84     gr_int64 val = d_sync[d_index];
85     gr_int32 marker = ((val & 0x0000FFFFFFFF0000ULL)) >> 16;
86
87     if (gr_count_bits32(marker^FLEX_SYNC_MARKER) < 4) {
88         gr_int32 code = ((val & 0xFFFF000000000000ULL) >> 32) |
89                          (val & 0x000000000000FFFFULL);
90
91         for (int i = 0; i < num_flex_modes; i++) {
92             if (gr_count_bits32(code^flex_modes[i].sync) < 4) {
93                 d_mode = i;
94                 return true;
95             }
96         }
97
98         // Marker received but doesn't match known codes
99         // All codes have high word inverted to low word
100         unsigned short high = (code & 0xFFFF0000) >> 16;
101         unsigned short low = code & 0x0000FFFF;
102         unsigned short syn = high^low;
103         if (syn == 0xFFFF)
104             fprintf(stderr, "Unknown sync code detected: %08X\n", code);
105     }
106
107     return false;
108 }
109
110 void pager_flex_deframer::enter_idle()
111 {
112     d_state = ST_IDLE;
113     d_index = 0;
114     d_start = 0;
115     d_center = 0;
116     d_end = 0;
117     d_count = 0;
118     d_mode = 0;
119     d_baudrate = 1600;
120     d_levels = 2;
121     d_spb = d_rate/d_baudrate;
122     d_hibit = false;
123     d_cdi = 0;
124     d_cdw = 0;
125     d_blk = 0;
126 }
127
128 void pager_flex_deframer::enter_syncing()
129 {
130     d_start = d_index;
131     d_state = ST_SYNCING;
132 }
133
134 void pager_flex_deframer::enter_sync1()
135 {
136     d_state = ST_SYNC1;
137     d_end = d_index;
138     d_center = index_avg(d_start, d_end);
139     d_count = 0;
140     fprintf(stderr, "SYNC1=%08X\n", flex_modes[d_mode].sync);
141 }
142
143 void pager_flex_deframer::enter_sync2()
144 {
145     d_state = ST_SYNC2;
146     d_count = 0;
147     d_baudrate = flex_modes[d_mode].baud;
148     d_levels = flex_modes[d_mode].levels;
149     d_spb = d_rate/d_baudrate;
150
151     if (d_baudrate == 3200) {
152         // Oversampling buffer just got halved
153         d_center = d_center/2;
154         d_index = d_index/2-d_spb/2; // We're here at the center of a 1600 baud bit
155         d_count = -1;                // So this hack gets us in the right place for 3200
156     }
157 }
158
159 void pager_flex_deframer::enter_data()
160 {
161     d_state = ST_DATA;
162     d_count = 0;
163 }
164
165 void pager_flex_deframer::enter_output()
166 {
167     d_state = ST_OUTPUT;
168     d_count = flex_modes[d_mode].phases*88; // Now d_count will count codewords, not bits
169     d_output_phase = 0;    // Always phase A
170     d_output_index = 0;
171 }
172
173 void pager_flex_deframer::accumulate_frames(unsigned char sym)
174 {
175     // Bits are encoded with 2-bit gray code 
176     // 
177     // SYM      Bit1 Bit2
178     // ---      ---- ----
179     //  0         1    1
180     //  1         1    0
181     //  2         0    0
182     //  3         0    1
183
184     // Codewords are interleaved in blocks of 8
185     //
186     // ABCDEFGH
187     // ABCDEFGH
188     // ABCDEFGH
189     // ABCDEFGH
190     // ...
191     // etc., for all 32 bits. So each successive incoming bit is multiplexed
192     // into a different d_frames[][], indexed by d_cdw
193
194     d_cdw = d_blk*8+d_cdi;
195     assert(d_cdw < 88);
196
197     if (d_baudrate == 1600) {
198         d_frames[0][d_cdw] <<= 1;
199         d_frames[0][d_cdw]  |= (sym < 2);
200
201         if (d_levels == 4) {
202             d_frames[1][d_cdw] <<= 1;
203             d_frames[1][d_cdw]  |= (sym == 0 || sym == 3);
204         }
205     }
206     else { 
207         if (!d_hibit) {
208             d_frames[0][d_cdw] <<= 1;
209             d_frames[0][d_cdw]  |= (sym < 2);
210
211             if (d_levels == 4) {
212                 d_frames[1][d_cdw] <<= 1;
213                 d_frames[1][d_cdw]  |= (sym == 0 || sym == 3);
214             }
215             d_hibit = true;
216         }
217         else {
218             d_frames[2][d_cdw] <<= 1;
219             d_frames[2][d_cdw]  |= (sym < 2);
220
221             if (d_levels == 4) {
222                 d_frames[3][d_cdw] <<= 1;
223                 d_frames[3][d_cdw]  |= (sym == 0 || sym == 3);
224             }
225             d_hibit = false;
226         }
227     }
228
229     d_cdi = ++d_cdi % 8;
230     if (++d_count % (d_baudrate*4/25) == 0)
231         d_blk++;    
232 }
233
234 int pager_flex_deframer::general_work(int noutput_items,
235     gr_vector_int &ninput_items,
236     gr_vector_const_void_star &input_items,
237         gr_vector_void_star &output_items)
238 {
239     const unsigned char *in = (const unsigned char *)input_items[0];
240     gr_int32 *out = (gr_int32 *)output_items[0];
241
242     int i = 0, j = 0;
243     int ninputs = ninput_items[0];
244
245     while (i < ninputs && j < noutput_items) {
246         unsigned char sym = 0;
247         if (d_state != ST_OUTPUT) {
248             sym = *in++; i++;
249             d_index = ++d_index % d_spb;
250         }
251     
252         switch (d_state) {
253             case ST_IDLE:
254                 if (test_sync(sym))
255                     enter_syncing();
256                 break;
257     
258             case ST_SYNCING:
259                 if (!test_sync(sym)) {
260                     enter_sync1();
261                     // Output sync code
262                     *out++ = flex_modes[d_mode].sync; j++;
263                 }
264                 break;
265     
266             case ST_SYNC1:
267                 if (d_index == d_center) {
268                     d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2);
269                     if (++d_count == 48) { // Skip 16 bits of dotting
270                         // Output frame information word
271                         *out++ = (gr_int32)(d_sync[d_index] & 0x00000000FFFFFFFFULL); j++;
272                         enter_sync2();
273                     }
274                 }
275                 break;
276     
277             case ST_SYNC2:
278                 if (d_index == d_center) {
279                     // Skip 25 ms = 40 bits @ 1600 bps, 80 @ 3200 bps
280                     if (++d_count == d_baudrate/40)
281                         enter_data();
282                 }
283                 break;
284     
285             case ST_DATA:
286                 if (d_index == d_center) {
287                     accumulate_frames(sym);
288                     if (d_count == d_baudrate*1760/1000)
289                         enter_output();
290                 }
291                 break;
292
293             case ST_OUTPUT:
294                 output_codeword(out++); j++;
295                 if (--d_count == 0)
296                     enter_idle();
297                 break;
298
299             default:
300                 assert(0); // memory corruption of d_state if ever gets here
301                 break;
302
303         }
304     }
305
306     consume_each(i);
307     return j;
308 }
309
310 void pager_flex_deframer::output_codeword(gr_int32 *out)
311 {
312     *out = d_frames[d_output_phase][d_output_index++];
313    
314     if (d_output_index == 88) {
315         d_output_index = 0;
316         d_output_phase++;
317         if (d_output_phase == 1 && !flex_modes[d_mode].phase_b)
318             d_output_phase++;
319         if (d_output_phase == 2 && !flex_modes[d_mode].phase_c)
320             d_output_phase++;
321         if (d_output_phase == 3 && !flex_modes[d_mode].phase_d)
322             d_output_phase++;
323     }
324 }