From d1e3108c8705289d194300ca9fad1c22f579be9b Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Wed, 12 Oct 2011 16:57:51 -0400
Subject: digital: moved narrowband examples to their own directory (to make
 room for OFDM examples).

---
 .../examples/narrowband/benchmark_add_channel.py   | 101 ++++++++
 gr-digital/examples/narrowband/benchmark_rx.py     | 134 ++++++++++
 gr-digital/examples/narrowband/benchmark_tx.py     | 147 +++++++++++
 gr-digital/examples/narrowband/digital_bert_rx.py  | 209 +++++++++++++++
 gr-digital/examples/narrowband/digital_bert_tx.py  | 135 ++++++++++
 gr-digital/examples/narrowband/receive_path.py     | 142 +++++++++++
 gr-digital/examples/narrowband/rx_voice.py         | 164 ++++++++++++
 gr-digital/examples/narrowband/transmit_path.py    | 126 +++++++++
 gr-digital/examples/narrowband/tunnel.py           | 283 +++++++++++++++++++++
 gr-digital/examples/narrowband/tx_voice.py         | 171 +++++++++++++
 gr-digital/examples/narrowband/uhd_interface.py    | 219 ++++++++++++++++
 11 files changed, 1831 insertions(+)
 create mode 100755 gr-digital/examples/narrowband/benchmark_add_channel.py
 create mode 100755 gr-digital/examples/narrowband/benchmark_rx.py
 create mode 100755 gr-digital/examples/narrowband/benchmark_tx.py
 create mode 100755 gr-digital/examples/narrowband/digital_bert_rx.py
 create mode 100755 gr-digital/examples/narrowband/digital_bert_tx.py
 create mode 100644 gr-digital/examples/narrowband/receive_path.py
 create mode 100755 gr-digital/examples/narrowband/rx_voice.py
 create mode 100644 gr-digital/examples/narrowband/transmit_path.py
 create mode 100755 gr-digital/examples/narrowband/tunnel.py
 create mode 100755 gr-digital/examples/narrowband/tx_voice.py
 create mode 100644 gr-digital/examples/narrowband/uhd_interface.py

(limited to 'gr-digital/examples/narrowband')

diff --git a/gr-digital/examples/narrowband/benchmark_add_channel.py b/gr-digital/examples/narrowband/benchmark_add_channel.py
new file mode 100755
index 0000000000..def1f8267e
--- /dev/null
+++ b/gr-digital/examples/narrowband/benchmark_add_channel.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#
+# Copyright 2010,2011 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 3, 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
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+import random, math, sys
+
+class my_top_block(gr.top_block):
+    def __init__(self, ifile, ofile, options):
+        gr.top_block.__init__(self)
+
+        SNR = 10.0**(options.snr/10.0)
+        frequency_offset = options.frequency_offset
+        time_offset = options.time_offset
+        phase_offset = options.phase_offset*(math.pi/180.0)
+
+        # calculate noise voltage from SNR
+        # FIXME: normalize to signal amplitude
+        power_in_signal = abs(1.0)**2
+        noise_power = power_in_signal/SNR
+        noise_voltage = math.sqrt(noise_power)
+        print noise_voltage
+
+        self.src = gr.file_source(gr.sizeof_gr_complex, ifile)
+        #self.throttle = gr.throttle(gr.sizeof_gr_complex, options.sample_rate)
+        self.channel = gr.channel_model(noise_voltage, frequency_offset,
+                                        time_offset, noise_seed=random.randint(0,100000))
+        self.phase = gr.multiply_const_cc(complex(math.cos(phase_offset),
+                                                  math.sin(phase_offset)))
+        self.snk = gr.file_sink(gr.sizeof_gr_complex, ofile)
+
+        self.connect(self.src, self.channel, self.phase, self.snk)
+        
+
+# /////////////////////////////////////////////////////////////////////////////
+#                                   main
+# /////////////////////////////////////////////////////////////////////////////
+
+def main():
+    # Create Options Parser:
+    usage = "benchmack_add_channel.py [options] <input file> <output file>"
+    parser = OptionParser (usage=usage, option_class=eng_option, conflict_handler="resolve")
+    parser.add_option("-n", "--snr", type="eng_float", default=30,
+                      help="set the SNR of the channel in dB [default=%default]")
+    parser.add_option("", "--seed", action="store_true", default=False,
+                      help="use a random seed for AWGN noise [default=%default]")
+    parser.add_option("-f", "--frequency-offset", type="eng_float", default=0,
+                      help="set frequency offset introduced by channel [default=%default]")
+    parser.add_option("-t", "--time-offset", type="eng_float", default=1.0,
+                      help="set timing offset between Tx and Rx [default=%default]")
+    parser.add_option("-p", "--phase-offset", type="eng_float", default=0,
+                      help="set phase offset (in degrees) between Tx and Rx [default=%default]")
+    parser.add_option("-m", "--use-multipath", action="store_true", default=False,
+                      help="Use a multipath channel [default=%default]")
+
+    (options, args) = parser.parse_args ()
+
+    if len(args) != 2:
+        parser.print_help(sys.stderr)
+        sys.exit(1)
+
+    ifile = args[0]
+    ofile = args[1]
+        
+    # build the graph
+    tb = my_top_block(ifile, ofile, options)
+
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: Failed to enable realtime scheduling."
+
+    tb.start()        # start flow graph
+    tb.wait()         # wait for it to finish
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
diff --git a/gr-digital/examples/narrowband/benchmark_rx.py b/gr-digital/examples/narrowband/benchmark_rx.py
new file mode 100755
index 0000000000..a8a2e92c49
--- /dev/null
+++ b/gr-digital/examples/narrowband/benchmark_rx.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+#
+# Copyright 2010,2011 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 3, 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
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+# From gr-digital
+from gnuradio import digital
+
+# from current dir
+from receive_path import receive_path
+from uhd_interface import uhd_receiver
+
+import struct
+import sys
+
+#import os
+#print os.getpid()
+#raw_input('Attach and press enter: ')
+
+class my_top_block(gr.top_block):
+    def __init__(self, demodulator, rx_callback, options):
+        gr.top_block.__init__(self)
+
+        if(options.rx_freq is not None):
+            self.source = uhd_receiver(options.address, options.bitrate,
+                                       options.samples_per_symbol,
+                                       options.rx_freq, options.rx_gain,
+                                       options.antenna, options.verbose)
+            options.samples_per_symbol = self.source._sps
+
+        elif(options.from_file is not None):
+            self.source = gr.file_source(gr.sizeof_gr_complex, options.from_file)
+        else:
+            self.source = gr.null_source(gr.sizeof_gr_complex)
+
+        # Set up receive path
+        # do this after for any adjustments to the options that may
+        # occur in the sinks (specifically the UHD sink)
+        self.rxpath = receive_path(demodulator, rx_callback, options) 
+
+        self.connect(self.source, self.rxpath)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#                                   main
+# /////////////////////////////////////////////////////////////////////////////
+
+global n_rcvd, n_right
+
+def main():
+    global n_rcvd, n_right
+
+    n_rcvd = 0
+    n_right = 0
+    
+    def rx_callback(ok, payload):
+        global n_rcvd, n_right
+        (pktno,) = struct.unpack('!H', payload[0:2])
+        n_rcvd += 1
+        if ok:
+            n_right += 1
+
+        print "ok = %5s  pktno = %4d  n_rcvd = %4d  n_right = %4d" % (
+            ok, pktno, n_rcvd, n_right)
+
+    demods = digital.modulation_utils2.type_1_demods()
+
+    # Create Options Parser:
+    parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
+    expert_grp = parser.add_option_group("Expert")
+
+    parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), 
+                      default='psk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(demods.keys()),))
+    parser.add_option("","--from-file", default=None,
+                      help="input file of samples to demod")
+
+    receive_path.add_options(parser, expert_grp)
+    uhd_receiver.add_options(parser)
+
+    for mod in demods.values():
+        mod.add_options(expert_grp)
+
+    (options, args) = parser.parse_args ()
+
+    if len(args) != 0:
+        parser.print_help(sys.stderr)
+        sys.exit(1)
+
+    if options.from_file is None:
+        if options.rx_freq is None:
+            sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
+            parser.print_help(sys.stderr)
+            sys.exit(1)
+
+
+    # build the graph
+    tb = my_top_block(demods[options.modulation], rx_callback, options)
+
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: Failed to enable realtime scheduling."
+
+    tb.start()        # start flow graph
+    tb.wait()         # wait for it to finish
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
diff --git a/gr-digital/examples/narrowband/benchmark_tx.py b/gr-digital/examples/narrowband/benchmark_tx.py
new file mode 100755
index 0000000000..39b0066f4b
--- /dev/null
+++ b/gr-digital/examples/narrowband/benchmark_tx.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+#
+# Copyright 2010,2011 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 3, 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
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+# From gr-digital
+from gnuradio import digital
+
+# from current dir
+from transmit_path import transmit_path
+from uhd_interface import uhd_transmitter
+
+import time, struct, sys
+
+#import os 
+#print os.getpid()
+#raw_input('Attach and press enter')
+
+class my_top_block(gr.top_block):
+    def __init__(self, modulator, options):
+        gr.top_block.__init__(self)
+
+        if(options.tx_freq is not None):
+            self.sink = uhd_transmitter(options.address, options.bitrate,
+                                        options.samples_per_symbol,
+                                        options.tx_freq, options.tx_gain,
+                                        options.antenna, options.verbose)
+            options.samples_per_symbol = self.sink._sps
+            
+        elif(options.to_file is not None):
+            self.sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file)
+        else:
+            self.sink = gr.null_sink(gr.sizeof_gr_complex)
+
+        # do this after for any adjustments to the options that may
+        # occur in the sinks (specifically the UHD sink)
+        self.txpath = transmit_path(modulator, options)
+
+        self.connect(self.txpath, self.sink)
+
+# /////////////////////////////////////////////////////////////////////////////
+#                                   main
+# /////////////////////////////////////////////////////////////////////////////
+
+def main():
+
+    def send_pkt(payload='', eof=False):
+        return tb.txpath.send_pkt(payload, eof)
+
+    mods = digital.modulation_utils2.type_1_mods()
+
+    parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+    expert_grp = parser.add_option_group("Expert")
+
+    parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
+                      default='psk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(mods.keys()),))
+
+    parser.add_option("-s", "--size", type="eng_float", default=1500,
+                      help="set packet size [default=%default]")
+    parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
+                      help="set megabytes to transmit [default=%default]")
+    parser.add_option("","--discontinuous", action="store_true", default=False,
+                      help="enable discontinous transmission (bursts of 5 packets)")
+    parser.add_option("","--from-file", default=None,
+                      help="use intput file for packet contents")
+    parser.add_option("","--to-file", default=None,
+                      help="Output file for modulated samples")
+
+    transmit_path.add_options(parser, expert_grp)
+    uhd_transmitter.add_options(parser)
+
+    for mod in mods.values():
+        mod.add_options(expert_grp)
+
+    (options, args) = parser.parse_args ()
+
+    if len(args) != 0:
+        parser.print_help()
+        sys.exit(1)
+           
+    if options.from_file is not None:
+        source_file = open(options.from_file, 'r')
+
+    # build the graph
+    tb = my_top_block(mods[options.modulation], options)
+
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: failed to enable realtime scheduling"
+
+    tb.start()                       # start flow graph
+        
+    # generate and send packets
+    nbytes = int(1e6 * options.megabytes)
+    n = 0
+    pktno = 0
+    pkt_size = int(options.size)
+
+    while n < nbytes:
+        if options.from_file is None:
+            data = (pkt_size - 2) * chr(pktno & 0xff) 
+        else:
+            data = source_file.read(pkt_size - 2)
+            if data == '':
+                break;
+
+        payload = struct.pack('!H', pktno & 0xffff) + data
+        send_pkt(payload)
+        n += len(payload)
+        sys.stderr.write('.')
+        if options.discontinuous and pktno % 5 == 4:
+            time.sleep(1)
+        pktno += 1
+        
+    send_pkt(eof=True)
+
+    tb.wait()                       # wait for it to finish
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
diff --git a/gr-digital/examples/narrowband/digital_bert_rx.py b/gr-digital/examples/narrowband/digital_bert_rx.py
new file mode 100755
index 0000000000..9ee1f5ee84
--- /dev/null
+++ b/gr-digital/examples/narrowband/digital_bert_rx.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python
+#
+# Copyright 2008,2011 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 3, 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, eng_notation
+from optparse import OptionParser
+from gnuradio.eng_option import eng_option
+import gnuradio.gr.gr_threading as _threading
+import sys, time, math
+
+from gnuradio import digital
+
+# from current dir
+from uhd_interface import uhd_receiver
+
+n2s = eng_notation.num_to_str
+
+class status_thread(_threading.Thread):
+    def __init__(self, tb):
+        _threading.Thread.__init__(self)
+        self.setDaemon(1)
+        self.tb = tb
+        self.done = False
+        self.start()
+
+    def run(self):
+        while not self.done:
+            print "Freq. Offset: {0:5.0f} Hz  Timing Offset: {1:10.1f} ppm  Estimated SNR: {2:4.1f} dB  BER: {3:g}".format(
+                tb.frequency_offset(), tb.timing_offset()*1e6, tb.snr(), tb.ber())
+            try:
+                time.sleep(1.0)
+            except KeyboardInterrupt:
+                self.done = True
+
+
+
+class bert_receiver(gr.hier_block2):
+    def __init__(self, bitrate,
+                 constellation, samples_per_symbol,
+                 differential, excess_bw, gray_coded,
+                 freq_bw, timing_bw, phase_bw,
+                 verbose, log):
+
+        gr.hier_block2.__init__(self, "bert_receive",
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                                gr.io_signature(0, 0, 0))                    # Output signature
+        
+        self._bitrate = bitrate
+
+        self._demod = digital.generic_demod(constellation, samples_per_symbol,
+                                            differential, excess_bw, gray_coded,
+                                            freq_bw, timing_bw, phase_bw,
+                                            verbose, log)
+
+        self._symbol_rate = self._bitrate * self._demod.bits_per_symbol()
+        self._sample_rate = self._symbol_rate * samples_per_symbol
+
+        # Add an SNR probe on the demodulated constellation
+        self._snr_probe = gr.probe_mpsk_snr_c(10.0/self._symbol_rate)
+        self.connect(self._demod.time_recov, self._snr_probe)
+        
+        # Descramble BERT sequence.  A channel error will create 3 incorrect bits
+        self._descrambler = gr.descrambler_bb(0x8A, 0x7F, 7) # CCSDS 7-bit descrambler
+
+        # Measure BER by the density of 0s in the stream
+        self._ber = gr.probe_density_b(1.0/self._symbol_rate)
+        
+        self.connect(self, self._demod, self._descrambler, self._ber)
+
+    def frequency_offset(self):
+        return self._demod.freq_recov.get_frequency()*self._sample_rate/(2*math.pi)
+
+    def timing_offset(self):
+        return self._demod.time_recov.get_clock_rate()
+
+    def snr(self):
+        return self._snr_probe.snr()
+
+    def ber(self):
+        return (1.0-self._ber.density())/3.0
+
+
+
+class rx_psk_block(gr.top_block):
+    def __init__(self, demod, options):
+
+	gr.top_block.__init__(self, "rx_mpsk")
+
+        self._demodulator_class = demod
+
+        # Get demod_kwargs
+        demod_kwargs = self._demodulator_class.extract_kwargs_from_options(options)
+        
+        # demodulator
+	self._demodulator = self._demodulator_class(**demod_kwargs)
+
+        if(options.rx_freq is not None):
+            self._source = uhd_receiver(options.address, options.bitrate,
+                                        options.samples_per_symbol,
+                                        options.rx_freq, options.rx_gain,
+                                        options.antenna, options.verbose)
+            options.samples_per_symbol = self._source._sps
+
+        elif(options.from_file is not None):
+            self._source = gr.file_source(gr.sizeof_gr_complex, options.from_file)
+        else:
+            self._source = gr.null_source(gr.sizeof_gr_complex)
+
+        # Create the BERT receiver
+        self._receiver = bert_receiver(options.bitrate,
+                                       self._demodulator._constellation, 
+                                       options.samples_per_symbol,
+                                       options.differential, 
+                                       options.excess_bw, 
+                                       gray_coded=True,
+                                       freq_bw=options.freq_bw,
+                                       timing_bw=options.timing_bw,
+                                       phase_bw=options.phase_bw,
+                                       verbose=options.verbose,
+                                       log=options.log)
+        
+        self.connect(self._source, self._receiver)
+
+    def snr(self):
+        return self._receiver.snr()
+
+    def mag(self):
+        return self._receiver.signal_mean()
+        
+    def var(self):
+        return self._receiver.noise_variance()
+
+    def ber(self):
+        return self._receiver.ber()
+
+    def frequency_offset(self):
+        return self._receiver.frequency_offset()
+        
+    def timing_offset(self):
+        return self._receiver.timing_offset()
+            
+
+def get_options(demods):
+    parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+    parser.add_option("","--from-file", default=None,
+                      help="input file of samples to demod")
+    parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), 
+                      default='psk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(demods.keys()),))
+    parser.add_option("-r", "--bitrate", type="eng_float", default=250e3,
+                      help="Select modulation bit rate (default=%default)")
+    parser.add_option("-S", "--samples-per-symbol", type="float", default=2,
+                      help="set samples/symbol [default=%default]")
+    if not parser.has_option("--verbose"):
+        parser.add_option("-v", "--verbose", action="store_true", default=False)
+    if not parser.has_option("--log"):
+        parser.add_option("", "--log", action="store_true", default=False,
+                      help="Log all parts of flow graph to files (CAUTION: lots of data)")
+
+    uhd_receiver.add_options(parser)
+
+    demods = digital.modulation_utils2.type_1_demods()
+    for mod in demods.values():
+        mod.add_options(parser)
+		      
+    (options, args) = parser.parse_args()
+    if len(args) != 0:
+        parser.print_help()
+        sys.exit(1)
+	
+    return (options, args)
+
+
+if __name__ == "__main__":
+    demods = digital.modulation_utils2.type_1_demods()
+
+    (options, args) = get_options(demods)
+
+    demod = demods[options.modulation]
+    tb = rx_psk_block(demod, options)
+
+    print "\n*** SNR estimator is inaccurate below about 7dB"
+    print "*** BER estimator is inaccurate above about 10%\n"
+    updater = status_thread(tb)
+
+    try:
+        tb.run()
+    except KeyboardInterrupt:
+        updater.done = True
+        updater = None
diff --git a/gr-digital/examples/narrowband/digital_bert_tx.py b/gr-digital/examples/narrowband/digital_bert_tx.py
new file mode 100755
index 0000000000..6b544c7f73
--- /dev/null
+++ b/gr-digital/examples/narrowband/digital_bert_tx.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+#
+# Copyright 2008,2011 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 3, 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, eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+import sys
+
+from gnuradio import digital
+
+# from current dir
+from uhd_interface import uhd_transmitter
+
+n2s = eng_notation.num_to_str
+
+class bert_transmit(gr.hier_block2):
+    def __init__(self, constellation, samples_per_symbol,
+                 differential, excess_bw, gray_coded,
+                 verbose, log):
+
+        gr.hier_block2.__init__(self, "bert_transmit",
+                                gr.io_signature(0, 0, 0),                    # Output signature
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Input signature
+        
+        # Create BERT data bit stream	
+	self._bits = gr.vector_source_b([1,], True)      # Infinite stream of ones
+        self._scrambler = gr.scrambler_bb(0x8A, 0x7F, 7) # CCSDS 7-bit scrambler
+
+        self._mod = digital.generic_mod(constellation, samples_per_symbol,
+                                        differential, excess_bw, gray_coded,
+                                        verbose, log)
+
+        self._pack = gr.unpacked_to_packed_bb(self._mod.bits_per_symbol(), gr.GR_MSB_FIRST)
+
+        self.connect(self._bits, self._scrambler, self._pack, self._mod, self)
+
+
+class tx_psk_block(gr.top_block):
+    def __init__(self, mod, options):
+	gr.top_block.__init__(self, "tx_mpsk")
+
+        self._modulator_class = mod
+
+        # Get mod_kwargs
+        mod_kwargs = self._modulator_class.extract_kwargs_from_options(options)
+        
+        # transmitter
+	self._modulator = self._modulator_class(**mod_kwargs)
+
+        if(options.tx_freq is not None):
+            self._sink = uhd_transmitter(options.address, options.bitrate,
+                                         options.samples_per_symbol,
+                                         options.tx_freq, options.tx_gain,
+                                         options.antenna, options.verbose)
+            options.samples_per_symbol = self._sink._sps
+            
+        elif(options.to_file is not None):
+            self._sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file)
+        else:
+            self._sink = gr.null_sink(gr.sizeof_gr_complex)
+            
+            
+        self._transmitter = bert_transmit(self._modulator._constellation,
+                                          options.samples_per_symbol,
+                                          options.differential,
+                                          options.excess_bw,
+                                          gray_coded=True,
+                                          verbose=options.verbose,
+                                          log=options.log)
+
+	self.connect(self._transmitter, self._sink)
+
+
+def get_options(mods):
+    parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+    parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
+                      default='psk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(mods.keys()),))
+    parser.add_option("", "--amplitude", type="eng_float", default=0.2,
+                      help="set Tx amplitude (0-1) (default=%default)")
+    parser.add_option("-r", "--bitrate", type="eng_float", default=250e3,
+                      help="Select modulation bit rate (default=%default)")
+    parser.add_option("-S", "--samples-per-symbol", type="float", default=2,
+                      help="set samples/symbol [default=%default]")
+    parser.add_option("","--to-file", default=None,
+                      help="Output file for modulated samples")
+    if not parser.has_option("--verbose"):
+        parser.add_option("-v", "--verbose", action="store_true", default=False)
+    if not parser.has_option("--log"):
+        parser.add_option("", "--log", action="store_true", default=False)
+
+    uhd_transmitter.add_options(parser)
+
+    for mod in mods.values():
+        mod.add_options(parser)
+		      
+    (options, args) = parser.parse_args()
+    if len(args) != 0:
+        parser.print_help()
+        sys.exit(1)
+	
+    return (options, args)
+
+if __name__ == "__main__":
+    mods = digital.modulation_utils2.type_1_mods()
+
+    (options, args) = get_options(mods)
+    
+    mod = mods[options.modulation]
+    tb = tx_psk_block(mod, options)
+
+    try:
+        tb.run()
+    except KeyboardInterrupt:
+        pass
diff --git a/gr-digital/examples/narrowband/receive_path.py b/gr-digital/examples/narrowband/receive_path.py
new file mode 100644
index 0000000000..92c77173ed
--- /dev/null
+++ b/gr-digital/examples/narrowband/receive_path.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2011 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 3, 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
+from gnuradio import eng_notation
+from gnuradio import digital
+
+import copy
+import sys
+
+# /////////////////////////////////////////////////////////////////////////////
+#                              receive path
+# /////////////////////////////////////////////////////////////////////////////
+
+class receive_path(gr.hier_block2):
+    def __init__(self, demod_class, rx_callback, options):
+	gr.hier_block2.__init__(self, "receive_path",
+				gr.io_signature(1, 1, gr.sizeof_gr_complex),
+				gr.io_signature(0, 0, 0))
+        
+        options = copy.copy(options)    # make a copy so we can destructively modify
+
+        self._verbose     = options.verbose
+        self._bitrate     = options.bitrate  # desired bit rate
+
+        self._rx_callback = rx_callback  # this callback is fired when a packet arrives
+        self._demod_class = demod_class  # the demodulator_class we're using
+
+        # Get demod_kwargs
+        demod_kwargs = self._demod_class.extract_kwargs_from_options(options)
+
+        # Build the demodulator
+        self.demodulator = self._demod_class(**demod_kwargs)
+        
+        # Design filter to get actual channel we want
+        sw_decim = 1
+        chan_coeffs = gr.firdes.low_pass (1.0,                  # gain
+                                          sw_decim * self.samples_per_symbol(), # sampling rate
+                                          1.0,                  # midpoint of trans. band
+                                          0.5,                  # width of trans. band
+                                          gr.firdes.WIN_HANN)   # filter type
+        self.channel_filter = gr.fft_filter_ccc(sw_decim, chan_coeffs)
+        
+        # receiver
+        self.packet_receiver = \
+            digital.demod_pkts(self.demodulator,
+                               access_code=None,
+                               callback=self._rx_callback,
+                               threshold=-1)
+
+        # Carrier Sensing Blocks
+        alpha = 0.001
+        thresh = 30   # in dB, will have to adjust
+        self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha)
+
+        # Display some information about the setup
+        if self._verbose:
+            self._print_verbage()
+
+	# connect block input to channel filter
+	self.connect(self, self.channel_filter)
+
+        # connect the channel input filter to the carrier power detector
+        self.connect(self.channel_filter, self.probe)
+
+        # connect channel filter to the packet receiver
+        self.connect(self.channel_filter, self.packet_receiver)
+
+    def bitrate(self):
+        return self._bitrate
+
+    def samples_per_symbol(self):
+        return self.demodulator._samples_per_symbol
+
+    def differential(self):
+        return self.demodulator._differential
+
+    def carrier_sensed(self):
+        """
+        Return True if we think carrier is present.
+        """
+        #return self.probe.level() > X
+        return self.probe.unmuted()
+
+    def carrier_threshold(self):
+        """
+        Return current setting in dB.
+        """
+        return self.probe.threshold()
+
+    def set_carrier_threshold(self, threshold_in_db):
+        """
+        Set carrier threshold.
+
+        @param threshold_in_db: set detection threshold
+        @type threshold_in_db:  float (dB)
+        """
+        self.probe.set_threshold(threshold_in_db)
+    
+        
+    def add_options(normal, expert):
+        """
+        Adds receiver-specific options to the Options Parser
+        """
+        normal.add_option("-v", "--verbose", action="store_true", default=False)
+        expert.add_option("-S", "--samples-per-symbol", type="float", default=2,
+                          help="set samples/symbol [default=%default]")
+        expert.add_option("", "--log", action="store_true", default=False,
+                          help="Log all parts of flow graph to files (CAUTION: lots of data)")
+
+    # Make a static method to call before instantiation
+    add_options = staticmethod(add_options)
+
+
+    def _print_verbage(self):
+        """
+        Prints information about the receive path
+        """
+        print "\nReceive Path:"
+        print "modulation:      %s"    % (self._demod_class.__name__)
+        print "bitrate:         %sb/s" % (eng_notation.num_to_str(self._bitrate))
+        print "samples/symbol:  %.4f"    % (self.samples_per_symbol())
+        print "Differential:    %s"    % (self.differential())
diff --git a/gr-digital/examples/narrowband/rx_voice.py b/gr-digital/examples/narrowband/rx_voice.py
new file mode 100755
index 0000000000..b58704e16f
--- /dev/null
+++ b/gr-digital/examples/narrowband/rx_voice.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+#
+# Copyright 2005,2006,2009,2011 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 3, 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, blks2, audio, uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+from gnuradio import digital
+from gnuradio import vocoder
+
+import random
+import struct
+import sys
+
+# from current dir
+from receive_path import receive_path
+from uhd_interface import uhd_receiver
+
+#import os
+#print os.getpid()
+#raw_input('Attach and press enter')
+
+
+class audio_tx(gr.hier_block2):
+    def __init__(self, audio_output_dev):
+	gr.hier_block2.__init__(self, "audio_tx",
+				gr.io_signature(0, 0, 0), # Input signature
+				gr.io_signature(0, 0, 0)) # Output signature
+				
+        self.sample_rate = sample_rate = 8000
+        self.packet_src = gr.message_source(33)
+        voice_decoder = vocoder.gsm_fr_decode_ps()
+        s2f = gr.short_to_float ()
+        sink_scale = gr.multiply_const_ff(1.0/32767.)
+        audio_sink = audio.sink(sample_rate, audio_output_dev)
+        self.connect(self.packet_src, voice_decoder, s2f, sink_scale, audio_sink)
+        
+    def msgq(self):
+        return self.packet_src.msgq()
+
+
+class my_top_block(gr.top_block):
+    def __init__(self, demod_class, rx_callback, options):
+        gr.top_block.__init__(self)
+        self.rxpath = receive_path(demod_class, rx_callback, options)
+        self.audio_tx = audio_tx(options.audio_output)
+
+        if(options.rx_freq is not None):
+            self.source = uhd_receiver(options.address, options.bitrate,
+                                       options.samples_per_symbol,
+                                       options.rx_freq, options.rx_gain,
+                                       options.antenna, options.verbose)
+            options.samples_per_symbol = self.source._sps
+
+            audio_rate = self.audio_tx.sample_rate
+            usrp_rate = self.source.get_sample_rate()
+            rrate = audio_rate / usrp_rate
+            self.resampler = blks2.pfb_arb_resampler_ccf(rrate)
+            
+            self.connect(self.source, self.resampler, self.rxpath)
+
+        elif(options.from_file is not None):
+            self.thr = gr.throttle(gr.sizeof_gr_complex, options.bitrate)
+            self.source = gr.file_source(gr.sizeof_gr_complex, options.from_file)
+            self.connect(self.source, self.thr, self.rxpath)
+
+        else:
+            self.thr = gr.throttle(gr.sizeof_gr_complex, 1e6)
+            self.source = gr.null_source(gr.sizeof_gr_complex)
+            self.connect(self.source, self.thr, self.rxpath)
+
+	self.connect(self.audio_tx)        
+
+# /////////////////////////////////////////////////////////////////////////////
+#                                   main
+# /////////////////////////////////////////////////////////////////////////////
+
+global n_rcvd, n_right
+
+def main():
+    global n_rcvd, n_right
+
+    n_rcvd = 0
+    n_right = 0
+    
+    def rx_callback(ok, payload):
+        global n_rcvd, n_right
+        n_rcvd += 1
+        if ok:
+            n_right += 1
+
+        tb.audio_tx.msgq().insert_tail(gr.message_from_string(payload))
+        
+        print "ok = %r  n_rcvd = %4d  n_right = %4d" % (
+            ok, n_rcvd, n_right)
+
+    demods = digital.modulation_utils2.type_1_demods()
+
+    # Create Options Parser:
+    parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
+    expert_grp = parser.add_option_group("Expert")
+
+    parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), 
+                      default='gmsk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(demods.keys()),))
+    parser.add_option("-O", "--audio-output", type="string", default="",
+                      help="pcm output device name.  E.g., hw:0,0 or /dev/dsp")
+    parser.add_option("","--from-file", default=None,
+                      help="input file of samples to demod")
+    receive_path.add_options(parser, expert_grp)
+    uhd_receiver.add_options(parser)
+
+    for mod in demods.values():
+        mod.add_options(expert_grp)
+
+    parser.set_defaults(bitrate=50e3)  # override default bitrate default
+    (options, args) = parser.parse_args ()
+
+    if len(args) != 0:
+        parser.print_help(sys.stderr)
+        sys.exit(1)
+
+    if options.from_file is None:
+        if options.rx_freq is None:
+            sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
+            parser.print_help(sys.stderr)
+            sys.exit(1)
+
+
+    # build the graph
+    tb = my_top_block(demods[options.modulation], rx_callback, options)
+
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: Failed to enable realtime scheduling."
+
+    tb.run()
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
diff --git a/gr-digital/examples/narrowband/transmit_path.py b/gr-digital/examples/narrowband/transmit_path.py
new file mode 100644
index 0000000000..4d6162ed61
--- /dev/null
+++ b/gr-digital/examples/narrowband/transmit_path.py
@@ -0,0 +1,126 @@
+#
+# Copyright 2005-2007,2011 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 3, 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
+from gnuradio import eng_notation
+from gnuradio import digital
+
+import copy
+import sys
+
+# /////////////////////////////////////////////////////////////////////////////
+#                              transmit path
+# /////////////////////////////////////////////////////////////////////////////
+
+class transmit_path(gr.hier_block2):
+    def __init__(self, modulator_class, options):
+        '''
+        See below for what options should hold
+        '''
+	gr.hier_block2.__init__(self, "transmit_path",
+				gr.io_signature(0,0,0),
+				gr.io_signature(1,1,gr.sizeof_gr_complex))
+        
+        options = copy.copy(options)    # make a copy so we can destructively modify
+
+        self._verbose      = options.verbose
+        self._tx_amplitude = options.tx_amplitude   # digital amplitude sent to USRP
+        self._bitrate      = options.bitrate        # desired bit rate
+        self._modulator_class = modulator_class     # the modulator_class we are using
+
+        # Get mod_kwargs
+        mod_kwargs = self._modulator_class.extract_kwargs_from_options(options)
+        
+        # transmitter
+	self.modulator = self._modulator_class(**mod_kwargs)
+        
+        self.packet_transmitter = \
+            digital.mod_pkts(self.modulator,
+                             access_code=None,
+                             msgq_limit=4,
+                             pad_for_usrp=True)
+
+        self.amp = gr.multiply_const_cc(1)
+        self.set_tx_amplitude(self._tx_amplitude)
+
+        # Display some information about the setup
+        if self._verbose:
+            self._print_verbage()
+
+        # Connect components in the flowgraph
+        self.connect(self.packet_transmitter, self.amp, self)
+
+    def set_tx_amplitude(self, ampl):
+        """
+        Sets the transmit amplitude sent to the USRP in volts
+        @param: ampl 0 <= ampl < 1.
+        """
+        self._tx_amplitude = max(0.0, min(ampl, 1))
+        self.amp.set_k(self._tx_amplitude)
+        
+    def send_pkt(self, payload='', eof=False):
+        """
+        Calls the transmitter method to send a packet
+        """
+        return self.packet_transmitter.send_pkt(payload, eof)
+        
+    def bitrate(self):
+        return self._bitrate
+
+    def samples_per_symbol(self):
+        return self.modulator._samples_per_symbol
+
+    def differential(self):
+        return self.modulator._differential
+
+    def add_options(normal, expert):
+        """
+        Adds transmitter-specific options to the Options Parser
+        """
+        if not normal.has_option('--bitrate'):
+            normal.add_option("-r", "--bitrate", type="eng_float",
+                              default=100e3,
+                              help="specify bitrate [default=%default].")
+        normal.add_option("", "--tx-amplitude", type="eng_float",
+                          default=0.250, metavar="AMPL",
+                          help="set transmitter digital amplitude: 0 <= AMPL < 1 [default=%default]")
+        normal.add_option("-v", "--verbose", action="store_true",
+                          default=False)
+
+        expert.add_option("-S", "--samples-per-symbol", type="float",
+                          default=2,
+                          help="set samples/symbol [default=%default]")
+        expert.add_option("", "--log", action="store_true",
+                          default=False,
+                          help="Log all parts of flow graph to file (CAUTION: lots of data)")
+
+    # Make a static method to call before instantiation
+    add_options = staticmethod(add_options)
+
+    def _print_verbage(self):
+        """
+        Prints information about the transmit path
+        """
+        print "Tx amplitude     %s"    % (self._tx_amplitude)
+        print "modulation:      %s"    % (self._modulator_class.__name__)
+        print "bitrate:         %sb/s" % (eng_notation.num_to_str(self._bitrate))
+        print "samples/symbol:  %.4f"  % (self.samples_per_symbol())
+        print "Differential:    %s"    % (self.differential())
diff --git a/gr-digital/examples/narrowband/tunnel.py b/gr-digital/examples/narrowband/tunnel.py
new file mode 100755
index 0000000000..d25594df59
--- /dev/null
+++ b/gr-digital/examples/narrowband/tunnel.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+#
+# Copyright 2005,2006,2009,2011 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 3, 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.
+# 
+
+
+# ////////////////////////////////////////////////////////////////////
+#
+#    This code sets up up a virtual ethernet interface (typically
+#    gr0), and relays packets between the interface and the GNU Radio
+#    PHY+MAC
+#
+#    What this means in plain language, is that if you've got a couple
+#    of USRPs on different machines, and if you run this code on those
+#    machines, you can talk between them using normal TCP/IP
+#    networking.
+#
+# ////////////////////////////////////////////////////////////////////
+
+
+from gnuradio import gr, digital, uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+# from current dir
+from receive_path  import receive_path
+from transmit_path import transmit_path
+from uhd_interface import uhd_transmitter
+from uhd_interface import uhd_receiver
+
+import os, sys
+import random, time, struct
+
+#print os.getpid()
+#raw_input('Attach and press enter')
+
+# ////////////////////////////////////////////////////////////////////
+#
+#   Use the Universal TUN/TAP device driver to move packets to/from
+#   kernel
+#
+#   See /usr/src/linux/Documentation/networking/tuntap.txt
+#
+# ////////////////////////////////////////////////////////////////////
+
+# Linux specific...
+# TUNSETIFF ifr flags from <linux/tun_if.h>
+
+IFF_TUN		= 0x0001   # tunnel IP packets
+IFF_TAP		= 0x0002   # tunnel ethernet frames
+IFF_NO_PI	= 0x1000   # don't pass extra packet info
+IFF_ONE_QUEUE	= 0x2000   # beats me ;)
+
+def open_tun_interface(tun_device_filename):
+    from fcntl import ioctl
+    
+    mode = IFF_TAP | IFF_NO_PI
+    TUNSETIFF = 0x400454ca
+
+    tun = os.open(tun_device_filename, os.O_RDWR)
+    ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode))
+    ifname = ifs[:16].strip("\x00")
+    return (tun, ifname)
+    
+
+# ////////////////////////////////////////////////////////////////////
+#                     the flow graph
+# ////////////////////////////////////////////////////////////////////
+
+class my_top_block(gr.top_block):
+
+    def __init__(self, mod_class, demod_class,
+                 rx_callback, options):
+
+        gr.top_block.__init__(self)
+
+        self.source = uhd_receiver(options.address, options.bitrate,
+                                   options.samples_per_symbol,
+                                   options.rx_freq, options.rx_gain,
+                                   options.antenna, options.verbose)
+
+        self.sink = uhd_transmitter(options.address, options.bitrate,
+                                    options.samples_per_symbol,
+                                    options.tx_freq, options.tx_gain,
+                                    options.antenna, options.verbose)
+        
+        options.samples_per_symbol = self.source._sps
+
+        self.txpath = transmit_path(mod_class, options)
+        self.rxpath = receive_path(demod_class, rx_callback, options)
+        self.connect(self.txpath, self.sink)
+        self.connect(self.source, self.rxpath)
+
+    def send_pkt(self, payload='', eof=False):
+        return self.txpath.send_pkt(payload, eof)
+
+    def carrier_sensed(self):
+        """
+        Return True if the receive path thinks there's carrier
+        """
+        return self.rxpath.carrier_sensed()
+
+
+# ////////////////////////////////////////////////////////////////////
+#                           Carrier Sense MAC
+# ////////////////////////////////////////////////////////////////////
+
+class cs_mac(object):
+    """
+    Prototype carrier sense MAC
+
+    Reads packets from the TUN/TAP interface, and sends them to the
+    PHY. Receives packets from the PHY via phy_rx_callback, and sends
+    them into the TUN/TAP interface.
+
+    Of course, we're not restricted to getting packets via TUN/TAP,
+    this is just an example.
+    """
+
+    def __init__(self, tun_fd, verbose=False):
+        self.tun_fd = tun_fd       # file descriptor for TUN/TAP interface
+        self.verbose = verbose
+        self.tb = None             # top block (access to PHY)
+
+    def set_top_block(self, tb):
+        self.tb = tb
+
+    def phy_rx_callback(self, ok, payload):
+        """
+        Invoked by thread associated with PHY to pass received packet up.
+
+        @param ok: bool indicating whether payload CRC was OK
+        @param payload: contents of the packet (string)
+        """
+        if self.verbose:
+            print "Rx: ok = %r  len(payload) = %4d" % (ok, len(payload))
+        if ok:
+            os.write(self.tun_fd, payload)
+
+    def main_loop(self):
+        """
+        Main loop for MAC.
+        Only returns if we get an error reading from TUN.
+
+        FIXME: may want to check for EINTR and EAGAIN and reissue read
+        """
+        min_delay = 0.001               # seconds
+
+        while 1:
+            payload = os.read(self.tun_fd, 10*1024)
+            if not payload:
+                self.tb.send_pkt(eof=True)
+                break
+
+            if self.verbose:
+                print "Tx: len(payload) = %4d" % (len(payload),)
+
+            delay = min_delay
+            while self.tb.carrier_sensed():
+                sys.stderr.write('B')
+                time.sleep(delay)
+                if delay < 0.050:
+                    delay = delay * 2       # exponential back-off
+
+            self.tb.send_pkt(payload)
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#                                   main
+# /////////////////////////////////////////////////////////////////////////////
+
+def main():
+
+    mods = digital.modulation_utils2.type_1_mods()
+    demods = digital.modulation_utils2.type_1_demods()
+
+    parser = OptionParser (option_class=eng_option, conflict_handler="resolve")
+    expert_grp = parser.add_option_group("Expert")
+    parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
+                      default='gmsk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(mods.keys()),))
+
+    parser.add_option("-s", "--size", type="eng_float", default=1500,
+                      help="set packet size [default=%default]")
+    parser.add_option("-v","--verbose", action="store_true", default=False)
+    expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30,
+                          help="set carrier detect threshold (dB) [default=%default]")
+    expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun",
+                          help="path to tun device file [default=%default]")
+
+    transmit_path.add_options(parser, expert_grp)
+    receive_path.add_options(parser, expert_grp)
+    uhd_receiver.add_options(parser)
+    uhd_transmitter.add_options(parser)
+
+    for mod in mods.values():
+        mod.add_options(expert_grp)
+
+    for demod in demods.values():
+        demod.add_options(expert_grp)
+
+    (options, args) = parser.parse_args ()
+    if len(args) != 0:
+        parser.print_help(sys.stderr)
+        sys.exit(1)
+
+    # open the TUN/TAP interface
+    (tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename)
+
+    # Attempt to enable realtime scheduling
+    r = gr.enable_realtime_scheduling()
+    if r == gr.RT_OK:
+        realtime = True
+    else:
+        realtime = False
+        print "Note: failed to enable realtime scheduling"
+
+    # instantiate the MAC
+    mac = cs_mac(tun_fd, verbose=True)
+
+    # build the graph (PHY)
+    tb = my_top_block(mods[options.modulation],
+                      demods[options.modulation],
+                      mac.phy_rx_callback,
+                      options)
+
+    mac.set_top_block(tb)    # give the MAC a handle for the PHY
+
+    if tb.txpath.bitrate() != tb.rxpath.bitrate():
+        print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % (
+            eng_notation.num_to_str(tb.txpath.bitrate()),
+            eng_notation.num_to_str(tb.rxpath.bitrate()))
+             
+    print "modulation:     %s"   % (options.modulation,)
+    print "freq:           %s"      % (eng_notation.num_to_str(options.tx_freq))
+    print "bitrate:        %sb/sec" % (eng_notation.num_to_str(tb.txpath.bitrate()),)
+    print "samples/symbol: %3d" % (tb.txpath.samples_per_symbol(),)
+
+    tb.rxpath.set_carrier_threshold(options.carrier_threshold)
+    print "Carrier sense threshold:", options.carrier_threshold, "dB"
+    
+    print
+    print "Allocated virtual ethernet interface: %s" % (tun_ifname,)
+    print "You must now use ifconfig to set its IP address. E.g.,"
+    print
+    print "  $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,)
+    print
+    print "Be sure to use a different address in the same subnet for each machine."
+    print
+
+
+    tb.start()    # Start executing the flow graph (runs in separate threads)
+
+    mac.main_loop()    # don't expect this to return...
+
+    tb.stop()     # but if it does, tell flow graph to stop.
+    tb.wait()     # wait for it to finish
+                
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
diff --git a/gr-digital/examples/narrowband/tx_voice.py b/gr-digital/examples/narrowband/tx_voice.py
new file mode 100755
index 0000000000..eabb5e3c37
--- /dev/null
+++ b/gr-digital/examples/narrowband/tx_voice.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#
+# Copyright 2005-2007,2009,2011 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 3, 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, blks2, audio, uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+from gnuradio import digital
+from gnuradio import vocoder
+
+import random
+import time
+import struct
+import sys
+
+# from current dir
+from transmit_path import transmit_path
+from uhd_interface import uhd_transmitter
+
+#import os
+#print os.getpid()
+#raw_input('Attach and press enter')
+
+
+class audio_rx(gr.hier_block2):
+    def __init__(self, audio_input_dev):
+	gr.hier_block2.__init__(self, "audio_rx",
+				gr.io_signature(0, 0, 0), # Input signature
+				gr.io_signature(0, 0, 0)) # Output signature
+        self.sample_rate = sample_rate = 8000
+        src = audio.source(sample_rate, audio_input_dev)
+        src_scale = gr.multiply_const_ff(32767)
+        f2s = gr.float_to_short()
+        voice_coder = vocoder.gsm_fr_encode_sp()
+        self.packets_from_encoder = gr.msg_queue()
+        packet_sink = gr.message_sink(33, self.packets_from_encoder, False)
+        self.connect(src, src_scale, f2s, voice_coder, packet_sink)
+
+    def get_encoded_voice_packet(self):
+        return self.packets_from_encoder.delete_head()
+        
+
+class my_top_block(gr.top_block):
+
+    def __init__(self, modulator_class, options):
+        gr.top_block.__init__(self)
+        self.txpath = transmit_path(modulator_class, options)
+        self.audio_rx = audio_rx(options.audio_input)
+
+        if(options.tx_freq is not None):
+            self.sink = uhd_transmitter(options.address, options.bitrate,
+                                        options.samples_per_symbol,
+                                        options.tx_freq, options.tx_gain,
+                                        options.antenna, options.verbose)
+            options.samples_per_symbol = self.sink._sps
+            audio_rate = self.audio_rx.sample_rate
+            usrp_rate = self.sink.get_sample_rate()
+            rrate = usrp_rate / audio_rate
+            
+        elif(options.to_file is not None):
+            self.sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file)
+            rrate = 1
+        else:
+            self.sink = gr.null_sink(gr.sizeof_gr_complex)
+            rrate = 1
+
+        self.resampler = blks2.pfb_arb_resampler_ccf(rrate)
+            
+	self.connect(self.audio_rx)
+	self.connect(self.txpath, self.resampler, self.sink)
+            
+
+# /////////////////////////////////////////////////////////////////////////////
+#                                   main
+# /////////////////////////////////////////////////////////////////////////////
+
+def main():
+
+    def send_pkt(payload='', eof=False):
+        return tb.txpath.send_pkt(payload, eof)
+
+    def rx_callback(ok, payload):
+        print "ok = %r, payload = '%s'" % (ok, payload)
+
+    mods = digital.modulation_utils2.type_1_mods()
+
+    parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+    expert_grp = parser.add_option_group("Expert")
+
+    parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
+                      default='gmsk',
+                      help="Select modulation from: %s [default=%%default]"
+                            % (', '.join(mods.keys()),))
+    parser.add_option("-M", "--megabytes", type="eng_float", default=0,
+                      help="set megabytes to transmit [default=inf]")
+    parser.add_option("-I", "--audio-input", type="string", default="",
+                      help="pcm input device name.  E.g., hw:0,0 or /dev/dsp")
+    parser.add_option("","--to-file", default=None,
+                      help="Output file for modulated samples")
+
+    transmit_path.add_options(parser, expert_grp)
+    uhd_transmitter.add_options(parser)
+
+    for mod in mods.values():
+        mod.add_options(expert_grp)
+
+    parser.set_defaults(bitrate=50e3)  # override default bitrate default
+    (options, args) = parser.parse_args ()
+
+    if len(args) != 0:
+        parser.print_help()
+        sys.exit(1)
+
+    if options.to_file is None:
+        if options.tx_freq is None:
+            sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
+            parser.print_help(sys.stderr)
+            sys.exit(1)
+
+    # build the graph
+    tb = my_top_block(mods[options.modulation], options)
+
+    r = gr.enable_realtime_scheduling()
+    if r != gr.RT_OK:
+        print "Warning: failed to enable realtime scheduling"
+
+
+    tb.start()                       # start flow graph
+
+    # generate and send packets
+    nbytes = int(1e6 * options.megabytes)
+    n = 0
+    pktno = 0
+
+    while nbytes == 0 or n < nbytes:
+        packet = tb.audio_rx.get_encoded_voice_packet()
+        s = packet.to_string()
+        send_pkt(s)
+        n += len(s)
+        sys.stderr.write('.')
+        pktno += 1
+        
+    send_pkt(eof=True)
+    tb.wait()                       # wait for it to finish
+
+
+if __name__ == '__main__':
+    try:
+        main()
+    except KeyboardInterrupt:
+	pass
diff --git a/gr-digital/examples/narrowband/uhd_interface.py b/gr-digital/examples/narrowband/uhd_interface.py
new file mode 100644
index 0000000000..8420f3eece
--- /dev/null
+++ b/gr-digital/examples/narrowband/uhd_interface.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+#
+# Copyright 2010,2011 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 3, 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, uhd
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+import sys
+
+def add_freq_option(parser):
+    """
+    Hackery that has the -f / --freq option set both tx_freq and rx_freq
+    """
+    def freq_callback(option, opt_str, value, parser):
+        parser.values.rx_freq = value
+        parser.values.tx_freq = value
+
+    if not parser.has_option('--freq'):
+        parser.add_option('-f', '--freq', type="eng_float",
+                          action="callback", callback=freq_callback,
+                          help="set Tx and/or Rx frequency to FREQ [default=%default]",
+                          metavar="FREQ")
+
+class uhd_interface:
+    def __init__(self, istx, address, bitrate, sps, freq=None,
+                 gain=None, antenna=None):
+        
+        if(istx):
+            self.u = uhd.usrp_sink(device_addr=address,
+                                   io_type=uhd.io_type.COMPLEX_FLOAT32,
+                                   num_channels=1)
+        else:
+            self.u = uhd.usrp_source(device_addr=address,
+                                     io_type=uhd.io_type.COMPLEX_FLOAT32,
+                                     num_channels=1)
+
+        self._addr = address
+        self._ant  = antenna
+        self._gain = self.set_gain(gain)
+        self._freq = self.set_freq(freq)
+
+        self._rate, self._sps = self.set_sample_rate(bitrate, sps)
+
+        if(antenna):
+            self.u.set_antenna(antenna, 0)
+        
+    def set_sample_rate(self, bitrate, req_sps):
+        start_sps = req_sps
+        while(True):
+            asked_samp_rate = bitrate * req_sps
+            self.u.set_samp_rate(asked_samp_rate)
+            actual_samp_rate = self.u.get_samp_rate()
+
+            sps = actual_samp_rate/bitrate
+            if(sps < 2):
+                req_sps +=1
+            else:
+                actual_sps = sps
+                break
+        
+        if(sps != req_sps):
+            print "\nBit Rate:            %f" % (bitrate)
+            print "Requested sps:       %f" % (start_sps)
+            print "Given sample rate:   %f" % (actual_samp_rate)
+            print "Actual sps for rate: %f" % (actual_sps)
+
+        if(actual_samp_rate != asked_samp_rate):
+            print "\nRequested sample rate: %f" % (asked_samp_rate)
+            print "Actual sample rate: %f" % (actual_samp_rate)
+
+        return (actual_samp_rate, actual_sps)
+
+    def get_sample_rate(self):
+        return self.u.get_samp_rate()
+    
+    def set_gain(self, gain=None):
+        if gain is None:
+            # if no gain was specified, use the mid-point in dB
+            g = self.u.get_gain_range()
+            gain = float(g.start()+g.stop())/2
+            print "\nNo gain specified."
+            print "Setting gain to %f (from [%f, %f])" % \
+                (gain, g.start(), g.stop())
+        
+        self.u.set_gain(gain, 0)
+        return gain
+
+    def set_freq(self, freq=None):
+        if(freq is None):
+            sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
+            sys.exit(1)
+        
+        r = self.u.set_center_freq(freq, 0)
+        if r:
+            return freq
+        else:
+            frange = self.u.get_freq_range()
+            sys.stderr.write(("\nRequested frequency (%f) out or range [%f, %f]\n") % \
+                                 (freq, frange.start(), frange.stop()))
+            sys.exit(1)
+
+#-------------------------------------------------------------------#
+#   TRANSMITTER
+#-------------------------------------------------------------------#
+
+class uhd_transmitter(uhd_interface, gr.hier_block2):
+    def __init__(self, address, bitrate, sps, freq=None, gain=None,
+                 antenna=None, verbose=False):
+        gr.hier_block2.__init__(self, "uhd_transmitter",
+                                gr.io_signature(1,1,gr.sizeof_gr_complex),
+                                gr.io_signature(0,0,0))
+
+        # Set up the UHD interface as a transmitter
+        uhd_interface.__init__(self, True, address, bitrate, sps,
+                               freq, gain, antenna)
+
+        self.connect(self, self.u)
+
+        if(verbose):
+            self._print_verbage()
+            
+    def add_options(parser):
+        add_freq_option(parser)
+        parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2",
+                          help="Address of UHD device, [default=%default]")
+        parser.add_option("-A", "--antenna", type="string", default=None,
+                          help="select Rx Antenna where appropriate")
+        parser.add_option("", "--tx-freq", type="eng_float", default=None,
+                          help="set transmit frequency to FREQ [default=%default]",
+                          metavar="FREQ")
+        parser.add_option("", "--tx-gain", type="eng_float", default=None,
+                          help="set transmit gain in dB (default is midpoint)")
+        parser.add_option("-v", "--verbose", action="store_true", default=False)
+
+    # Make a static method to call before instantiation
+    add_options = staticmethod(add_options)
+
+    def _print_verbage(self):
+        """
+        Prints information about the UHD transmitter
+        """
+        print "\nUHD Transmitter:"
+        print "Address:     %s"    % (self._addr)
+        print "Freq:        %sHz"  % (eng_notation.num_to_str(self._freq))
+        print "Gain:        %f dB" % (self._gain)
+        print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
+        print "Antenna:     %s"    % (self._ant)
+
+
+
+#-------------------------------------------------------------------#
+#   RECEIVER
+#-------------------------------------------------------------------#
+
+
+class uhd_receiver(uhd_interface, gr.hier_block2):
+    def __init__(self, address, bitrate, sps, freq=None, gain=None,
+                 antenna=None, verbose=False):
+        gr.hier_block2.__init__(self, "uhd_receiver",
+                                gr.io_signature(0,0,0),
+                                gr.io_signature(1,1,gr.sizeof_gr_complex))
+      
+        # Set up the UHD interface as a receiver
+        uhd_interface.__init__(self, False, address, bitrate, sps,
+                               freq, gain, antenna)
+
+        self.connect(self.u, self)
+
+        if(verbose):
+            self._print_verbage()
+
+    def add_options(parser):
+        add_freq_option(parser)
+        parser.add_option("-a", "--address", type="string", default="addr=192.168.10.2",
+                          help="Address of UHD device, [default=%default]")
+        parser.add_option("-A", "--antenna", type="string", default=None,
+                          help="select Rx Antenna where appropriate")
+        parser.add_option("", "--rx-freq", type="eng_float", default=None,
+                          help="set receive frequency to FREQ [default=%default]",
+                          metavar="FREQ")
+        parser.add_option("", "--rx-gain", type="eng_float", default=None,
+                          help="set receive gain in dB (default is midpoint)")
+        if not parser.has_option("--verbose"):
+            parser.add_option("-v", "--verbose", action="store_true", default=False)
+
+    # Make a static method to call before instantiation
+    add_options = staticmethod(add_options)
+
+    def _print_verbage(self):
+        """
+        Prints information about the UHD transmitter
+        """
+        print "\nUHD Receiver:"
+        print "Address:     %s"    % (self._addr)
+        print "Freq:        %sHz"  % (eng_notation.num_to_str(self._freq))
+        print "Gain:        %f dB" % (self._gain)
+        print "Sample Rate: %ssps" % (eng_notation.num_to_str(self._rate))
+        print "Antenna:     %s"    % (self._ant)
+
-- 
cgit v1.2.3