diff options
-rw-r--r-- | gr-pager/README | 63 | ||||
-rw-r--r-- | gr-pager/src/Makefile.am | 17 | ||||
-rw-r--r-- | gr-pager/src/flex_demod.py | 33 | ||||
-rw-r--r-- | gr-pager/src/pager.i | 38 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_deframer.cc | 324 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_deinterleave.cc | 94 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_deinterleave.h | 54 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_parse.cc | 167 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_parse.h | 65 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_sync.cc | 339 | ||||
-rw-r--r-- | gr-pager/src/pager_flex_sync.h (renamed from gr-pager/src/pager_flex_deframer.h) | 56 | ||||
-rw-r--r-- | gr-pager/src/pageri_bch3221.cc | 5 | ||||
-rw-r--r-- | gr-pager/src/pageri_flex_modes.cc | 22 | ||||
-rw-r--r-- | gr-pager/src/pageri_flex_modes.h | 37 | ||||
-rw-r--r-- | gr-pager/src/pageri_util.cc | 46 | ||||
-rw-r--r-- | gr-pager/src/pageri_util.h | 30 | ||||
-rwxr-xr-x | gr-pager/src/usrp_flex.py | 48 |
17 files changed, 989 insertions, 449 deletions
diff --git a/gr-pager/README b/gr-pager/README index f898d7ae0..9c0701d9f 100644 --- a/gr-pager/README +++ b/gr-pager/README @@ -1,38 +1,37 @@ This GNU Radio component implements (will implement) common radiopager signaling protocols such as POCSAG and FLEX. -Current status (9/13/06): - -FLEX receiving is in mid-stream of implemention. - -pager.slicer_fb() Accepts a complex baseband downconverted channel - and outputs 4-level FSK symbols [0-3] as bytes. - This may migrate into gnuradio-core at some point. - -pager.flex_deframer() Accepts a symbol stream from slicer_fb() and - outputs received 32-bit FLEX codewords for each - defined phase. Auto adjusts for 1600 or 3200 bps, - and 2 or 4 level FSK encoding based on received - synchronization word. The sync portion of this - block may factor out into its own block for - purposes of clarity and code complexity. - -pager.bch3221_ecd() (not yet implemented) Accepts a stream of 32-bit - FLEX codewords and applies BCH (32,21) error - detection/correction (up to 2 bits), the emits - corrected stream. This may be absorbed into the - deframer at some point. - -pager.message_decode() (not yet implemented) Accepts a stream of 32-bit - FLEX codewords and separates individual paging - messages into output stream as bytes. - -pager.flex_decode() Combines the above blocks correctly to convert - from downconverted baseband to pager messages - -usrp_flex.py Instantiates USRP receive chain to receive FLEX - protocol pages. See command-line help for options. - This will probably make it into gnuradio-examples. +Current status (9/28/06): + +FLEX receiving is nearing completion. + +pager.slicer_fb() Accepts a complex baseband downconverted channel + and outputs 4-level FSK symbols [0-3] as bytes. + This may migrate into gnuradio-core at some point. + +pager.flex_sync() Accepts 4FSK symbol stream at channel rate and + outputs four phases of FLEX data bits as bytes. + Auto-shifts to 3200 bps as determined by received + FLEX synchronization word. + +pager.flex_deinterleave() Accepts a single phase of FLEX data bits and performs + deinterleaving on 256-bit blocks. Resulting code + words are error corrected using BCH 32,21 ecc (stub) + and converted into FLEX data words for output. + +pager.flex_parse() Sink block that accepts a single phase of FLEX data + words and unpacks and parses individual pages. + Currently, this block decodes the capcodes of each + receive page and displays the page type, but not yet + the contents. + +pager.flex_decode() Combines the above blocks correctly to convert + from downconverted baseband to pager messages + +usrp_flex.py Instantiates USRP receive chain to receive FLEX + protocol pages. See command-line help for options. + Right now this installs into $PREFIX/bin but will + probably make it into gnuradio-examples. Johnathan Corgan jcorgan@aeinet.com diff --git a/gr-pager/src/Makefile.am b/gr-pager/src/Makefile.am index 7438d2384..c4a8c938e 100644 --- a/gr-pager/src/Makefile.am +++ b/gr-pager/src/Makefile.am @@ -27,6 +27,9 @@ EXTRA_DIST = \ TESTS = \ run_tests +bin_SCRIPTS = \ + usrp_flex.py + noinst_PYTHON = \ qa_pager.py @@ -72,9 +75,12 @@ ourlib_LTLIBRARIES = _pager_swig.la _pager_swig_la_SOURCES = \ pager_swig.cc \ pager_slicer_fb.cc \ - pager_flex_deframer.cc \ + pager_flex_sync.cc \ + pager_flex_deinterleave.cc \ + pager_flex_parse.cc \ + pageri_bch3221.cc \ pageri_flex_modes.cc \ - pageri_bch3221.cc + pageri_util.cc # Additional source modules here # magic flags @@ -92,9 +98,12 @@ pager_swig.cc pager_swig.py: $(ALL_IFILES) # These headers get installed in ${prefix}/include/gnuradio grinclude_HEADERS = \ pager_slicer_fb.h \ - pager_flex_deframer.h \ + pager_flex_sync.h \ + pager_flex_deinterleave.h \ + pager_flex_parse.h \ + pageri_bch3221.h \ pageri_flex_modes.h \ - pageri_bch3221.h + pageri_util.h # Additional header files here # These swig headers get installed in ${prefix}/include/gnuradio/swig diff --git a/gr-pager/src/flex_demod.py b/gr-pager/src/flex_demod.py index 8326c9fa5..95a6517a1 100644 --- a/gr-pager/src/flex_demod.py +++ b/gr-pager/src/flex_demod.py @@ -23,9 +23,9 @@ from gnuradio import gr, optfir from math import pi import pager_swig -class flex_demod(gr.hier_block): +class flex_demod: """ - FLEX protocol demodulation block. + FLEX pager protocol demodulation block. This block demodulates a band-limited, complex down-converted baseband channel into FLEX protocol frames. @@ -35,7 +35,9 @@ class flex_demod(gr.hier_block): QUAD - Quadrature demodulator converts FSK to baseband amplitudes LPF - Low pass filter to remove noise prior to slicer SLICER - Converts input to one of four symbols (0, 1, 2, 3) - DEFRAMER - Syncronizes symbol stream and outputs FLEX codewords + SYNC - Converts symbol stream to four phases of FLEX blocks + DEINTx - Deinterleaves FLEX blocks into datawords + PARSEx - Parse a single FLEX phase worth of data words into pages --- @param fg: flowgraph @@ -46,12 +48,27 @@ class flex_demod(gr.hier_block): def __init__(self, fg, channel_rate): k = channel_rate/(2*pi*4800) # 4800 Hz max deviation QUAD = gr.quadrature_demod_cf(k) - + self.INPUT = QUAD + taps = optfir.low_pass(1.0, channel_rate, 3200, 6400, 0.1, 60) LPF = gr.fir_filter_fff(1, taps) SLICER = pager_swig.slicer_fb(.001, .00001) # Attack, decay - DEFRAMER = pager_swig.flex_deframer(channel_rate) - - fg.connect(QUAD, LPF, SLICER, DEFRAMER) + SYNC = pager_swig.flex_sync(channel_rate) + fg.connect(QUAD, LPF, SLICER, SYNC) + + DEINTA = pager_swig.flex_deinterleave() + PARSEA = pager_swig.flex_parse() - gr.hier_block.__init__(self, fg, QUAD, DEFRAMER) + DEINTB = pager_swig.flex_deinterleave() + PARSEB = pager_swig.flex_parse() + + DEINTC = pager_swig.flex_deinterleave() + PARSEC = pager_swig.flex_parse() + + DEINTD = pager_swig.flex_deinterleave() + PARSED = pager_swig.flex_parse() + + fg.connect((SYNC, 0), DEINTA, PARSEA) + fg.connect((SYNC, 1), DEINTB, PARSEB) + fg.connect((SYNC, 2), DEINTC, PARSEC) + fg.connect((SYNC, 3), DEINTD, PARSED) diff --git a/gr-pager/src/pager.i b/gr-pager/src/pager.i index 1e14af085..aaa02feea 100644 --- a/gr-pager/src/pager.i +++ b/gr-pager/src/pager.i @@ -26,7 +26,9 @@ %{ #include "gnuradio_swig_bug_workaround.h" // mandatory bug fix #include "pager_slicer_fb.h" -#include "pager_flex_deframer.h" +#include "pager_flex_sync.h" +#include "pager_flex_deinterleave.h" +#include "pager_flex_parse.h" #include <stdexcept> %} @@ -46,16 +48,42 @@ public: // ---------------------------------------------------------------- -GR_SWIG_BLOCK_MAGIC(pager,flex_deframer); +GR_SWIG_BLOCK_MAGIC(pager,flex_sync); -pager_flex_deframer_sptr pager_make_flex_deframer(int rate); +pager_flex_sync_sptr pager_make_flex_sync(int rate); -class pager_flex_deframer : public gr_block +class pager_flex_sync : public gr_block { private: - pager_flex_deframer(int rate); + pager_flex_sync(int rate); public: }; // ---------------------------------------------------------------- + +GR_SWIG_BLOCK_MAGIC(pager,flex_deinterleave); + +pager_flex_deinterleave_sptr pager_make_flex_deinterleave(); + +class pager_flex_deinterleave : public gr_sync_decimator +{ +private: + pager_flex_deinterleave(); + +public: +}; + +// ---------------------------------------------------------------- + +GR_SWIG_BLOCK_MAGIC(pager,flex_parse); + +pager_flex_parse_sptr pager_make_flex_parse(); + +class pager_flex_parse : public gr_block +{ +private: + pager_flex_parse(); + +public: +}; diff --git a/gr-pager/src/pager_flex_deframer.cc b/gr-pager/src/pager_flex_deframer.cc deleted file mode 100644 index 1f8c90209..000000000 --- a/gr-pager/src/pager_flex_deframer.cc +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright 2004,2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <pager_flex_deframer.h> -#include <pageri_flex_modes.h> -#include <gr_io_signature.h> -#include <gr_count_bits.h> - -pager_flex_deframer_sptr pager_make_flex_deframer(int rate) -{ - return pager_flex_deframer_sptr(new pager_flex_deframer(rate)); -} - -// FLEX deframer block takes input from symbol stream with alphabet [0, 1, 2, 3] -// at specified channel rate and and outputs deinterleaved 32-bit FLEX code words -// at 50, 100, or 200 code words per second (based on detected mode in sync -// word). - -pager_flex_deframer::pager_flex_deframer(int rate) : - gr_block ("flex_deframer", - gr_make_io_signature (1, 1, sizeof(unsigned char)), - gr_make_io_signature (1, 1, sizeof(gr_int32))), - d_sync(rate/1600) // Maximum samples per baud -{ - d_rate = rate; - set_output_multiple(1); - enter_idle(); -} - -void pager_flex_deframer::forecast(int noutput_items, gr_vector_int &inputs_required) -{ - // samples per bit X 32 bits * number of outputs needed - int items = noutput_items*sizeof(gr_int32)*8*d_spb; - for (unsigned int i = 0; i < inputs_required.size(); i++) - inputs_required[i] = items; -} - -int pager_flex_deframer::index_avg(int start, int end) -{ - // modulo average - if (start < end) - return (end + start)/2; - else - return ((end + start)/2 + d_spb/2) % d_spb; -} - -bool pager_flex_deframer::test_sync(unsigned char sym) -{ - // 64-bit FLEX sync code: - // AAAA:BBBBBBBB:CCCC - // - // Where BBBBBBBB is always 0xA6C6AAAA - // and AAAA^CCCC is 0xFFFF - // - // Specific values of AAAA determine what bps and encoding the - // packet is beyond the frame information word - // - // First we match on the marker field with a hamming distance < 4 - // Then we match on the outer code with a hamming distance < 4 - - d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2); - gr_int64 val = d_sync[d_index]; - gr_int32 marker = ((val & 0x0000FFFFFFFF0000ULL)) >> 16; - - if (gr_count_bits32(marker^FLEX_SYNC_MARKER) < 4) { - gr_int32 code = ((val & 0xFFFF000000000000ULL) >> 32) | - (val & 0x000000000000FFFFULL); - - for (int i = 0; i < num_flex_modes; i++) { - if (gr_count_bits32(code^flex_modes[i].sync) < 4) { - d_mode = i; - return true; - } - } - - // Marker received but doesn't match known codes - // All codes have high word inverted to low word - unsigned short high = (code & 0xFFFF0000) >> 16; - unsigned short low = code & 0x0000FFFF; - unsigned short syn = high^low; - if (syn == 0xFFFF) - fprintf(stderr, "Unknown sync code detected: %08X\n", code); - } - - return false; -} - -void pager_flex_deframer::enter_idle() -{ - d_state = ST_IDLE; - d_index = 0; - d_start = 0; - d_center = 0; - d_end = 0; - d_count = 0; - d_mode = 0; - d_baudrate = 1600; - d_levels = 2; - d_spb = d_rate/d_baudrate; - d_hibit = false; - d_cdi = 0; - d_cdw = 0; - d_blk = 0; -} - -void pager_flex_deframer::enter_syncing() -{ - d_start = d_index; - d_state = ST_SYNCING; -} - -void pager_flex_deframer::enter_sync1() -{ - d_state = ST_SYNC1; - d_end = d_index; - d_center = index_avg(d_start, d_end); - d_count = 0; - fprintf(stderr, "SYNC1=%08X\n", flex_modes[d_mode].sync); -} - -void pager_flex_deframer::enter_sync2() -{ - d_state = ST_SYNC2; - d_count = 0; - d_baudrate = flex_modes[d_mode].baud; - d_levels = flex_modes[d_mode].levels; - d_spb = d_rate/d_baudrate; - - if (d_baudrate == 3200) { - // Oversampling buffer just got halved - d_center = d_center/2; - d_index = d_index/2-d_spb/2; // We're here at the center of a 1600 baud bit - d_count = -1; // So this hack gets us in the right place for 3200 - } -} - -void pager_flex_deframer::enter_data() -{ - d_state = ST_DATA; - d_count = 0; -} - -void pager_flex_deframer::enter_output() -{ - d_state = ST_OUTPUT; - d_count = flex_modes[d_mode].phases*88; // Now d_count will count codewords, not bits - d_output_phase = 0; // Always phase A - d_output_index = 0; -} - -void pager_flex_deframer::accumulate_frames(unsigned char sym) -{ - // Bits are encoded with 2-bit gray code - // - // SYM Bit1 Bit2 - // --- ---- ---- - // 0 1 1 - // 1 1 0 - // 2 0 0 - // 3 0 1 - - // Codewords are interleaved in blocks of 8 - // - // ABCDEFGH - // ABCDEFGH - // ABCDEFGH - // ABCDEFGH - // ... - // etc., for all 32 bits. So each successive incoming bit is multiplexed - // into a different d_frames[][], indexed by d_cdw - - d_cdw = d_blk*8+d_cdi; - assert(d_cdw < 88); - - if (d_baudrate == 1600) { - d_frames[0][d_cdw] <<= 1; - d_frames[0][d_cdw] |= (sym < 2); - - if (d_levels == 4) { - d_frames[1][d_cdw] <<= 1; - d_frames[1][d_cdw] |= (sym == 0 || sym == 3); - } - } - else { - if (!d_hibit) { - d_frames[0][d_cdw] <<= 1; - d_frames[0][d_cdw] |= (sym < 2); - - if (d_levels == 4) { - d_frames[1][d_cdw] <<= 1; - d_frames[1][d_cdw] |= (sym == 0 || sym == 3); - } - d_hibit = true; - } - else { - d_frames[2][d_cdw] <<= 1; - d_frames[2][d_cdw] |= (sym < 2); - - if (d_levels == 4) { - d_frames[3][d_cdw] <<= 1; - d_frames[3][d_cdw] |= (sym == 0 || sym == 3); - } - d_hibit = false; - } - } - - d_cdi = ++d_cdi % 8; - if (++d_count % (d_baudrate*4/25) == 0) - d_blk++; -} - -int pager_flex_deframer::general_work(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *)input_items[0]; - gr_int32 *out = (gr_int32 *)output_items[0]; - - int i = 0, j = 0; - int ninputs = ninput_items[0]; - - while (i < ninputs && j < noutput_items) { - unsigned char sym = 0; - if (d_state != ST_OUTPUT) { - sym = *in++; i++; - d_index = ++d_index % d_spb; - } - - switch (d_state) { - case ST_IDLE: - if (test_sync(sym)) - enter_syncing(); - break; - - case ST_SYNCING: - if (!test_sync(sym)) { - enter_sync1(); - // Output sync code - *out++ = flex_modes[d_mode].sync; j++; - } - break; - - case ST_SYNC1: - if (d_index == d_center) { - d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2); - if (++d_count == 48) { // Skip 16 bits of dotting - // Output frame information word - *out++ = (gr_int32)(d_sync[d_index] & 0x00000000FFFFFFFFULL); j++; - enter_sync2(); - } - } - break; - - case ST_SYNC2: - if (d_index == d_center) { - // Skip 25 ms = 40 bits @ 1600 bps, 80 @ 3200 bps - if (++d_count == d_baudrate/40) - enter_data(); - } - break; - - case ST_DATA: - if (d_index == d_center) { - accumulate_frames(sym); - if (d_count == d_baudrate*1760/1000) - enter_output(); - } - break; - - case ST_OUTPUT: - output_codeword(out++); j++; - if (--d_count == 0) - enter_idle(); - break; - - default: - assert(0); // memory corruption of d_state if ever gets here - break; - - } - } - - consume_each(i); - return j; -} - -void pager_flex_deframer::output_codeword(gr_int32 *out) -{ - *out = d_frames[d_output_phase][d_output_index++]; - - if (d_output_index == 88) { - d_output_index = 0; - d_output_phase++; - if (d_output_phase == 1 && !flex_modes[d_mode].phase_b) - d_output_phase++; - if (d_output_phase == 2 && !flex_modes[d_mode].phase_c) - d_output_phase++; - if (d_output_phase == 3 && !flex_modes[d_mode].phase_d) - d_output_phase++; - } -} diff --git a/gr-pager/src/pager_flex_deinterleave.cc b/gr-pager/src/pager_flex_deinterleave.cc new file mode 100644 index 000000000..e689e9f39 --- /dev/null +++ b/gr-pager/src/pager_flex_deinterleave.cc @@ -0,0 +1,94 @@ +/* + * Copyright 2004,2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pager_flex_deinterleave.h> +#include <pageri_bch3221.h> +#include <pageri_util.h> +#include <gr_io_signature.h> + +pager_flex_deinterleave_sptr pager_make_flex_deinterleave() +{ + return pager_flex_deinterleave_sptr(new pager_flex_deinterleave()); +} + +pager_flex_deinterleave::pager_flex_deinterleave() : + gr_sync_decimator("flex_deinterleave", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(gr_int32)), 32) +{ + set_output_multiple(8); // One FLEX block at a time +} + +int pager_flex_deinterleave::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const unsigned char *in = (const unsigned char *)input_items[0]; + gr_int32 *out = (gr_int32 *)output_items[0]; + + // FLEX codewords are interleaved in blocks of 256 bits or 8, 32 bit + // codes. To deinterleave we parcel each incoming bit into the MSB + // of each codeword, then switch to MSB-1, etc. This is done by shifting + // in the bits from the right on each codeword as the bits come in. + // When we are done we have a FLEX block of eight codewords, ready for + // conversion to data words. + // + // FLEX data words are recovered by reversing the bit order of the code + // word, masking off the (reversed) ECC, and inverting the remainder of + // the bits (!). + // + // The data portion of a FLEX frame consists of 11 of these deinterleaved + // and converted blocks. + // + // set_output_multiple garauntees we have output space for at least + // eight data words, and 256 bits are supplied on input + + int i, j; + for (i = 0; i < 32; i++) { + for (j = 0; j < 8; j++) { + d_codewords[j] <<= 1; + d_codewords[j] |= *in++; + } + } + + // Now convert code words into data words + for (j = 0; j < 8; j++) { + gr_int32 codeword = d_codewords[j]; + + // Apply BCH 32,21 error correction + // TODO: mark dataword when codeword fails ECC + pageri_bch3221(codeword); + + // Reverse bit order + codeword = pageri_reverse_bits32(codeword); + + // Mask off ECC then invert lower 21 bits + codeword = (codeword & 0x001FFFFF)^0x001FFFFF; + + *out++ = codeword; + } + + return j; +} diff --git a/gr-pager/src/pager_flex_deinterleave.h b/gr-pager/src/pager_flex_deinterleave.h new file mode 100644 index 000000000..77ffb3df3 --- /dev/null +++ b/gr-pager/src/pager_flex_deinterleave.h @@ -0,0 +1,54 @@ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_PAGER_FLEX_DEINTERLEAVE_H +#define INCLUDED_PAGER_FLEX_DEINTERLEAVE_H + +#include <gr_sync_decimator.h> + +class pager_flex_deinterleave; +typedef boost::shared_ptr<pager_flex_deinterleave> pager_flex_deinterleave_sptr; + +pager_flex_deinterleave_sptr pager_make_flex_deinterleave(); + +/*! + * \brief flex deinterleave description + * \ingroup block + */ + +class pager_flex_deinterleave : public gr_sync_decimator +{ +private: + // Constructors + friend pager_flex_deinterleave_sptr pager_make_flex_deinterleave(); + pager_flex_deinterleave(); + + // One FLEX block of deinterleaved data + gr_int32 d_codewords[8]; + +public: + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_PAGER_FLEX_DEINTERLEAVE_H */ diff --git a/gr-pager/src/pager_flex_parse.cc b/gr-pager/src/pager_flex_parse.cc new file mode 100644 index 000000000..7d2b309ff --- /dev/null +++ b/gr-pager/src/pager_flex_parse.cc @@ -0,0 +1,167 @@ +/* + * Copyright 2004,2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pager_flex_parse.h> +#include <pageri_bch3221.h> +#include <gr_io_signature.h> + +pager_flex_parse_sptr pager_make_flex_parse() +{ + return pager_flex_parse_sptr(new pager_flex_parse()); +} + +pager_flex_parse::pager_flex_parse() : + gr_sync_block("flex_parse", + gr_make_io_signature(1, 1, sizeof(gr_int32)), + gr_make_io_signature(0, 0, 0)) +{ + d_count = 0; +} + +int pager_flex_parse::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_int32 *in = (const gr_int32 *)input_items[0]; + + int i = 0; + while (i < noutput_items) { + // Accumulate one whole frame's worth of data words (88 of them) + d_datawords[d_count] = *in++; i++; + if (++d_count == 88) { + parse_data(); + d_count = 0; + } + } + + return i; +} + +/* FLEX data frames (that is, 88 data words per phase recovered after sync, + symbol decoding, dephasing, deinterleaving, error correction, and conversion + from codewords to data words) start with a block information word containing + indices of the page address field and page vector fields. +*/ + +void pager_flex_parse::parse_capcode(gr_int32 aw1, gr_int32 aw2) +{ + d_laddr = (aw1 < 0x008001L) || + (aw1 > 0x1E0000L) || + (aw1 > 0x1E7FFEL); + + if (d_laddr) + d_capcode = aw1+((aw2^0x001FFFFF)<<15)+0x1F9000; // Don't ask + else + d_capcode = aw1-0x8000; +} + +void pager_flex_parse::parse_data() +{ + // Block information word is the first data word in frame + gr_int32 biw = d_datawords[0]; + + // Nothing to see here, please move along + if (biw == 0 || biw == 0x001FFFFF) + return; + + // Vector start index is bits 15-10 + // Address start address is bits 9-8, plus one for offset + int voffset = (biw >> 10) & 0x3f; + int aoffset = ((biw >> 8) & 0x03) + 1; + +// printf("BIW=%08X A=%i V=%i\n", biw, aoffset, voffset); + + // Iterate through pages and dispatch to appropriate handler + for (int i = aoffset; i < voffset; i++) { + int j = voffset+i-aoffset; // Start of vector field for address @ i + + if (d_datawords[i] == 0x00000000 || + d_datawords[i] == 0x001FFFFF) + continue; // Idle codewords, invalid address + + parse_capcode(d_datawords[i], d_datawords[i+1]); + if (d_laddr) + i++; + + if (d_capcode < 0) // Invalid address, skip + continue; + + // Parse vector information word for address @ offset 'i' + gr_int32 viw = d_datawords[j]; + d_type = (page_type_t)((viw >> 4) & 0x00000007); + int mw1 = (viw >> 7) & 0x00000007F; + int len = (viw >> 14) & 0x0000007F; + + if (is_numeric_page(d_type)) + len &= 0x07; + int mw2 = mw1+len; + + if (mw1 == 0 && mw2 == 0) + continue; // Invalid VIW + + if (is_tone_page(d_type)) + mw1 = mw2 = 0; + + if (mw1 > 87 || mw2 > 87) + continue; // Invalid offsets + + printf("%09i: ", d_capcode); + + if (is_alphanumeric_page(d_type)) + parse_alphanumeric(mw1, mw2-1); + else if (is_numeric_page(d_type)) + parse_numeric(mw1, mw2); + else if (is_tone_page(d_type)) + parse_tone_only(); + else + parse_unknown(mw1, mw2); + + printf("\n"); + } +} + +void pager_flex_parse::parse_alphanumeric(int mw1, int mw2) +{ + printf("ALPHA"); + + for (int i = mw1; i < mw2; i++) { + + } +} + +void pager_flex_parse::parse_numeric(int mw1, int mw2) +{ + printf("NUMERIC"); +} + +void pager_flex_parse::parse_tone_only() +{ + printf("TONE"); +} + +void pager_flex_parse::parse_unknown(int mw1, int mw2) +{ + printf("UNKNOWN"); +} diff --git a/gr-pager/src/pager_flex_parse.h b/gr-pager/src/pager_flex_parse.h new file mode 100644 index 000000000..ade88c056 --- /dev/null +++ b/gr-pager/src/pager_flex_parse.h @@ -0,0 +1,65 @@ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_PAGER_FLEX_PARSE_H +#define INCLUDED_PAGER_FLEX_PARSE_H + +#include <gr_sync_block.h> +#include <pageri_flex_modes.h> + +class pager_flex_parse; +typedef boost::shared_ptr<pager_flex_parse> pager_flex_parse_sptr; + +pager_flex_parse_sptr pager_make_flex_parse(); + +/*! + * \brief flex parse description + * \ingroup block + */ + +class pager_flex_parse : public gr_sync_block +{ +private: + // Constructors + friend pager_flex_parse_sptr pager_make_flex_parse(); + pager_flex_parse(); + + int d_count; // Count of received codewords + gr_int32 d_datawords[88]; // 11 blocks of 8 32-bit words + + page_type_t d_type; // Current page type + int d_capcode; // Current page destination address + bool d_laddr; // Current page has long address + + void parse_data(); // Handle a frame's worth of data + void parse_capcode(gr_int32 aw1, gr_int32 aw2); + void parse_alphanumeric(int mw1, int mw2); + void parse_numeric(int mw1, int mw2); + void parse_tone_only(); + void parse_unknown(int mw1, int mw2); + +public: + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_PAGER_FLEX_PARSE_H */ diff --git a/gr-pager/src/pager_flex_sync.cc b/gr-pager/src/pager_flex_sync.cc new file mode 100644 index 000000000..c8012e8bd --- /dev/null +++ b/gr-pager/src/pager_flex_sync.cc @@ -0,0 +1,339 @@ +/* + * Copyright 2004,2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pager_flex_sync.h> +#include <pageri_flex_modes.h> +#include <pageri_bch3221.h> +#include <pageri_util.h> +#include <gr_io_signature.h> +#include <gr_count_bits.h> + +pager_flex_sync_sptr pager_make_flex_sync(int rate) +{ + return pager_flex_sync_sptr(new pager_flex_sync(rate)); +} + +// FLEX sync block takes input from sliced baseband stream [0-3] at specified +// channel rate. Symbol timing is established based on receiving one of the +// defined FLEX protocol synchronization words. The block outputs one FLEX frame +// worth of bits on each output phase for the data portion of the frame. Unused phases +// get all zeros, which are considered idle code words. + +pager_flex_sync::pager_flex_sync(int rate) : + gr_block ("flex_sync", + gr_make_io_signature (1, 1, sizeof(unsigned char)), + gr_make_io_signature (4, 4, sizeof(unsigned char))), + d_sync(rate/1600) // Maximum samples per baud +{ + d_rate = rate; + enter_idle(); +} + +void pager_flex_sync::forecast(int noutput_items, gr_vector_int &inputs_required) +{ + // samples per bit X number of outputs needed + int items = noutput_items*d_spb; + for (unsigned int i = 0; i < inputs_required.size(); i++) + inputs_required[i] = items; +} + +int pager_flex_sync::index_avg(int start, int end) +{ + // modulo average + if (start < end) + return (end + start)/2; + else + return ((end + start)/2 + d_spb/2) % d_spb; +} + +bool pager_flex_sync::test_sync(unsigned char sym) +{ + // 64-bit FLEX sync code: + // AAAA:BBBBBBBB:CCCC + // + // Where BBBBBBBB is always 0xA6C6AAAA + // and AAAA^CCCC is 0xFFFF + // + // Specific values of AAAA determine what bps and encoding the + // packet is beyond the frame information word + // + // First we match on the marker field with a hamming distance < 4 + // Then we match on the outer code with a hamming distance < 4 + + d_sync[d_index] = (d_sync[d_index] << 1) | (sym < 2); + gr_int64 val = d_sync[d_index]; + gr_int32 marker = ((val & 0x0000FFFFFFFF0000ULL)) >> 16; + + if (gr_count_bits32(marker^FLEX_SYNC_MARKER) < 4) { + gr_int32 code = ((val & 0xFFFF000000000000ULL) >> 32) | + (val & 0x000000000000FFFFULL); + + for (int i = 0; i < num_flex_modes; i++) { + if (gr_count_bits32(code^flex_modes[i].sync) < 4) { + d_mode = i; + return true; + } + } + + // Marker received but doesn't match known codes + // All codes have high word inverted to low word + unsigned short high = (code & 0xFFFF0000) >> 16; + unsigned short low = code & 0x0000FFFF; + unsigned short syn = high^low; + if (syn == 0xFFFF) + fprintf(stderr, "Unknown sync code detected: %08X\n", code); + } + + return false; +} + +void pager_flex_sync::enter_idle() +{ + d_state = ST_IDLE; + d_index = 0; + d_start = 0; + d_center = 0; + d_end = 0; + d_count = 0; + d_mode = 0; + d_baudrate = 1600; + d_levels = 2; + d_spb = d_rate/d_baudrate; + d_bit_a = 0; + d_bit_b = 0; + d_bit_c = 0; + d_bit_d = 0; + d_hibit = false; + fflush(stdout); +} + +void pager_flex_sync::enter_syncing() +{ + d_start = d_index; + d_state = ST_SYNCING; +} + +void pager_flex_sync::enter_sync1() +{ + d_state = ST_SYNC1; + d_end = d_index; + d_center = index_avg(d_start, d_end); // Center of goodness + d_count = 0; +// printf("SYNC1=%08X ", flex_modes[d_mode].sync); +} + +void pager_flex_sync::enter_sync2() +{ + d_state = ST_SYNC2; + d_count = 0; + d_baudrate = flex_modes[d_mode].baud; + d_levels = flex_modes[d_mode].levels; + d_spb = d_rate/d_baudrate; + + if (d_baudrate == 3200) { + // Oversampling buffer just got halved + d_center = d_center/2; + + // We're here at the center of a 1600 baud bit + // So this hack puts the index and bit counter + // in the right place for 3200 bps. + d_index = d_index/2-d_spb/2; + d_count = -1; + } +} + +void pager_flex_sync::enter_data() +{ + d_state = ST_DATA; + d_count = 0; +} + +void pager_flex_sync::parse_fiw() +{ + // Nothing is done with these now, but these will end up getting + // passed as metadata when mblocks are available + + // Bits 31-28 are frame number related, but unknown function + // This might be a checksum + d_unknown2 = pageri_reverse_bits8((d_fiw >> 24) & 0xF0); + + // Cycle is bits 27-24, reversed + d_cycle = pageri_reverse_bits8((d_fiw >> 20) & 0xF0); + + // Frame is bits 23-17, reversed + d_frame = pageri_reverse_bits8((d_fiw >> 16) & 0xFE); + + // Bits 16-11 are some sort of marker, usually identical across + // many frames but sometimes changes between frames or modes + d_unknown1 = (d_fiw >> 11) & 0x3F; +} + +int pager_flex_sync::output_symbol(unsigned char sym) +{ + // Here is where we output a 1 or 0 on each phase according + // to current FLEX mode and symbol value. Unassigned phases + // are zero from the enter_idle() initialization. + // + // FLEX can transmit the data portion of the frame at either + // 1600 bps or 3200 bps, and can use either two- or four-level + // FSK encoding. + // + // At 1600 bps, 2-level, a single "phase" is transmitted with bit + // value '0' using level '3' and bit value '1' using level '0'. + // + // At 1600 bps, 4-level, a second "phase" is transmitted, and the + // di-bits are encoded with a gray code: + // + // Symbol Phase 1 Phase 2 + // ------ ------- ------- + // 0 1 1 + // 1 1 0 + // 2 0 0 + // 3 0 1 + // + // At 1600 bps, 4-level, these are called PHASE A and PHASE B. + // + // At 3200 bps, the same 1 or 2 bit encoding occurs, except that + // additionally two streams are interleaved on alternating symbols. + // Thus, PHASE A (and PHASE B if 4-level) are decoded on one symbol, + // then PHASE C (and PHASE D if 4-level) are decoded on the next. + + int bits = 0; + + if (d_baudrate == 1600) { + d_bit_a = (sym < 2); + if (d_levels == 4) + d_bit_b = (sym == 0) || (sym == 3); + + *d_phase_a++ = d_bit_a; + *d_phase_b++ = d_bit_b; + *d_phase_c++ = d_bit_c; + *d_phase_d++ = d_bit_d; + bits++; + } + else { + if (!d_hibit) { + d_bit_a = (sym < 2); + if (d_levels == 4) + d_bit_b = (sym == 0) || (sym == 3); + d_hibit = true; + } + else { + d_bit_c = (sym < 2); + if (d_levels == 4) + d_bit_d = (sym == 0) || (sym == 3); + d_hibit = false; + + *d_phase_a++ = d_bit_a; + *d_phase_b++ = d_bit_b; + *d_phase_c++ = d_bit_c; + *d_phase_d++ = d_bit_d; + bits++; + } + } + + return bits; +} + +int pager_flex_sync::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const unsigned char *in = (const unsigned char *)input_items[0]; + d_phase_a = (unsigned char *)output_items[0]; + d_phase_b = (unsigned char *)output_items[1]; + d_phase_c = (unsigned char *)output_items[2]; + d_phase_d = (unsigned char *)output_items[3]; + + int i = 0, j = 0; + int ninputs = ninput_items[0]; + + while (i < ninputs && j < noutput_items) { + unsigned char sym = *in++; i++; + d_index = ++d_index % d_spb; + + switch (d_state) { + case ST_IDLE: + // Continually compare the received symbol stream + // against the known FLEX sync words. + if (test_sync(sym)) + enter_syncing(); + break; + + case ST_SYNCING: + // Wait until we stop seeing sync, then calculate + // the center of the bit period (d_center) + if (!test_sync(sym)) + enter_sync1(); + break; + + case ST_SYNC1: + // Skip 16 bits of dotting, then accumulate 32 bits + // of Frame Information Word. + if (d_index == d_center) { + d_fiw = (d_fiw << 1) | (sym > 1); + if (++d_count == 48) { + // FIW is accumulated, call BCH to error correct it + pageri_bch3221(d_fiw); + parse_fiw(); + enter_sync2(); + } + } + break; + + case ST_SYNC2: + // This part and the remainder of the frame are transmitted + // at either 1600 bps or 3200 bps based on the received + // FLEX sync word. The second SYNC header is 25ms of idle bits + // at either speed. + if (d_index == d_center) { + // Skip 25 ms = 40 bits @ 1600 bps, 80 @ 3200 bps + if (++d_count == d_baudrate/40) + enter_data(); + } + break; + + case ST_DATA: + // The data portion of the frame is 1760 ms long at either + // baudrate. This is 2816 bits @ 1600 bps and 5632 bits @ 3200 bps. + // The output_symbol() routine decodes and doles out the bits + // to each of the four transmitted phases of FLEX interleaved codes. + if (d_index == d_center) { + j += output_symbol(sym); + if (++d_count == d_baudrate*1760/1000) + enter_idle(); + } + break; + + default: + assert(0); // memory corruption of d_state if ever gets here + break; + } + } + + consume_each(i); + return j; +} diff --git a/gr-pager/src/pager_flex_deframer.h b/gr-pager/src/pager_flex_sync.h index 22c2109a8..813b7cf26 100644 --- a/gr-pager/src/pager_flex_deframer.h +++ b/gr-pager/src/pager_flex_sync.h @@ -19,28 +19,28 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_PAGER_FLEX_DEFRAMER_H -#define INCLUDED_PAGER_FLEX_DEFRAMER_H +#ifndef INCLUDED_PAGER_FLEX_SYNC_H +#define INCLUDED_PAGER_FLEX_SYNC_H #include <gr_block.h> -class pager_flex_deframer; -typedef boost::shared_ptr<pager_flex_deframer> pager_flex_deframer_sptr; +class pager_flex_sync; +typedef boost::shared_ptr<pager_flex_sync> pager_flex_sync_sptr; typedef std::vector<gr_int64> gr_int64_vector; -pager_flex_deframer_sptr pager_make_flex_deframer(int rate); +pager_flex_sync_sptr pager_make_flex_sync(int rate); /*! - * \brief flex deframer description + * \brief flex sync description * \ingroup block */ -class pager_flex_deframer : public gr_block +class pager_flex_sync : public gr_block { private: // Constructors - friend pager_flex_deframer_sptr pager_make_flex_deframer(int rate); - pager_flex_deframer(int rate); + friend pager_flex_sync_sptr pager_make_flex_sync(int rate); + pager_flex_sync(int rate); // State machine transitions void enter_idle(); @@ -48,15 +48,14 @@ private: void enter_sync1(); void enter_sync2(); void enter_data(); - void enter_output(); int index_avg(int start, int end); bool test_sync(unsigned char sym); - void accumulate_frames(unsigned char sym); - void output_codeword(gr_int32 *out); + void parse_fiw(); + int output_symbol(unsigned char sym); // Simple state machine - enum state_t { ST_IDLE, ST_SYNCING, ST_SYNC1, ST_SYNC2, ST_DATA, ST_OUTPUT }; + enum state_t { ST_IDLE, ST_SYNCING, ST_SYNC1, ST_SYNC2, ST_DATA }; state_t d_state; int d_rate; // Incoming sample rate @@ -70,19 +69,26 @@ private: int d_baudrate; // Current decoding baud rate int d_levels; // Current decoding levels int d_spb; // Current samples per baud - bool d_hibit; // Current bit is high bit when 3200 baud - + bool d_hibit; // Alternating bit indicator for 3200 bps + + gr_int32 d_fiw; // Frame information word + int d_frame; // Current FLEX frame + int d_cycle; // Current FLEX cycle + int d_unknown1; + int d_unknown2; + + unsigned char d_bit_a; + unsigned char d_bit_b; + unsigned char d_bit_c; + unsigned char d_bit_d; + + unsigned char *d_phase_a; + unsigned char *d_phase_b; + unsigned char *d_phase_c; + unsigned char *d_phase_d; + gr_int64_vector d_sync; // Trial synchronizers - int d_cdi; // 0-7 code word index for deinterleave - int d_cdw; // 0-87 code word index for frame - int d_blk; // 0-10 block index - - int d_output_phase; // Indexes d_frames[][] during output - int d_output_index; // indexes d_frames[][] during output - - gr_int32 d_frames[4][88]; // Frame accumulators for each phase - public: void forecast(int noutput_items, gr_vector_int &inputs_required); @@ -92,4 +98,4 @@ public: gr_vector_void_star &output_items); }; -#endif /* INCLUDED_PAGER_FLEX_DEFRAMER_H */ +#endif /* INCLUDED_PAGER_FLEX_SYNC_H */ diff --git a/gr-pager/src/pageri_bch3221.cc b/gr-pager/src/pageri_bch3221.cc index 7e2e28978..48ef75cbf 100644 --- a/gr-pager/src/pageri_bch3221.cc +++ b/gr-pager/src/pageri_bch3221.cc @@ -25,6 +25,11 @@ #include <pageri_bch3221.h> +// Corrects supplied data word according to BCH3221 encoding and +// returns the number of errors detected/corrected. +// +// Not implemented yet + int pageri_bch3221(gr_int32 &data) { return 0; diff --git a/gr-pager/src/pageri_flex_modes.cc b/gr-pager/src/pageri_flex_modes.cc index a846643a7..5988da4a7 100644 --- a/gr-pager/src/pageri_flex_modes.cc +++ b/gr-pager/src/pageri_flex_modes.cc @@ -23,11 +23,21 @@ const flex_mode_t flex_modes[] = { - { 0x870C78F3, 1600, 2, true, false, false, false, 1 }, - { 0xB0684F97, 1600, 4, true, true, false, false, 2 }, -// { 0xUNKNOWN, 3200, 2, true, false, true, false, 2 }, - { 0xDEA0215F, 3200, 4, true, true, true, true, 4 }, - { 0x4C7CB383, 3200, 4, true, true, true, true, 4 } + { 0x870C78F3, 1600, 2 }, + { 0xB0684F97, 1600, 4 }, +// { 0xUNKNOWN, 3200, 2 }, + { 0xDEA0215F, 3200, 4 }, + { 0x4C7CB383, 3200, 4 } }; -const int num_flex_modes = sizeof(flex_modes); +const int num_flex_modes = sizeof(flex_modes)/sizeof(flex_modes[0]); + +int find_flex_mode(gr_int32 sync_code) +{ + for (int i = 0; i < num_flex_modes; i++) + if (flex_modes[i].sync == sync_code) + return i; + + // Not found + return -1; +} diff --git a/gr-pager/src/pageri_flex_modes.h b/gr-pager/src/pageri_flex_modes.h index ab8b10683..bf3b8d98e 100644 --- a/gr-pager/src/pageri_flex_modes.h +++ b/gr-pager/src/pageri_flex_modes.h @@ -31,15 +31,42 @@ typedef struct flex_mode gr_int32 sync; // Outer synchronization code unsigned int baud; // Baudrate of SYNC2 and DATA unsigned int levels; // FSK encoding of SYNC2 and DATA - bool phase_a; // PHASEA is transmitted - bool phase_b; // PHASEB is transmitted - bool phase_c; // PHASEC is transmitted - bool phase_d; // PHASED is transmitted - int phases; // number of phases transmitted } flex_mode_t; extern const flex_mode_t flex_modes[]; extern const int num_flex_modes; +int find_flex_mode(gr_int32 sync_code); + +typedef enum { + FLEX_SECURE, + FLEX_UNKNOWN, + FLEX_TONE, + FLEX_STANDARD_NUMERIC, + FLEX_SPECIAL_NUMERIC, + FLEX_ALPHANUMERIC, + FLEX_BINARY, + FLEX_NUMBERED_NUMERIC, + NUM_FLEX_PAGE_TYPES +} +page_type_t; + +inline bool is_alphanumeric_page(page_type_t type) +{ + return (type == FLEX_ALPHANUMERIC || + type == FLEX_SECURE); +} + +inline bool is_numeric_page(page_type_t type) +{ + return (type == FLEX_STANDARD_NUMERIC || + type == FLEX_SPECIAL_NUMERIC || + type == FLEX_NUMBERED_NUMERIC); +} + +inline bool is_tone_page(page_type_t type) +{ + return (type == FLEX_TONE); +} #endif // INCLUDED_PAGERI_FLEX_MODES_H diff --git a/gr-pager/src/pageri_util.cc b/gr-pager/src/pageri_util.cc new file mode 100644 index 000000000..44ed3642c --- /dev/null +++ b/gr-pager/src/pageri_util.cc @@ -0,0 +1,46 @@ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <pageri_util.h> + +unsigned char pageri_reverse_bits8(unsigned char val) +{ + // This method was attributed to Rich Schroeppel in the Programming + // Hacks section of Beeler, M., Gosper, R. W., and Schroeppel, R. + // HAKMEM. MIT AI Memo 239, Feb. 29, 1972. + // + // Reverses 8 bits in 5 machine operations with 64 bit arch + return (val * 0x0202020202ULL & 0x010884422010ULL) % 1023; +} + +gr_int32 pageri_reverse_bits32(gr_int32 val) +{ + gr_int32 out = 0x00000000; + out |= (pageri_reverse_bits8((val >> 24) & 0x000000FF) ); + out |= (pageri_reverse_bits8((val >> 16) & 0x000000FF) << 8); + out |= (pageri_reverse_bits8((val >> 8) & 0x000000FF) << 16); + out |= (pageri_reverse_bits8((val ) & 0x000000FF) << 24); + return out; +} diff --git a/gr-pager/src/pageri_util.h b/gr-pager/src/pageri_util.h new file mode 100644 index 000000000..e76ecabbf --- /dev/null +++ b/gr-pager/src/pageri_util.h @@ -0,0 +1,30 @@ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_PAGERI_UTIL_H +#define INCLUDED_PAGERI_UTIL_H + +#include <gr_types.h> + +unsigned char pageri_reverse_bits8(unsigned char val); +gr_int32 pageri_reverse_bits32(gr_int32 val); + +#endif /* INCLUDED_PAGERI_UTIL_H */ diff --git a/gr-pager/src/usrp_flex.py b/gr-pager/src/usrp_flex.py index ae455fde0..636efc7e3 100755 --- a/gr-pager/src/usrp_flex.py +++ b/gr-pager/src/usrp_flex.py @@ -1,12 +1,10 @@ #!/usr/bin/env python -from gnuradio import gr, gru, usrp, optfir, eng_notation, blks +from gnuradio import gr, gru, usrp, optfir, eng_notation, blks, pager from gnuradio.eng_option import eng_option from optparse import OptionParser import time, os, sys -from flex_demod import flex_demod - """ This example application demonstrates receiving and demodulating the FLEX pager protocol. @@ -16,10 +14,8 @@ blocks: USRP - Daughter board source generating complex baseband signal. CHAN - Low pass filter to select channel bandwidth -RFSQL - RF squelch zeroing output when input power below threshold AGC - Automatic gain control leveling signal at [-1.0, +1.0] FLEX - FLEX pager protocol decoder -SINK - File sink for decoded output The following are required command line parameters: @@ -36,11 +32,6 @@ The following are optional command line parameters: Once the program is running, ctrl-break (Ctrl-C) stops operation. """ -def make_filename(dir, freq): - t = time.strftime('%Y%m%d-%H%M%S') - f = 'r%s-%s.dat' % (t, eng_notation.num_to_str(freq)) - return os.path.join(dir, f) - class usrp_source_c(gr.hier_block): """ Create a USRP source object supplying complex floats. @@ -84,7 +75,7 @@ class app_flow_graph(gr.flow_graph): USRP = usrp_source_c(self, # Flow graph options.rx_subdev_spec, # Daugherboard spec - 250, # IF decimation ratio gets 256K if_rate + 250, # IF decimation ratio gets 256K if_rate options.gain, # Receiver gain options.calibration) # Frequency offset USRP.tune(options.frequency) @@ -95,35 +86,24 @@ class app_flow_graph(gr.flow_graph): CHAN_taps = optfir.low_pass(1.0, # Filter gain if_rate, # Sample rate - 8000, # One sided modulation bandwidth - 10000, # One sided channel bandwidth - 0.1, # Passband ripple - 60) # Stopband attenuation + 8000, # One sided modulation bandwidth + 10000, # One sided channel bandwidth + 0.1, # Passband ripple + 60) # Stopband attenuation CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate CHAN_taps, # Filter taps 0.0, # Offset frequency if_rate) # Sample rate - RFSQL = gr.pwr_squelch_cc(options.rf_squelch, # Power threshold - 125.0/channel_rate, # Time constant - channel_rate/20, # 50ms rise/fall - False) # Zero, not gate output - AGC = gr.agc_cc(1.0/channel_rate, # Time constant 1.0, # Reference power 1.0, # Initial gain 1.0) # Maximum gain - FLEX = flex_demod(self, 32000) + FLEX = pager.flex_demod(self, 32000) - SINK = gr.file_sink(4, options.filename) - - self.connect(USRP, CHAN) - self.connect(CHAN, RFSQL) - self.connect(RFSQL, AGC) - self.connect(AGC, FLEX) - self.connect(FLEX, SINK) + self.connect(USRP, CHAN, AGC, FLEX.INPUT) def main(): parser = OptionParser(option_class=eng_option) @@ -135,23 +115,11 @@ def main(): help="set frequency offset to Hz", metavar="Hz") parser.add_option("-g", "--gain", type="int", default=None, help="set RF gain", metavar="dB") - parser.add_option("-r", "--rf-squelch", type="eng_float", default=-50.0, - help="set RF squelch to dB", metavar="dB") - parser.add_option("-F", "--filename", default=None) - parser.add_option("-D", "--dir", default=None) (options, args) = parser.parse_args() if options.frequency < 1e6: options.frequency *= 1e6 - if options.filename is None and options.dir is None: - sys.stderr.write('Must specify either -F FILENAME or -D DIR\n') - parser.print_help() - sys.exit(1) - - if options.filename is None: - options.filename = make_filename(options.dir, options.frequency) - fg = app_flow_graph(options, args) try: fg.run() |