diff options
Diffstat (limited to 'gr-digital/examples/narrowband')
-rwxr-xr-x | gr-digital/examples/narrowband/benchmark_add_channel.py | 102 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/benchmark_rx.py | 136 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/benchmark_tx.py | 149 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/digital_bert_rx.py | 209 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/digital_bert_tx.py | 135 | ||||
-rw-r--r-- | gr-digital/examples/narrowband/receive_path.py | 145 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/rx_voice.py | 164 | ||||
-rw-r--r-- | gr-digital/examples/narrowband/transmit_path.py | 126 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/tunnel.py | 291 | ||||
-rwxr-xr-x | gr-digital/examples/narrowband/tx_voice.py | 171 | ||||
-rw-r--r-- | gr-digital/examples/narrowband/uhd_interface.py | 219 |
11 files changed, 1847 insertions, 0 deletions
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 000000000..841833a08 --- /dev/null +++ b/gr-digital/examples/narrowband/benchmark_add_channel.py @@ -0,0 +1,102 @@ +#!/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 + power_in_signal = abs(options.tx_amplitude)**2 + noise_power = power_in_signal/SNR + noise_voltage = math.sqrt(noise_power) + + 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]") + parser.add_option("", "--tx-amplitude", type="eng_float", + default=1.0, + help="tell the simulator the signal amplitude [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 000000000..65aac3638 --- /dev/null +++ b/gr-digital/examples/narrowband/benchmark_rx.py @@ -0,0 +1,136 @@ +#!/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): + sys.stderr.write(("Reading samples from '%s'.\n\n" % (options.from_file))) + self.source = gr.file_source(gr.sizeof_gr_complex, options.from_file) + else: + sys.stderr.write("No source defined, pulling samples from null source.\n\n") + 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_utils.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 000000000..1fd881981 --- /dev/null +++ b/gr-digital/examples/narrowband/benchmark_tx.py @@ -0,0 +1,149 @@ +#!/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): + sys.stderr.write(("Saving samples to '%s'.\n\n" % (options.to_file))) + self.sink = gr.file_sink(gr.sizeof_gr_complex, options.to_file) + else: + sys.stderr.write("No sink defined, dumping samples to null sink.\n\n") + 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_utils.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 000000000..9878f55e1 --- /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_utils.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_utils.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 000000000..96cb338fe --- /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_utils.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 000000000..1c5e58963 --- /dev/null +++ b/gr-digital/examples/narrowband/receive_path.py @@ -0,0 +1,145 @@ +#!/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 + """ + if not normal.has_option("--bitrate"): + normal.add_option("-r", "--bitrate", type="eng_float", default=100e3, + help="specify bitrate [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 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 000000000..42d7b893b --- /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_utils.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 000000000..4d6162ed6 --- /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 000000000..7f40bb1c3 --- /dev/null +++ b/gr-digital/examples/narrowband/tunnel.py @@ -0,0 +1,291 @@ +#!/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 +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() + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + """ + + self.sink.set_freq(target_freq) + self.source.set_freq(target_freq) + + +# //////////////////////////////////////////////////////////////////// +# 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_utils.type_1_mods() + demods = digital.modulation_utils.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 000000000..3d767a077 --- /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_utils.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 000000000..8420f3eec --- /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) + |