summaryrefslogtreecommitdiff
path: root/gr-pager
diff options
context:
space:
mode:
Diffstat (limited to 'gr-pager')
-rw-r--r--gr-pager/AUTHORS1
-rw-r--r--gr-pager/Makefile.am26
-rw-r--r--gr-pager/README37
-rw-r--r--gr-pager/src/Makefile.am124
-rw-r--r--gr-pager/src/__init__.py25
-rwxr-xr-xgr-pager/src/aypabtu.py117
-rw-r--r--gr-pager/src/flex_demod.py88
-rw-r--r--gr-pager/src/pager.i92
-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_frame.cc38
-rw-r--r--gr-pager/src/pager_flex_frame.h46
-rw-r--r--gr-pager/src/pager_flex_frame.i37
-rw-r--r--gr-pager/src/pager_flex_parse.cc237
-rw-r--r--gr-pager/src/pager_flex_parse.h72
-rw-r--r--gr-pager/src/pager_flex_sync.cc341
-rw-r--r--gr-pager/src/pager_flex_sync.h101
-rw-r--r--gr-pager/src/pager_slicer_fb.cc100
-rw-r--r--gr-pager/src/pager_slicer_fb.h58
-rw-r--r--gr-pager/src/pageri_bch3221.cc36
-rw-r--r--gr-pager/src/pageri_bch3221.h31
-rw-r--r--gr-pager/src/pageri_flex_modes.cc45
-rw-r--r--gr-pager/src/pageri_flex_modes.h73
-rw-r--r--gr-pager/src/pageri_util.cc46
-rw-r--r--gr-pager/src/pageri_util.h30
-rwxr-xr-xgr-pager/src/qa_pager.py35
-rw-r--r--gr-pager/src/run_tests.in10
-rwxr-xr-xgr-pager/src/usrp_flex.py138
28 files changed, 2132 insertions, 0 deletions
diff --git a/gr-pager/AUTHORS b/gr-pager/AUTHORS
new file mode 100644
index 000000000..cdb61c9f1
--- /dev/null
+++ b/gr-pager/AUTHORS
@@ -0,0 +1 @@
+Johnathan Corgan <jcorgan@aeinet.com>
diff --git a/gr-pager/Makefile.am b/gr-pager/Makefile.am
new file mode 100644
index 000000000..a9fc0d490
--- /dev/null
+++ b/gr-pager/Makefile.am
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+SUBDIRS = src
+
+MOSTLYCLEANFILES = *~ *.tmp \ No newline at end of file
diff --git a/gr-pager/README b/gr-pager/README
new file mode 100644
index 000000000..4327f258e
--- /dev/null
+++ b/gr-pager/README
@@ -0,0 +1,37 @@
+This GNU Radio component implements (will implement) common radiopager
+signaling protocols such as POCSAG and FLEX.
+
+Current status (10/6/06):
+
+FLEX receiving is completed except for addition of BCH error correction.
+
+pager.slicer_fb() Accepts a complex baseband downconverted channel
+ and outputs 4-level FSK symbols [0-3] as bytes.
+
+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. These are
+ passed outside the data plane via gr_message's.
+
+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.
+
+aypabtu.py Decodes FLEX pages from multiple rx channels in a range.
+ Incomplete.
+
+Johnathan Corgan
+jcorgan@aeinet.com
diff --git a/gr-pager/src/Makefile.am b/gr-pager/src/Makefile.am
new file mode 100644
index 000000000..b82e34dca
--- /dev/null
+++ b/gr-pager/src/Makefile.am
@@ -0,0 +1,124 @@
+#
+# Copyright 2004,2005,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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+EXTRA_DIST = \
+ run_tests.in
+
+TESTS = \
+ run_tests
+
+bin_SCRIPTS = \
+ usrp_flex.py \
+ aypabtu.py
+
+noinst_PYTHON = \
+ qa_pager.py
+
+# Install this stuff so that it ends up as the gnuradio.pgr module
+# This usually ends up at:
+# ${prefix}/lib/python${python_version}/site-packages/gnuradio/pager
+
+ourpythondir = $(grpythondir)/pager
+ourlibdir = $(grpyexecdir)/pager
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS)
+
+SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(STD_DEFINES_AND_INCLUDES)
+
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES) \
+ pager_flex_frame.i
+
+NON_LOCAL_IFILES = \
+ $(GNURADIO_I)
+
+LOCAL_IFILES = \
+ $(top_srcdir)/gr-pager/src/pager.i
+
+# These files are built by SWIG. The first is the C++ glue.
+# The second is the python wrapper that loads the _howto shared library
+# and knows how to call our extensions.
+
+BUILT_SOURCES = \
+ pager_swig.cc \
+ pager_swig.py
+
+# This gets pgr.py installed in the right place
+ourpython_PYTHON = \
+ __init__.py \
+ pager_swig.py \
+ flex_demod.py \
+ usrp_flex.py \
+ aypabtu.py
+
+ourlib_LTLIBRARIES = _pager_swig.la
+
+# These are the source files that go into the shared library
+_pager_swig_la_SOURCES = \
+ pager_swig.cc \
+ pager_flex_frame.cc \
+ pager_slicer_fb.cc \
+ pager_flex_sync.cc \
+ pager_flex_deinterleave.cc \
+ pager_flex_parse.cc \
+ pageri_bch3221.cc \
+ pageri_flex_modes.cc \
+ pageri_util.cc
+ # Additional source modules here
+
+# magic flags
+_pager_swig_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+# link the library against the c++ standard library
+_pager_swig_la_LIBADD = \
+ $(PYTHON_LDFLAGS) \
+ $(GNURADIO_CORE_LIBS) \
+ -lstdc++
+
+pager_swig.cc pager_swig.py: $(ALL_IFILES)
+ $(SWIG) $(SWIGPYTHONARGS) -module pager_swig -o pager_swig.cc $(LOCAL_IFILES)
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ pager_slicer_fb.h \
+ pager_flex_sync.h \
+ pager_flex_deinterleave.h \
+ pager_flex_parse.h \
+ pager_flex_frame.h \
+ pageri_bch3221.h \
+ pageri_flex_modes.h \
+ pageri_util.h
+ # Additional header files here
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = \
+ $(LOCAL_IFILES) \
+ pager_flex_frame.i
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc *~ *.tmp
+
+# Don't distribute output of swig
+dist-hook:
+ @for file in $(BUILT_SOURCES); do echo $(RM) $(distdir)/$$file; done
+ @for file in $(BUILT_SOURCES); do $(RM) $(distdir)/$$file; done
diff --git a/gr-pager/src/__init__.py b/gr-pager/src/__init__.py
new file mode 100644
index 000000000..cf0edaa96
--- /dev/null
+++ b/gr-pager/src/__init__.py
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+# The presence of this file turns this directory into a Python package
+
+from pager_swig import *
+from flex_demod import flex_demod
diff --git a/gr-pager/src/aypabtu.py b/gr-pager/src/aypabtu.py
new file mode 100755
index 000000000..c742744c3
--- /dev/null
+++ b/gr-pager/src/aypabtu.py
@@ -0,0 +1,117 @@
+#!/usr/bin/env python
+
+from math import pi
+from gnuradio import gr, gru, usrp, optfir, audio, eng_notation, blks, pager
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+from string import split, join, printable
+
+class usrp_source_c(gr.hier_block):
+ """
+ Create a USRP source object supplying complex floats.
+
+ Selects user supplied subdevice or chooses first available one.
+
+ Calibration value is the offset from the tuned frequency to
+ the actual frequency.
+ """
+ def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0):
+ self._decim = decim
+ self._src = usrp.source_c()
+ if subdev_spec is None:
+ subdev_spec = usrp.pick_rx_subdevice(self._src)
+ self._subdev = usrp.selected_subdev(self._src, subdev_spec)
+ self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec))
+ self._src.set_decim_rate(self._decim)
+
+ # If no gain specified, set to midrange
+ if gain is None:
+ g = self._subdev.gain_range()
+ gain = (g[0]+g[1])/2.0
+
+ self._subdev.set_gain(gain)
+ self._cal = calibration
+
+ gr.hier_block.__init__(self, fg, self._src, self._src)
+
+ def tune(self, freq):
+ result = usrp.tune(self._src, 0, self._subdev, freq+self._cal)
+ # TODO: deal with residual
+
+ def rate(self):
+ return self._src.adc_rate()/self._decim
+
+class channelizer(blks.analysis_filterbank):
+ def __init__(self,
+ fg, # Flow graph
+ if_rate, # IF input sample rate (complex)
+ channel_rate, # Final channel sample rate (complex)
+ channel_pass, # Occupied spectrum for narrowband channel
+ channel_stop): # Total channel + guard band
+
+ num_channels = int(if_rate/channel_rate)
+ taps = optfir.low_pass(1.0, if_rate, channel_pass, channel_stop, 0.1, 60)
+ blks.analysis_filterbank.__init__(self, fg, num_channels, taps)
+
+class app_flow_graph(gr.flow_graph):
+ def __init__(self, options, args, queue):
+ gr.flow_graph.__init__(self)
+ self.options = options
+ self.args = args
+
+ # FIXME: Parameterize
+ #
+ # Difference between upper and lower must evenly divide into USRP sample rate
+ # and also must be divisible by 25000
+ options.channel_rate = 25000
+ options.channel_pass = 8000
+ options.channel_stop = 10000
+
+ if_rate = options.upper_freq - options.lower_freq
+ center_freq = options.lower_freq + if_rate/2
+ num_channels = int(if_rate/options.channel_rate)
+ decim = int(64000000/if_rate)
+
+ self.SRC = usrp_source_c(self, options.rx_board, decim, options.gain, options.calibration)
+ self.CHAN = channelizer(self, if_rate, options.channel_rate, options.channel_pass, options.channel_stop)
+
+ self.connect(self.SRC, self.CHAN)
+ for i in range(num_channels):
+ freq = options.lower_freq + i*options.channel_rate
+ if freq > center_freq:
+ freq -= if_rate/2
+ else:
+ freq += if_rate/2
+ FLEX = pager.flex_demod(self, options.channel_rate, queue)
+ self.connect((self.CHAN, i), FLEX.INPUT)
+
+ self.SRC.tune(center_freq)
+
+def make_printable(data):
+ return "".join(char for char in data if char in printable)
+
+def main():
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("", "--upper-freq", type="eng_float", help="lower Rx frequency", metavar="LOWER")
+ parser.add_option("", "--lower-freq", type="eng_float", help="upper Rx frequency", metavar="UPPER")
+ parser.add_option("-R", "--rx-board", type="subdev", help="select USRP Rx side A or B (default=first daughterboard found)", metavar="SIDE")
+ parser.add_option("-c", "--calibration", type="eng_float", default=0.0, help="set frequency offset to Hz", metavar="Hz")
+ parser.add_option("-g", "--gain", type="int", help="set RF gain", metavar="dB")
+ (options, args) = parser.parse_args()
+
+ # FIXME: parameter sanity checks
+
+ queue = gr.msg_queue()
+ fg = app_flow_graph(options, args, queue)
+ try:
+ fg.start()
+ while 1:
+ msg = queue.delete_head() # Blocking read
+ fields = split(msg.to_string(), chr(128))
+ print join([make_printable(field) for field in fields], '|')
+
+ except KeyboardInterrupt:
+ fg.stop()
+
+if __name__ == "__main__":
+ main()
diff --git a/gr-pager/src/flex_demod.py b/gr-pager/src/flex_demod.py
new file mode 100644
index 000000000..a8c6f09b1
--- /dev/null
+++ b/gr-pager/src/flex_demod.py
@@ -0,0 +1,88 @@
+#
+# 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.
+#
+
+from gnuradio import gr, gru, optfir, blks
+from math import pi
+import pager_swig
+
+chan_rate = 16000
+
+class flex_demod:
+ """
+ FLEX pager protocol demodulation block.
+
+ This block demodulates a band-limited, complex down-converted baseband
+ channel into FLEX protocol frames.
+
+ Flow graph (so far):
+
+ RSAMP - Resample incoming stream to 16000 sps
+ 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)
+ 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
+ @param channel_rate: incoming sample rate of the baseband channel
+ @type sample_rate: integer
+ """
+
+
+ def __init__(self, fg, channel_rate, queue):
+ k = chan_rate/(2*pi*4800) # 4800 Hz max deviation
+ QUAD = gr.quadrature_demod_cf(k)
+ self.INPUT = QUAD
+
+ if channel_rate != chan_rate:
+ interp = gru.lcm(channel_rate, chan_rate)/channel_rate
+ decim = gru.lcm(channel_rate, chan_rate)/chan_rate
+ RESAMP = blks.rational_resampler_ccf(fg, interp, decim)
+ self.INPUT = RESAMP
+
+ taps = optfir.low_pass(1.0, chan_rate, 3200, 6400, 0.1, 60)
+ LPF = gr.fir_filter_fff(1, taps)
+ SLICER = pager_swig.slicer_fb(.001, .00001) # Attack, decay
+ SYNC = pager_swig.flex_sync(chan_rate)
+
+ if channel_rate != chan_rate:
+ fg.connect(RESAMP, QUAD, LPF, SLICER, SYNC)
+ else:
+ fg.connect(QUAD, LPF, SLICER, SYNC)
+
+ DEINTA = pager_swig.flex_deinterleave()
+ PARSEA = pager_swig.flex_parse(queue)
+
+ DEINTB = pager_swig.flex_deinterleave()
+ PARSEB = pager_swig.flex_parse(queue)
+
+ DEINTC = pager_swig.flex_deinterleave()
+ PARSEC = pager_swig.flex_parse(queue)
+
+ DEINTD = pager_swig.flex_deinterleave()
+ PARSED = pager_swig.flex_parse(queue)
+
+ 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
new file mode 100644
index 000000000..cc73a5473
--- /dev/null
+++ b/gr-pager/src/pager.i
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2005,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.
+ */
+
+%feature("autodoc","1");
+%include "exception.i"
+%import "gnuradio.i"
+
+%{
+#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
+#include "pager_flex_frame.h"
+#include "pager_slicer_fb.h"
+#include "pager_flex_sync.h"
+#include "pager_flex_deinterleave.h"
+#include "pager_flex_parse.h"
+#include <stdexcept>
+%}
+
+%include "pager_flex_frame.i"
+
+// ----------------------------------------------------------------
+
+GR_SWIG_BLOCK_MAGIC(pager,slicer_fb);
+
+pager_slicer_fb_sptr pager_make_slicer_fb(float alpha, float beta);
+
+class pager_slicer_fb : public gr_sync_block
+{
+private:
+ pager_slicer_fb(float alpha, float beta);
+
+public:
+};
+
+// ----------------------------------------------------------------
+
+GR_SWIG_BLOCK_MAGIC(pager,flex_sync);
+
+pager_flex_sync_sptr pager_make_flex_sync(int rate);
+
+class pager_flex_sync : public gr_block
+{
+private:
+ 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(gr_msg_queue_sptr queue);
+
+class pager_flex_parse : public gr_block
+{
+private:
+ pager_flex_parse(gr_msg_queue_sptr queue);
+
+public:
+};
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_frame.cc b/gr-pager/src/pager_flex_frame.cc
new file mode 100644
index 000000000..3934c7692
--- /dev/null
+++ b/gr-pager/src/pager_flex_frame.cc
@@ -0,0 +1,38 @@
+/*
+ * 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 <pager_flex_frame.h>
+
+pager_flex_frame_sptr pager_make_flex_frame()
+{
+ return pager_flex_frame_sptr(new pager_flex_frame());
+}
+
+pager_flex_frame::pager_flex_frame()
+{
+}
+
+pager_flex_frame::~pager_flex_frame()
+{
+}
diff --git a/gr-pager/src/pager_flex_frame.h b/gr-pager/src/pager_flex_frame.h
new file mode 100644
index 000000000..300de9096
--- /dev/null
+++ b/gr-pager/src/pager_flex_frame.h
@@ -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.
+ */
+#ifndef INCLUDED_PAGER_FLEX_FRAME_H
+#define INCLUDED_PAGER_FLEX_FRAME_H
+
+#include <boost/shared_ptr.hpp>
+
+class pager_flex_frame;
+typedef boost::shared_ptr<pager_flex_frame> pager_flex_frame_sptr;
+
+/*!
+ * \brief public constructor for pager_flex_frame
+ */
+pager_flex_frame_sptr pager_make_flex_frame();
+
+/*!
+ * \brief flex_frame.
+ */
+class pager_flex_frame {
+ // Constructor is private to force use of shared_ptr
+ pager_flex_frame();
+ friend pager_flex_frame_sptr pager_make_flex_frame();
+
+public:
+ ~pager_flex_frame();
+};
+
+#endif /* INCLUDED_PAGER_FLEX_FRAME_H */
diff --git a/gr-pager/src/pager_flex_frame.i b/gr-pager/src/pager_flex_frame.i
new file mode 100644
index 000000000..d3fa1b6b7
--- /dev/null
+++ b/gr-pager/src/pager_flex_frame.i
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+class pager_flex_frame;
+typedef boost::shared_ptr<pager_flex_frame> pager_flex_frame_sptr;
+%template(pager_flex_frame_sptr) boost::shared_ptr<pager_flex_frame>;
+
+%rename(flex_frame) pager_make_flex_frame;
+pager_flex_frame_sptr pager_make_flex_frame();
+
+/*!
+ * \brief flex_frame.
+ */
+class pager_flex_frame {
+ pager_flex_frame();
+
+public:
+};
+
diff --git a/gr-pager/src/pager_flex_parse.cc b/gr-pager/src/pager_flex_parse.cc
new file mode 100644
index 000000000..7178ba516
--- /dev/null
+++ b/gr-pager/src/pager_flex_parse.cc
@@ -0,0 +1,237 @@
+/*
+ * 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>
+#include <ctype.h>
+#include <iostream>
+
+pager_flex_parse_sptr pager_make_flex_parse(gr_msg_queue_sptr queue)
+{
+ return pager_flex_parse_sptr(new pager_flex_parse(queue));
+}
+
+pager_flex_parse::pager_flex_parse(gr_msg_queue_sptr queue) :
+ gr_sync_block("flex_parse",
+ gr_make_io_signature(1, 1, sizeof(gr_int32)),
+ gr_make_io_signature(0, 0, 0)),
+ d_queue(queue)
+{
+ 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 AW:%02i-%02i\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
+
+ d_payload.str("");
+ d_payload << d_capcode << FIELD_DELIM << d_type << FIELD_DELIM;
+
+ if (is_alphanumeric_page(d_type))
+ parse_alphanumeric(mw1, mw2-1, j);
+ else if (is_numeric_page(d_type))
+ parse_numeric(mw1, mw2, j);
+ else if (is_tone_page(d_type))
+ parse_tone_only();
+ else
+ parse_unknown(mw1, mw2);
+
+ //std::cout << d_payload.str() << std::endl;
+ //fflush(stdout);
+
+ gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
+ d_queue->handle(msg);
+ }
+}
+
+void pager_flex_parse::parse_alphanumeric(int mw1, int mw2, int j)
+{
+ int frag;
+ bool cont;
+
+ if (!d_laddr) {
+ frag = (d_datawords[mw1] >> 11) & 0x03;
+ cont = (d_datawords[mw1] >> 10) & 0x01;
+ mw1++;
+ }
+ else {
+ frag = (d_datawords[j+1] >> 11) & 0x03;
+ cont = (d_datawords[j+1] >> 10) & 0x01;
+ mw2--;
+ }
+
+ d_payload << frag << FIELD_DELIM;
+ d_payload << cont << FIELD_DELIM;
+
+ for (int i = mw1; i <= mw2; i++) {
+ gr_int32 dw = d_datawords[i];
+ unsigned char ch;
+
+ if (i > mw1 || frag != 0x03) {
+ ch = dw & 0x7F;
+ if (ch != 0x03)
+ d_payload << ch;
+ }
+
+ ch = (dw >> 7) & 0x7F;
+ if (ch != 0x03) // Fill
+ d_payload << ch;
+
+ ch = (dw >> 14) & 0x7F;
+ if (ch != 0x03) // Fill
+ d_payload << ch;
+ }
+}
+
+void pager_flex_parse::parse_numeric(int mw1, int mw2, int j)
+{
+ // Get first dataword from message field or from second
+ // vector word if long address
+ gr_int32 dw;
+ if (!d_laddr) {
+ dw = d_datawords[mw1];
+ mw1++;
+ mw2++;
+ }
+ else {
+ dw = d_datawords[j+1];
+ }
+
+ unsigned char digit = 0;
+ int count = 4;
+ if (d_type == FLEX_NUMBERED_NUMERIC)
+ count += 10; // Skip 10 header bits for numbered numeric pages
+ else
+ count += 2; // Otherwise skip 2
+
+ for (int i = mw1; i <= mw2; i++) {
+ for (int k = 0; k < 21; k++) {
+ // Shift LSB from data word into digit
+ digit = (digit >> 1) & 0x0F;
+ if (dw & 0x01)
+ digit ^= 0x08;
+ dw >>= 1;
+ if (--count == 0) {
+ if (digit != 0x0C) // Fill
+ d_payload << flex_bcd[digit];
+ count = 4;
+ }
+ }
+
+ dw = d_datawords[i];
+ }
+}
+
+void pager_flex_parse::parse_tone_only()
+{
+}
+
+void pager_flex_parse::parse_unknown(int mw1, int mw2)
+{
+}
diff --git a/gr-pager/src/pager_flex_parse.h b/gr-pager/src/pager_flex_parse.h
new file mode 100644
index 000000000..e5a225b28
--- /dev/null
+++ b/gr-pager/src/pager_flex_parse.h
@@ -0,0 +1,72 @@
+/*
+ * 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 <gr_msg_queue.h>
+#include <pageri_flex_modes.h>
+#include <sstream>
+
+class pager_flex_parse;
+typedef boost::shared_ptr<pager_flex_parse> pager_flex_parse_sptr;
+
+pager_flex_parse_sptr pager_make_flex_parse(gr_msg_queue_sptr queue);
+
+/*!
+ * \brief flex parse description
+ * \ingroup block
+ */
+
+#define FIELD_DELIM ((unsigned char)128)
+
+class pager_flex_parse : public gr_sync_block
+{
+private:
+ // Constructors
+ friend pager_flex_parse_sptr pager_make_flex_parse(gr_msg_queue_sptr queue);
+ pager_flex_parse(gr_msg_queue_sptr queue);
+
+ std::ostringstream d_payload;
+ gr_msg_queue_sptr d_queue; // Destination for decoded pages
+
+ 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, int j);
+ void parse_numeric(int mw1, int mw2, int j);
+ 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..c4e5f7c02
--- /dev/null
+++ b/gr-pager/src/pager_flex_sync.cc
@@ -0,0 +1,341 @@
+/*
+ * 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;
+
+ //printf("CYC:%02i FRM:%03i\n", d_cycle, d_frame);
+}
+
+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
index 000000000..813b7cf26
--- /dev/null
+++ b/gr-pager/src/pager_flex_sync.h
@@ -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 */
diff --git a/gr-pager/src/pager_slicer_fb.cc b/gr-pager/src/pager_slicer_fb.cc
new file mode 100644
index 000000000..98e8a2b00
--- /dev/null
+++ b/gr-pager/src/pager_slicer_fb.cc
@@ -0,0 +1,100 @@
+/*
+ * 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_slicer_fb.h>
+#include <gr_io_signature.h>
+
+pager_slicer_fb_sptr pager_make_slicer_fb(float alpha, float beta)
+{
+ return pager_slicer_fb_sptr(new pager_slicer_fb(alpha, beta));
+}
+
+pager_slicer_fb::pager_slicer_fb(float alpha, float beta) :
+ gr_sync_block ("slicer_fb",
+ gr_make_io_signature (1, 1, sizeof(float)),
+ gr_make_io_signature (1, 1, sizeof(unsigned char)))
+{
+ d_alpha = alpha;
+ d_beta = beta;
+ d_max = 0.0;
+ d_hi = 0.0;
+ d_avg = 0.0;
+ d_lo = 0.0;
+ d_min = 0.0;
+}
+
+// Tracks average, minimum, and peak, then converts input into one of:
+//
+// [0, 1, 2, 3]
+unsigned char pager_slicer_fb::slice(float sample)
+{
+ unsigned char decision;
+
+ // Update DC level and remove
+ d_avg = d_avg*(1.0-d_alpha)+sample*d_alpha;
+ sample -= d_avg;
+
+ if (sample > 0) {
+ if (sample > d_hi) { // In max region
+ d_max = d_max*(1.0-d_alpha) + sample*d_alpha;
+ decision = 3;
+ }
+ else {
+ d_max -= (d_max-d_avg)*d_beta; // decay otherwise
+ decision = 2;
+ }
+ }
+ else {
+ if (sample < d_lo) { // In min region
+ d_min = d_min*(1.0-d_alpha) + sample*d_alpha;
+ decision = 0;
+ }
+ else {
+ d_min -= (d_min-d_avg)*d_beta; // decay otherwise
+ decision = 1;
+ }
+ }
+
+ d_hi = d_max*2.0/3.0;
+ d_lo = d_min*2.0/3.0;
+
+ //fprintf(stderr, "%f %d\n", sample, decision);
+ return decision;
+}
+
+int pager_slicer_fb::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ float *iptr = (float *) input_items[0];
+ unsigned char *optr = (unsigned char *) output_items[0];
+
+ int size = noutput_items;
+
+ for (int i = 0; i < size; i++)
+ *optr++ = slice(*iptr++);
+
+ return noutput_items;
+}
diff --git a/gr-pager/src/pager_slicer_fb.h b/gr-pager/src/pager_slicer_fb.h
new file mode 100644
index 000000000..4751bb47e
--- /dev/null
+++ b/gr-pager/src/pager_slicer_fb.h
@@ -0,0 +1,58 @@
+/*
+ * 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_SLICER_FB_H
+#define INCLUDED_PAGER_SLICER_FB_H
+
+#include <gr_sync_block.h>
+
+class pager_slicer_fb;
+typedef boost::shared_ptr<pager_slicer_fb> pager_slicer_fb_sptr;
+
+pager_slicer_fb_sptr pager_make_slicer_fb(float alpha, float beta);
+
+/*!
+ * \brief slicer description
+ * \ingroup block
+ */
+class pager_slicer_fb : public gr_sync_block
+{
+private:
+ friend pager_slicer_fb_sptr pager_make_slicer_fb(float alpha, float beta);
+ pager_slicer_fb(float alpha, float beta);
+
+ unsigned char slice(float sample);
+
+ float d_alpha; // Attack constant
+ float d_beta; // Decay constant
+ float d_max; // Maximum value for symbol comparison
+ float d_hi; // High side decision boundary
+ float d_avg; // Average value for DC offset subtraction
+ float d_lo; // Low side decision boundary
+ float d_min; // Minimum value for symbol comparison
+
+public:
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_PAGER_SLICER_FB_H */
diff --git a/gr-pager/src/pageri_bch3221.cc b/gr-pager/src/pageri_bch3221.cc
new file mode 100644
index 000000000..48ef75cbf
--- /dev/null
+++ b/gr-pager/src/pageri_bch3221.cc
@@ -0,0 +1,36 @@
+/*
+ * 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_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_bch3221.h b/gr-pager/src/pageri_bch3221.h
new file mode 100644
index 000000000..c4767b231
--- /dev/null
+++ b/gr-pager/src/pageri_bch3221.h
@@ -0,0 +1,31 @@
+/*
+ * 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_BCH3221_H
+#define INCLUDED_PAGERI_BCH3221_H
+
+#include <gr_types.h>
+
+// Perform BCH (32,21) error correction on supplied data
+// Return number of errors found/corrected (0, 1, or 2)
+int pageri_bch3221(gr_int32 &data);
+
+#endif /* INCLUDED_PAGERI_BCH3221_H */
diff --git a/gr-pager/src/pageri_flex_modes.cc b/gr-pager/src/pageri_flex_modes.cc
new file mode 100644
index 000000000..b2bb4e29c
--- /dev/null
+++ b/gr-pager/src/pageri_flex_modes.cc
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include "pageri_flex_modes.h"
+
+const flex_mode_t flex_modes[] =
+{
+ { 0x870C78F3, 1600, 2 },
+ { 0xB0684F97, 1600, 4 },
+// { 0xUNKNOWN, 3200, 2 },
+ { 0xDEA0215F, 3200, 4 },
+ { 0x4C7CB383, 3200, 4 }
+};
+
+const int num_flex_modes = sizeof(flex_modes)/sizeof(flex_modes[0]);
+
+unsigned char flex_bcd[17] = "0123456789 U -][";
+
+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
new file mode 100644
index 000000000..09e5952b9
--- /dev/null
+++ b/gr-pager/src/pageri_flex_modes.h
@@ -0,0 +1,73 @@
+/*
+ * 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_FLEX_MODES_H
+#define INCLUDED_PAGERI_FLEX_MODES_H
+
+#include <gr_types.h>
+
+#define FLEX_SYNC_MARKER 0xA6C6AAAA
+
+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
+}
+flex_mode_t;
+
+extern const flex_mode_t flex_modes[];
+extern const int num_flex_modes;
+int find_flex_mode(gr_int32 sync_code);
+extern unsigned char flex_bcd[];
+
+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/qa_pager.py b/gr-pager/src/qa_pager.py
new file mode 100755
index 000000000..5b9a3996c
--- /dev/null
+++ b/gr-pager/src/qa_pager.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+from gnuradio import gr, gr_unittest
+import pager_swig
+
+class qa_pgr(gr_unittest.TestCase):
+
+ def setUp (self):
+ self.fg = gr.flow_graph ()
+
+ def tearDown (self):
+ self.fg = None
+
+if __name__ == '__main__':
+ gr_unittest.main ()
diff --git a/gr-pager/src/run_tests.in b/gr-pager/src/run_tests.in
new file mode 100644
index 000000000..6bb0c3980
--- /dev/null
+++ b/gr-pager/src/run_tests.in
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# 1st parameter is absolute path to component source directory
+# 2nd parameter is absolute path to component build directory
+# 3rd parameter is path to Python QA directory
+
+@top_builddir@/run_tests.sh \
+ @abs_top_srcdir@/gr-pager \
+ @abs_top_builddir@/gr-pager \
+ @srcdir@
diff --git a/gr-pager/src/usrp_flex.py b/gr-pager/src/usrp_flex.py
new file mode 100755
index 000000000..055583c99
--- /dev/null
+++ b/gr-pager/src/usrp_flex.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+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 string import split, join
+
+"""
+This example application demonstrates receiving and demodulating the
+FLEX pager protocol.
+
+A receive chain is built up of the following signal processing
+blocks:
+
+USRP - Daughter board source generating complex baseband signal.
+CHAN - Low pass filter to select channel bandwidth
+AGC - Automatic gain control leveling signal at [-1.0, +1.0]
+FLEX - FLEX pager protocol decoder
+
+The following are required command line parameters:
+
+-f FREQ USRP receive frequency
+
+The following are optional command line parameters:
+
+-R SUBDEV Daughter board specification, defaults to first found
+-c FREQ Calibration offset. Gets added to receive frequency.
+ Defaults to 0.0 Hz.
+-g GAIN Daughterboard gain setting. Defaults to mid-range.
+-r RFSQL RF squelch in db. Defaults to -50.0.
+
+Once the program is running, ctrl-break (Ctrl-C) stops operation.
+"""
+
+class usrp_source_c(gr.hier_block):
+ """
+ Create a USRP source object supplying complex floats.
+
+ Selects user supplied subdevice or chooses first available one.
+
+ Calibration value is the offset from the tuned frequency to
+ the actual frequency.
+ """
+ def __init__(self, fg, subdev_spec, decim, gain=None, calibration=0.0):
+ self._decim = decim
+ self._src = usrp.source_c()
+ if subdev_spec is None:
+ subdev_spec = usrp.pick_rx_subdevice(self._src)
+ self._subdev = usrp.selected_subdev(self._src, subdev_spec)
+ self._src.set_mux(usrp.determine_rx_mux_value(self._src, subdev_spec))
+ self._src.set_decim_rate(self._decim)
+
+ # If no gain specified, set to midrange
+ if gain is None:
+ g = self._subdev.gain_range()
+ gain = (g[0]+g[1])/2.0
+
+ self._subdev.set_gain(gain)
+ self._cal = calibration
+
+ gr.hier_block.__init__(self, fg, self._src, self._src)
+
+ def tune(self, freq):
+ result = usrp.tune(self._src, 0, self._subdev, freq+self._cal)
+ # TODO: deal with residual
+
+ def rate(self):
+ return self._src.adc_rate()/self._decim
+
+class app_flow_graph(gr.flow_graph):
+ def __init__(self, options, args, queue):
+ gr.flow_graph.__init__(self)
+ self.options = options
+ self.args = args
+
+ USRP = usrp_source_c(self, # Flow graph
+ options.rx_subdev_spec, # Daugherboard spec
+ 256, # IF decimation ratio gets 250K if_rate
+ options.gain, # Receiver gain
+ options.calibration) # Frequency offset
+ USRP.tune(options.frequency)
+
+ if_rate = USRP.rate()
+ channel_rate = 25000
+ channel_decim = int(if_rate / channel_rate)
+
+ 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
+
+ CHAN = gr.freq_xlating_fir_filter_ccf(channel_decim, # Decimation rate
+ CHAN_taps, # Filter taps
+ 0.0, # Offset frequency
+ if_rate) # Sample rate
+
+ AGC = gr.agc_cc(1.0/channel_rate, # Time constant
+ 1.0, # Reference power
+ 1.0, # Initial gain
+ 1.0) # Maximum gain
+
+ FLEX = pager.flex_demod(self, 25000, queue)
+
+ self.connect(USRP, CHAN, AGC, FLEX.INPUT)
+
+def main():
+ parser = OptionParser(option_class=eng_option)
+ parser.add_option("-f", "--frequency", type="eng_float",
+ help="set receive frequency to Hz", metavar="Hz")
+ parser.add_option("-R", "--rx-subdev-spec", type="subdev",
+ help="select USRP Rx side A or B", metavar="SUBDEV")
+ parser.add_option("-c", "--calibration", type="eng_float", default=0.0,
+ help="set frequency offset to Hz", metavar="Hz")
+ parser.add_option("-g", "--gain", type="int", default=None,
+ help="set RF gain", metavar="dB")
+ (options, args) = parser.parse_args()
+
+ if options.frequency < 1e6:
+ options.frequency *= 1e6
+
+ queue = gr.msg_queue()
+
+ fg = app_flow_graph(options, args, queue)
+ try:
+ fg.start()
+ while 1:
+ msg = queue.delete_head() # Blocking read
+ fields = split(msg.to_string(), chr(128))
+ print join(fields, '|')
+
+ except KeyboardInterrupt:
+ fg.stop()
+
+if __name__ == "__main__":
+ main()