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