diff options
-rw-r--r-- | gr-digital/examples/README | 84 | ||||
-rwxr-xr-x | gr-digital/examples/tunnel.py | 283 | ||||
-rw-r--r-- | gr-digital/python/gmsk.py | 10 |
3 files changed, 372 insertions, 5 deletions
diff --git a/gr-digital/examples/README b/gr-digital/examples/README new file mode 100644 index 000000000..904a64895 --- /dev/null +++ b/gr-digital/examples/README @@ -0,0 +1,84 @@ +Quick overview of what's here: + +* benchmark_tx.py: generates packets of the size you +specify and sends them across the air using the USRP. Known to work +well using the USRP with the RFX transceiver daughterboards. +You can specify the bitrate to use with the -r <bitrate> command line +parameter. The default is 500k. Some machines will do 1M or more. +You can select the modulation to use with the -m <modulation> command +line argument. The legal values for <modulation> are gmsk, dbpsk and dqpsk. + +* benchmark_rx.py: the receiver half of benchmark_tx.py. +Command line arguments are pretty much the same as rx. Works well +with a USRP and RFX transceiver daughterboards. Will also work +with TVRX daugherboard, but you'll need to fiddle with the gain. See +below. Prints a summary of each packet received and keeps a running +total of packets received, and how many of them were error free. +There are two levels of error reporting going on. If the access code +(PN code) and header of a packet were properly detected, then you'll +get an output line. If the CRC32 of the payload was correct you get +"ok = True", else "ok = False". The "pktno" is extracted from the +received packet. If there are skipped numbers, you're missing some +packets. Be sure you've got a suitable antenna connected to the TX/RX +port on each board. For the RFX-400, "70 cm" / 420 MHz antennas for ham +handi-talkies work great. These are available at ham radio supplies, +etc. The boards need to be at least 3m apart. You can also try +experimenting with the rx gain (-g <gain> command line option). + +Generally speaking, I start the rx first on one machine, and then fire +up the tx on the other machine. The tx also supports a discontinous +transmission mode where it sends bursts of 5 packets and then waits 1 +second. This is useful for ensuring that all the receiver control +loops lock up fast enough. + +* tunnel.py: This program provides a framework for building your own +MACs. It creates a "TAP" interface in the kernel, typically gr0, +and sends and receives ethernet frames through it. See +/usr/src/linux/Documentation/networking/tuntap.txt and/or Google for +"universal tun tap". The Linux 2.6 kernel includes the tun module, you +don't have to build it. You may have to "modprobe tun" if it's not +loaded by default. If /dev/net/tun doesn't exist, try "modprobe tun". + +To run this program you'll need to be root or running with the +appropriate capability to open the tun interface. You'll need to fire +up two copies on different machines. Once each is running you'll need +to ifconfig the gr0 interface to set the IP address. + +This will allow two machines to talk, but anything beyond the two +machines depends on your networking setup. Left as an exercise... + +On machine A: + + $ su + # ./tunnel.py --freq 423.0M --bitrate 500k + # # in another window on A, also as root... + # ifconfig gr0 192.168.200.1 + + +On machine B: + + $ su + # ./tunnel.py --freq 423.0M --bitrate 500k + # # in another window on B, also as root... + # ifconfig gr0 192.168.200.2 + +Now, on machine A you shold be able to ping machine B: + + $ ping 192.168.200.2 + +and you should see some output for each packet in the +tunnel.py window if you used the -v option. + +Likewise, on machine B: + + $ ping 192.168.200.1 + +This now uses a carrier sense MAC, so you should be able to ssh +between the machines, web browse, etc. + +* run_length.py: This program takes a single argument '-f FILE' and +outputs the number of runs of similar bits within the file. It is +useful as a diagnostic tool when experimenting with line coding or +whitening algorithms. + + diff --git a/gr-digital/examples/tunnel.py b/gr-digital/examples/tunnel.py new file mode 100755 index 000000000..d25594df5 --- /dev/null +++ b/gr-digital/examples/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/python/gmsk.py b/gr-digital/python/gmsk.py index ba122821e..4db62e40d 100644 --- a/gr-digital/python/gmsk.py +++ b/gr-digital/python/gmsk.py @@ -78,8 +78,8 @@ class gmsk_mod(gr.hier_block2): self._samples_per_symbol = samples_per_symbol self._bt = bt - if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: - raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % \ + if samples_per_symbol < 2: + raise TypeError, ("samples_per_symbol must >= 2, is %r" % \ (samples_per_symbol,)) ntaps = 4 * samples_per_symbol # up to 3 bits in filter at once @@ -94,12 +94,12 @@ class gmsk_mod(gr.hier_block2): 1, # gain samples_per_symbol, # symbol_rate bt, # bandwidth * symbol time - ntaps # number of taps + int(ntaps) # number of taps ) - self.sqwave = (1,) * samples_per_symbol # rectangular window + self.sqwave = (1,) * int(samples_per_symbol) # rectangular window self.taps = numpy.convolve(numpy.array(self.gaussian_taps),numpy.array(self.sqwave)) - self.gaussian_filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) + self.gaussian_filter = gr.pfb_arb_resampler_fff(samples_per_symbol, self.taps) # FM modulation self.fmmod = gr.frequency_modulator_fc(sensitivity) |