summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-pager/README63
-rw-r--r--gr-pager/src/Makefile.am17
-rw-r--r--gr-pager/src/flex_demod.py33
-rw-r--r--gr-pager/src/pager.i38
-rw-r--r--gr-pager/src/pager_flex_deframer.cc324
-rw-r--r--gr-pager/src/pager_flex_deinterleave.cc94
-rw-r--r--gr-pager/src/pager_flex_deinterleave.h54
-rw-r--r--gr-pager/src/pager_flex_parse.cc167
-rw-r--r--gr-pager/src/pager_flex_parse.h65
-rw-r--r--gr-pager/src/pager_flex_sync.cc339
-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.cc5
-rw-r--r--gr-pager/src/pageri_flex_modes.cc22
-rw-r--r--gr-pager/src/pageri_flex_modes.h37
-rw-r--r--gr-pager/src/pageri_util.cc46
-rw-r--r--gr-pager/src/pageri_util.h30
-rwxr-xr-xgr-pager/src/usrp_flex.py48
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()