Merged jcorgan/pager developer branch into trunk.
authorjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Thu, 28 Sep 2006 16:43:53 +0000 (16:43 +0000)
committerjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Thu, 28 Sep 2006 16:43:53 +0000 (16:43 +0000)
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3685 221aa14e-8319-0410-a670-987f0aec2ac5

18 files changed:
gr-pager/README
gr-pager/src/Makefile.am
gr-pager/src/flex_demod.py
gr-pager/src/pager.i
gr-pager/src/pager_flex_deframer.cc [deleted file]
gr-pager/src/pager_flex_deframer.h [deleted file]
gr-pager/src/pager_flex_deinterleave.cc [new file with mode: 0644]
gr-pager/src/pager_flex_deinterleave.h [new file with mode: 0644]
gr-pager/src/pager_flex_parse.cc [new file with mode: 0644]
gr-pager/src/pager_flex_parse.h [new file with mode: 0644]
gr-pager/src/pager_flex_sync.cc [new file with mode: 0644]
gr-pager/src/pager_flex_sync.h [new file with mode: 0644]
gr-pager/src/pageri_bch3221.cc
gr-pager/src/pageri_flex_modes.cc
gr-pager/src/pageri_flex_modes.h
gr-pager/src/pageri_util.cc [new file with mode: 0644]
gr-pager/src/pageri_util.h [new file with mode: 0644]
gr-pager/src/usrp_flex.py

index f898d7ae0bb66d76e3291b3b1e83fd189dc28a76..9c0701d9f9a3be184f8536de21af150072e6e16a 100644 (file)
@@ -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
index 7438d2384b11ad0e4f1fdde320a0ae0e599b15ca..c4a8c938ec76043df9bc259581696e13eaeee8f2 100644 (file)
@@ -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
index 8326c9fa5d32cae284d653212ffcf1228969496a..95a6517a1d0fd3140cfbff2cfa461bea842e7bad 100644 (file)
@@ -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)
index 1e14af0854822e6adc052319056931fb1286a328..aaa02feea12591e387aed166b00b14ad6f52d7ff 100644 (file)
@@ -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 (file)
index 1f8c902..0000000
+++ /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_deframer.h b/gr-pager/src/pager_flex_deframer.h
deleted file mode 100644 (file)
index 22c2109..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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_DEFRAMER_H
-#define INCLUDED_PAGER_FLEX_DEFRAMER_H
-
-#include <gr_block.h>
-
-class pager_flex_deframer;
-typedef boost::shared_ptr<pager_flex_deframer> pager_flex_deframer_sptr;
-typedef std::vector<gr_int64> gr_int64_vector;
-
-pager_flex_deframer_sptr pager_make_flex_deframer(int rate);
-
-/*!
- * \brief flex deframer description
- * \ingroup block
- */
-
-class pager_flex_deframer : public gr_block
-{
-private:
-    // Constructors
-    friend pager_flex_deframer_sptr pager_make_flex_deframer(int rate);
-    pager_flex_deframer(int rate);
-   
-    // State machine transitions
-    void enter_idle();
-    void enter_syncing();
-    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);
-    
-    // Simple state machine
-    enum state_t { ST_IDLE, ST_SYNCING, ST_SYNC1, ST_SYNC2, ST_DATA, ST_OUTPUT };
-    state_t d_state;     
-
-    int d_rate;     // Incoming sample rate
-    int d_index;    // Index into current baud
-    int d_start;    // Start of good sync 
-    int d_center;   // Center of bit
-    int d_end;      // End of good sync
-    int d_count;    // Bit counter
-
-    int d_mode;     // Current packet mode
-    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
-
-    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);
-
-    int general_work(int noutput_items,
-                     gr_vector_int &ninput_items,
-                     gr_vector_const_void_star &input_items, 
-                     gr_vector_void_star &output_items);
-};
-
-#endif /* INCLUDED_PAGER_FLEX_DEFRAMER_H */
diff --git a/gr-pager/src/pager_flex_deinterleave.cc b/gr-pager/src/pager_flex_deinterleave.cc
new file mode 100644 (file)
index 0000000..e689e9f
--- /dev/null
@@ -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 (file)
index 0000000..77ffb3d
--- /dev/null
@@ -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 (file)
index 0000000..7d2b309
--- /dev/null
@@ -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 (file)
index 0000000..ade88c0
--- /dev/null
@@ -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 (file)
index 0000000..c8012e8
--- /dev/null
@@ -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_sync.h b/gr-pager/src/pager_flex_sync.h
new file mode 100644 (file)
index 0000000..813b7cf
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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_SYNC_H
+#define INCLUDED_PAGER_FLEX_SYNC_H
+
+#include <gr_block.h>
+
+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_sync_sptr pager_make_flex_sync(int rate);
+
+/*!
+ * \brief flex sync description
+ * \ingroup block
+ */
+
+class pager_flex_sync : public gr_block
+{
+private:
+    // Constructors
+    friend pager_flex_sync_sptr pager_make_flex_sync(int rate);
+    pager_flex_sync(int rate);
+   
+    // State machine transitions
+    void enter_idle();
+    void enter_syncing();
+    void enter_sync1();
+    void enter_sync2();
+    void enter_data();
+
+    int index_avg(int start, int end);
+    bool test_sync(unsigned char sym);
+    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 };
+    state_t d_state;     
+
+    int d_rate;     // Incoming sample rate
+    int d_index;    // Index into current baud
+    int d_start;    // Start of good sync 
+    int d_center;   // Center of bit
+    int d_end;      // End of good sync
+    int d_count;    // Bit counter
+
+    int d_mode;     // Current packet mode
+    int d_baudrate; // Current decoding baud rate
+    int d_levels;   // Current decoding levels
+    int d_spb;      // Current samples per 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
+
+public:
+    void forecast(int noutput_items, gr_vector_int &inputs_required);
+
+    int general_work(int noutput_items,
+                     gr_vector_int &ninput_items,
+                     gr_vector_const_void_star &input_items, 
+                     gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_PAGER_FLEX_SYNC_H */
index 7e2e28978a3eb90c0a7e89818e24d82aadbb9558..48ef75cbf65f5d2f0e9069c1782e65baa2087821 100644 (file)
 
 #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;
index a846643a74496038b73e42b598149b44a8dd8d54..5988da4a7ed0f3324a9d721efe4b5ac2003bd517 100644 (file)
 
 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;
+}
index ab8b10683547c6e08abb686129c72bcc96b187b0..bf3b8d98e67ae69e5aea4700cbc3248c74ced7ef 100644 (file)
@@ -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 (file)
index 0000000..44ed364
--- /dev/null
@@ -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 (file)
index 0000000..e76ecab
--- /dev/null
@@ -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 */
index ae455fde0e5c27aaf8f24c613600c55bc369c23c..636efc7e393d973ef8a3cd61a5fb8019c86c0a88 100755 (executable)
@@ -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()