Imported Upstream version 3.2.2
[debian/gnuradio] / gr-pager / src / pager_flex_sync.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 3, 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_sync.h>
27 #include <pageri_flex_modes.h>
28 #include <pageri_bch3221.h>
29 #include <pageri_util.h>
30 #include <gr_io_signature.h>
31 #include <gr_count_bits.h>
32 #include <cstdio>
33
34 pager_flex_sync_sptr pager_make_flex_sync()
35 {
36     return pager_flex_sync_sptr(new pager_flex_sync());
37 }
38
39 // FLEX sync block takes input from sliced baseband stream [0-3] at specified 
40 // channel rate.  Symbol timing is established based on receiving one of the
41 // defined FLEX protocol synchronization words.  The block outputs one FLEX frame
42 // worth of bits on each output phase for the data portion of the frame. Unused phases
43 // get all zeros, which are considered idle code words.
44
45 pager_flex_sync::pager_flex_sync() :
46     gr_block ("flex_sync",
47     gr_make_io_signature (1, 1, sizeof(unsigned char)),
48     gr_make_io_signature (4, 4, sizeof(unsigned char))),
49     d_sync(10) // Fixed at 10 samples per baud (@ 1600 baud)
50 {
51     enter_idle();
52 }
53
54 void pager_flex_sync::forecast(int noutput_items, gr_vector_int &inputs_required)
55 {
56     // samples per bit X number of outputs needed
57     int items = noutput_items*d_spb;
58     for (unsigned int i = 0; i < inputs_required.size(); i++)
59         inputs_required[i] = items;
60 }
61
62 int pager_flex_sync::index_avg(int start, int end)
63 {
64     // modulo average
65     if (start < end)
66         return (end + start)/2;
67     else
68         return ((end + start)/2 + d_spb/2) % d_spb;
69 }
70
71 bool pager_flex_sync::test_sync(unsigned char sym)
72 {
73     // 64-bit FLEX sync code:
74     // AAAA:BBBBBBBB:CCCC
75     //
76     // Where BBBBBBBB is always 0xA6C6AAAA
77     // and AAAA^CCCC is 0xFFFF
78     // 
79     // Specific values of AAAA determine what bps and encoding the
80     // packet is beyond the frame information word
81     //
82     // First we match on the marker field with a hamming distance < 4
83     // Then we match on the outer code with a hamming distance < 4
84
85     d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2);
86     gr_int64 val = d_sync[d_index];
87     gr_int32 marker = ((val & 0x0000FFFFFFFF0000ULL)) >> 16;
88
89     if (gr_count_bits32(marker^FLEX_SYNC_MARKER) < 4) {
90         gr_int32 code = ((val & 0xFFFF000000000000ULL) >> 32) |
91                          (val & 0x000000000000FFFFULL);
92
93         for (int i = 0; i < num_flex_modes; i++) {
94             if (gr_count_bits32(code^flex_modes[i].sync) < 4) {
95                 d_mode = i;
96                 return true;
97             }
98         }
99
100         // Marker received but doesn't match known codes
101         // All codes have high word inverted to low word
102         unsigned short high = (code & 0xFFFF0000) >> 16;
103         unsigned short low = code & 0x0000FFFF;
104         unsigned short syn = high^low;
105         if (syn == 0xFFFF)
106             fprintf(stderr, "Unknown sync code detected: %08X\n", code);
107     }
108
109     return false;
110 }
111
112 void pager_flex_sync::enter_idle()
113 {
114     d_state = ST_IDLE;
115     d_index = 0;
116     d_start = 0;
117     d_center = 0;
118     d_end = 0;
119     d_count = 0;
120     d_mode = 0;
121     d_baudrate = 1600;
122     d_levels = 2;
123     d_spb = 16000/d_baudrate;
124     d_bit_a = 0;
125     d_bit_b = 0;
126     d_bit_c = 0;
127     d_bit_d = 0;
128     d_hibit = false;
129     fflush(stdout);
130 }
131
132 void pager_flex_sync::enter_syncing()
133 {
134     d_start = d_index;
135     d_state = ST_SYNCING;
136 }
137
138 void pager_flex_sync::enter_sync1()
139 {
140     d_state = ST_SYNC1;
141     d_end = d_index;
142     d_center = index_avg(d_start, d_end); // Center of goodness
143     d_count = 0;
144 }
145
146 void pager_flex_sync::enter_sync2()
147 {
148     d_state = ST_SYNC2;
149     d_count = 0;
150     d_baudrate = flex_modes[d_mode].baud;
151     d_levels = flex_modes[d_mode].levels;
152     d_spb = 16000/d_baudrate;
153
154     if (d_baudrate == 3200) {
155         // Oversampling buffer just got halved
156         d_center = d_center/2;
157
158         // We're here at the center of a 1600 baud bit
159         // So this hack puts the index and bit counter
160         // in the right place for 3200 bps.
161         d_index = d_index/2-d_spb/2;         
162         d_count = -1;                
163     }                                
164 }
165
166 void pager_flex_sync::enter_data()
167 {
168     d_state = ST_DATA;
169     d_count = 0;
170 }
171
172 void pager_flex_sync::parse_fiw()
173 {
174     // Nothing is done with these now, but these will end up getting
175     // passed as metadata when mblocks are available
176
177     // Bits 31-28 are frame number related, but unknown function
178     // This might be a checksum
179     d_unknown2 = pageri_reverse_bits8((d_fiw >> 24) & 0xF0);
180         
181     // Cycle is bits 27-24, reversed
182     d_cycle = pageri_reverse_bits8((d_fiw >> 20) & 0xF0);
183
184     // Frame is bits 23-17, reversed
185     d_frame = pageri_reverse_bits8((d_fiw >> 16) & 0xFE);
186
187     // Bits 16-11 are some sort of marker, usually identical across
188     // many frames but sometimes changes between frames or modes
189     d_unknown1 = (d_fiw >> 11) & 0x3F;
190
191     //printf("CYC:%02i FRM:%03i\n", d_cycle, d_frame);
192 }
193
194 int pager_flex_sync::output_symbol(unsigned char sym)
195 {
196     // Here is where we output a 1 or 0 on each phase according
197     // to current FLEX mode and symbol value.  Unassigned phases
198     // are zero from the enter_idle() initialization.
199     //
200     // FLEX can transmit the data portion of the frame at either
201     // 1600 bps or 3200 bps, and can use either two- or four-level
202     // FSK encoding.
203     //
204     // At 1600 bps, 2-level, a single "phase" is transmitted with bit
205     // value '0' using level '3' and bit value '1' using level '0'.
206     //
207     // At 1600 bps, 4-level, a second "phase" is transmitted, and the 
208     // di-bits are encoded with a gray code:
209     //
210     // Symbol   Phase 1  Phase 2
211     // ------   -------  -------
212     //   0         1        1
213     //   1         1        0
214     //   2         0        0
215     //   3         0        1
216     //
217     // At 1600 bps, 4-level, these are called PHASE A and PHASE B.
218     //
219     // At 3200 bps, the same 1 or 2 bit encoding occurs, except that
220     // additionally two streams are interleaved on alternating symbols.
221     // Thus, PHASE A (and PHASE B if 4-level) are decoded on one symbol,
222     // then PHASE C (and PHASE D if 4-level) are decoded on the next.
223     
224     int bits = 0;
225     
226     if (d_baudrate == 1600) {
227         d_bit_a = (sym < 2);
228         if (d_levels == 4)
229             d_bit_b = (sym == 0) || (sym == 3);
230
231         *d_phase_a++ = d_bit_a;
232         *d_phase_b++ = d_bit_b;
233         *d_phase_c++ = d_bit_c;
234         *d_phase_d++ = d_bit_d;
235         bits++;
236     }
237     else {
238         if (!d_hibit) {
239             d_bit_a = (sym < 2);
240             if (d_levels == 4)
241                 d_bit_b = (sym == 0) || (sym == 3);
242             d_hibit = true;
243         }
244         else {
245             d_bit_c = (sym < 2);
246             if (d_levels == 4)
247                 d_bit_d = (sym == 0) || (sym == 3);
248             d_hibit = false;
249
250             *d_phase_a++ = d_bit_a;
251             *d_phase_b++ = d_bit_b;
252             *d_phase_c++ = d_bit_c;
253             *d_phase_d++ = d_bit_d;
254             bits++;
255         }
256     }
257
258     return bits;
259 }
260
261 int pager_flex_sync::general_work(int noutput_items,
262     gr_vector_int &ninput_items,
263     gr_vector_const_void_star &input_items,
264     gr_vector_void_star &output_items)
265 {
266     const unsigned char *in = (const unsigned char *)input_items[0];
267     d_phase_a = (unsigned char *)output_items[0];
268     d_phase_b = (unsigned char *)output_items[1];
269     d_phase_c = (unsigned char *)output_items[2];
270     d_phase_d = (unsigned char *)output_items[3];
271
272     int i = 0, j = 0;
273     int ninputs = ninput_items[0];
274
275     while (i < ninputs && j < noutput_items) {
276         unsigned char sym = *in++; i++;
277         d_index = ++d_index % d_spb;
278     
279         switch (d_state) {
280             case ST_IDLE:
281                 // Continually compare the received symbol stream
282                 // against the known FLEX sync words.
283                 if (test_sync(sym))
284                     enter_syncing();
285                 break;
286     
287             case ST_SYNCING:
288                 // Wait until we stop seeing sync, then calculate
289                 // the center of the bit period (d_center)
290                 if (!test_sync(sym))
291                     enter_sync1();
292                 break;
293     
294             case ST_SYNC1:
295                 // Skip 16 bits of dotting, then accumulate 32 bits
296                 // of Frame Information Word.
297                 if (d_index == d_center) {
298                     d_fiw = (d_fiw << 1) | (sym > 1);
299                     if (++d_count == 48) {
300                         // FIW is accumulated, call BCH to error correct it
301                         pageri_bch3221(d_fiw);
302                         parse_fiw();
303                         enter_sync2();  
304                     }
305                 }
306                 break;
307     
308             case ST_SYNC2:
309                 // This part and the remainder of the frame are transmitted
310                 // at either 1600 bps or 3200 bps based on the received
311                 // FLEX sync word. The second SYNC header is 25ms of idle bits
312                 // at either speed.
313                 if (d_index == d_center) {
314                     // Skip 25 ms = 40 bits @ 1600 bps, 80 @ 3200 bps
315                     if (++d_count == d_baudrate/40)
316                         enter_data();
317                 }
318                 break;
319     
320             case ST_DATA:
321                 // The data portion of the frame is 1760 ms long at either 
322                 // baudrate.  This is 2816 bits @ 1600 bps and 5632 bits @ 3200 bps.
323                 // The output_symbol() routine decodes and doles out the bits
324                 // to each of the four transmitted phases of FLEX interleaved codes.
325                 if (d_index == d_center) {
326                     j += output_symbol(sym);                
327                     if (++d_count == d_baudrate*1760/1000)
328                         enter_idle();
329                 }
330                 break;
331
332             default:
333                 assert(0); // memory corruption of d_state if ever gets here
334                 break;
335         }
336     }
337
338     consume_each(i);
339     return j;
340 }