Imported Upstream version 3.2.2
[debian/gnuradio] / gr-pager / src / pager_flex_parse.cc
1 /*
2  * Copyright 2004,2006,2007 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_parse.h>
27 #include <pageri_bch3221.h>
28 #include <gr_io_signature.h>
29 #include <ctype.h>
30 #include <iostream>
31 #include <iomanip>
32
33 pager_flex_parse_sptr pager_make_flex_parse(gr_msg_queue_sptr queue, float freq)
34 {
35     return pager_flex_parse_sptr(new pager_flex_parse(queue, freq));
36 }
37
38 pager_flex_parse::pager_flex_parse(gr_msg_queue_sptr queue, float freq) :
39     gr_sync_block("flex_parse",
40     gr_make_io_signature(1, 1, sizeof(gr_int32)),
41     gr_make_io_signature(0, 0, 0)),
42     d_queue(queue),
43     d_freq(freq)
44 {
45     d_count = 0;
46 }
47
48 int pager_flex_parse::work(int noutput_items,
49     gr_vector_const_void_star &input_items,
50     gr_vector_void_star &output_items)
51 {
52     const gr_int32 *in = (const gr_int32 *)input_items[0];
53     
54     int i = 0;
55     while (i < noutput_items) {
56         // Accumulate one whole frame's worth of data words (88 of them)
57         d_datawords[d_count] = *in++; i++;
58         if (++d_count == 88) {
59             parse_data();
60             d_count = 0;
61         }
62     }
63
64     return i;
65 }
66
67 /* FLEX data frames (that is, 88 data words per phase recovered after sync,
68    symbol decoding, dephasing, deinterleaving, error correction, and conversion
69    from codewords to data words) start with a block information word containing
70    indices of the page address field and page vector fields.
71 */
72
73 void pager_flex_parse::parse_capcode(gr_int32 aw1, gr_int32 aw2)
74 {
75     d_laddr = (aw1 < 0x008001L) ||
76               (aw1 > 0x1E0000L) ||
77               (aw1 > 0x1E7FFEL);        
78     
79     if (d_laddr)
80         d_capcode = aw1+((aw2^0x001FFFFF)<<15)+0x1F9000;  // Don't ask
81     else
82         d_capcode = aw1-0x8000;
83 }
84
85 void pager_flex_parse::parse_data()
86 {
87     // Block information word is the first data word in frame
88     gr_int32 biw = d_datawords[0];
89
90     // Nothing to see here, please move along
91     if (biw == 0 || biw == 0x001FFFFF)
92         return;
93
94     // Vector start index is bits 15-10
95     // Address start address is bits 9-8, plus one for offset
96     int voffset = (biw >> 10) & 0x3f;
97     int aoffset = ((biw >> 8) & 0x03) + 1;
98     
99     //printf("BIW:%08X AW:%02i-%02i\n", biw, aoffset, voffset);
100
101     // Iterate through pages and dispatch to appropriate handler
102     for (int i = aoffset; i < voffset; i++) {
103         int j = voffset+i-aoffset;              // Start of vector field for address @ i
104
105         if (d_datawords[i] == 0x00000000 ||
106             d_datawords[i] == 0x001FFFFF)
107             continue;                           // Idle codewords, invalid address
108
109         parse_capcode(d_datawords[i], d_datawords[i+1]);
110         if (d_laddr)
111            i++;
112                            
113         if (d_capcode < 0)                      // Invalid address, skip
114           continue;        
115
116         // Parse vector information word for address @ offset 'i'
117         gr_int32 viw = d_datawords[j];
118         d_type = (page_type_t)((viw >> 4) & 0x00000007);
119         int mw1 = (viw >> 7) & 0x00000007F;
120         int len = (viw >> 14) & 0x0000007F;
121
122         if (is_numeric_page(d_type))
123             len &= 0x07;
124         int mw2 = mw1+len;
125             
126         if (mw1 == 0 && mw2 == 0)
127             continue;                           // Invalid VIW
128
129         if (is_tone_page(d_type))
130             mw1 = mw2 = 0;
131
132         if (mw1 > 87 || mw2 > 87)
133             continue;                           // Invalid offsets
134
135         d_payload.str("");
136         d_payload.setf(std::ios::showpoint);
137         d_payload << std::setprecision(6) << std::setw(7)
138                   << d_freq/1e6 << FIELD_DELIM 
139                   << std::setw(10) << d_capcode << FIELD_DELIM
140                   << flex_page_desc[d_type] << FIELD_DELIM;
141
142         if (is_alphanumeric_page(d_type))
143             parse_alphanumeric(mw1, mw2-1, j);
144         else if (is_numeric_page(d_type))
145             parse_numeric(mw1, mw2, j);
146         else if (is_tone_page(d_type))
147             parse_tone_only();
148         else
149             parse_unknown(mw1, mw2);
150
151         gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
152         d_queue->handle(msg);
153     }
154 }
155
156 void pager_flex_parse::parse_alphanumeric(int mw1, int mw2, int j)
157 {
158     int frag;
159     bool cont;
160
161     if (!d_laddr) {
162         frag = (d_datawords[mw1] >> 11) & 0x03;
163         cont = (d_datawords[mw1] >> 10) & 0x01;
164         mw1++;
165     }
166     else {
167         frag = (d_datawords[j+1] >> 11) & 0x03;
168         cont = (d_datawords[j+1] >> 10) & 0x01;
169         mw2--;
170     }    
171
172     //d_payload << frag << FIELD_DELIM;
173     //d_payload << cont << FIELD_DELIM;
174
175     for (int i = mw1; i <= mw2; i++) {
176         gr_int32 dw = d_datawords[i];
177         unsigned char ch;
178         
179         if (i > mw1 || frag != 0x03) {
180             ch = dw & 0x7F;
181             if (ch != 0x03)
182                 d_payload << ch;
183         }
184         
185         ch = (dw >> 7) & 0x7F;
186         if (ch != 0x03) // Fill
187             d_payload << ch;
188                 
189         ch = (dw >> 14) & 0x7F;
190         if (ch != 0x03) // Fill
191             d_payload << ch;
192     }
193 }
194
195 void pager_flex_parse::parse_numeric(int mw1, int mw2, int j)
196 {
197     // Get first dataword from message field or from second
198     // vector word if long address
199     gr_int32 dw;
200     if (!d_laddr) {
201         dw = d_datawords[mw1];
202         mw1++;
203         mw2++;
204     }
205     else {
206         dw = d_datawords[j+1];
207     }
208
209     unsigned char digit = 0;
210     int count = 4;
211     if (d_type == FLEX_NUMBERED_NUMERIC)
212         count += 10;    // Skip 10 header bits for numbered numeric pages
213     else
214         count += 2;     // Otherwise skip 2
215     
216     for (int i = mw1; i <= mw2; i++) {
217         for (int k = 0; k < 21; k++) {
218             // Shift LSB from data word into digit
219             digit = (digit >> 1) & 0x0F;
220             if (dw & 0x01)
221                 digit ^= 0x08;
222             dw >>= 1;
223             if (--count == 0) {
224                 if (digit != 0x0C) // Fill
225                     d_payload << flex_bcd[digit];
226                 count = 4;
227             }
228         }
229         
230         dw = d_datawords[i];
231     }
232 }
233
234 void pager_flex_parse::parse_tone_only()
235 {
236 }
237
238 void pager_flex_parse::parse_unknown(int mw1, int mw2)
239 {
240 }