Fixing benchmark_tx to use usrp_options interface. Also changes the default power...
[debian/gnuradio] / gnuradio-examples / python / digital / benchmark_tx.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2005,2006,2007,2009 Free Software Foundation, Inc.
4
5 # This file is part of GNU Radio
6
7 # GNU Radio is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3, or (at your option)
10 # any later version.
11
12 # GNU Radio is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16
17 # You should have received a copy of the GNU General Public License
18 # along with GNU Radio; see the file COPYING.  If not, write to
19 # the Free Software Foundation, Inc., 51 Franklin Street,
20 # Boston, MA 02110-1301, USA.
21
22
23 from gnuradio import gr, gru, modulation_utils
24 from gnuradio import usrp
25 from gnuradio import eng_notation
26 from gnuradio.eng_option import eng_option
27 from optparse import OptionParser
28
29 import random, time, struct, sys
30
31 # from current dir
32 from transmit_path import transmit_path
33 from pick_bitrate import pick_tx_bitrate
34 import usrp_options
35
36 #import os 
37 #print os.getpid()
38 #raw_input('Attach and press enter')
39
40 class my_top_block(gr.top_block):
41     def __init__(self, modulator, options):
42         gr.top_block.__init__(self)
43
44         self._tx_freq            = options.tx_freq         # tranmitter's center frequency
45         self._interp             = options.interp          # interpolating rate for the USRP (prelim)
46         self._bitrate            = options.bitrate
47         self._samples_per_symbol = options.samples_per_symbol
48         self._modulator_class    = modulator
49
50         if self._tx_freq is None:
51             sys.stderr.write("-f FREQ or --freq FREQ or --tx-freq FREQ must be specified\n")
52             raise SystemExit
53
54         # Set up USRP sink; also adjusts interp, and bitrate
55         self._setup_usrp_sink(options)
56
57         # copy the final answers back into options for use by modulator
58         options.samples_per_symbol = self._samples_per_symbol
59         options.bitrate = self._bitrate
60         options.interp = self._interp
61
62         # Set center frequency of USRP
63         ok = self.set_freq(self._tx_freq)
64         if not ok:
65             print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(self._tx_freq),)
66             raise ValueError
67
68         # Set the USRP for maximum transmit gain
69         # (Note that on the RFX cards this is a nop.)
70         self.set_gain(self.u.gain_range()[1])
71
72         self.txpath = transmit_path(modulator, options)
73
74         self.connect(self.txpath, self.u)
75
76     def _setup_usrp_sink(self, options):
77         """
78         Creates a USRP sink, determines the settings for best bitrate,
79         and attaches to the transmitter's subdevice.
80         """
81         self.u = usrp_options.create_usrp_sink(options)
82         dac_rate = self.u.dac_rate()
83
84         (self._bitrate, self._samples_per_symbol, self._interp) = \
85                         pick_tx_bitrate(self._bitrate, self._modulator_class.bits_per_symbol(), \
86                                         self._samples_per_symbol, self._interp, dac_rate, \
87                                         self.u.get_interp_rates())
88
89         self.u.set_interp(self._interp)
90         self.set_auto_tr(True)                 # enable Auto Transmit/Receive switching
91
92     def set_freq(self, target_freq):
93         """
94         Set the center frequency we're interested in.
95
96         @param target_freq: frequency in Hz
97         @rypte: bool
98
99         Tuning is a two step process.  First we ask the front-end to
100         tune as close to the desired frequency as it can.  Then we use
101         the result of that operation and our target_frequency to
102         determine the value for the digital up converter.
103         """
104         return self.u.set_center_freq(target_freq)
105
106     def set_gain(self, gain):
107         """
108         Sets the analog gain in the USRP
109         """
110         self.gain = gain
111         self.u.set_gain(gain)
112
113     def set_auto_tr(self, enable):
114         """
115         Turns on auto transmit/receive of USRP daughterboard (if exits; else ignored)
116         """
117         return self.u.set_auto_tr(enable)
118         
119     def interp(self):
120         return self._interp
121
122     def add_options(normal, expert):
123         """
124         Adds usrp-specific options to the Options Parser
125         """
126         add_freq_option(normal)
127         normal.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
128                           help="select USRP Tx side A or B")
129         normal.add_option("-v", "--verbose", action="store_true", default=False)
130
131         expert.add_option("", "--tx-freq", type="eng_float", default=None,
132                           help="set transmit frequency to FREQ [default=%default]", metavar="FREQ")
133         expert.add_option("-i", "--interp", type="intx", default=256,
134                           help="set fpga interpolation rate to INTERP [default=%default]")
135     # Make a static method to call before instantiation
136     add_options = staticmethod(add_options)
137
138     def _print_verbage(self):
139         """
140         Prints information about the transmit path
141         """
142         print "Using TX d'board %s"    % (self.subdev.side_and_name(),)
143         print "modulation:      %s"    % (self._modulator_class.__name__)
144         print "interp:          %3d"   % (self._interp)
145         print "Tx Frequency:    %s"    % (eng_notation.num_to_str(self._tx_freq))
146         
147
148 def add_freq_option(parser):
149     """
150     Hackery that has the -f / --freq option set both tx_freq and rx_freq
151     """
152     def freq_callback(option, opt_str, value, parser):
153         parser.values.rx_freq = value
154         parser.values.tx_freq = value
155
156     if not parser.has_option('--freq'):
157         parser.add_option('-f', '--freq', type="eng_float",
158                           action="callback", callback=freq_callback,
159                           help="set Tx and/or Rx frequency to FREQ [default=%default]",
160                           metavar="FREQ")
161
162
163 # /////////////////////////////////////////////////////////////////////////////
164 #                                   main
165 # /////////////////////////////////////////////////////////////////////////////
166
167 def main():
168
169     def send_pkt(payload='', eof=False):
170         return tb.txpath.send_pkt(payload, eof)
171
172     def rx_callback(ok, payload):
173         print "ok = %r, payload = '%s'" % (ok, payload)
174
175     mods = modulation_utils.type_1_mods()
176
177     parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
178     expert_grp = parser.add_option_group("Expert")
179
180     parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(),
181                       default='gmsk',
182                       help="Select modulation from: %s [default=%%default]"
183                             % (', '.join(mods.keys()),))
184
185     parser.add_option("-s", "--size", type="eng_float", default=1500,
186                       help="set packet size [default=%default]")
187     parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
188                       help="set megabytes to transmit [default=%default]")
189     parser.add_option("","--discontinuous", action="store_true", default=False,
190                       help="enable discontinous transmission (bursts of 5 packets)")
191     parser.add_option("","--from-file", default=None,
192                       help="use file for packet contents")
193
194     my_top_block.add_options(parser, expert_grp)
195     transmit_path.add_options(parser, expert_grp)
196     usrp_options.add_tx_options(parser)
197
198     for mod in mods.values():
199         mod.add_options(expert_grp)
200
201     (options, args) = parser.parse_args ()
202
203     if len(args) != 0:
204         parser.print_help()
205         sys.exit(1)
206
207     if options.tx_freq is None:
208         sys.stderr.write("You must specify -f FREQ or --freq FREQ\n")
209         parser.print_help(sys.stderr)
210         sys.exit(1)
211
212     if options.from_file is not None:
213         source_file = open(options.from_file, 'r')
214
215     # build the graph
216     tb = my_top_block(mods[options.modulation], options)
217
218     r = gr.enable_realtime_scheduling()
219     if r != gr.RT_OK:
220         print "Warning: failed to enable realtime scheduling"
221
222     tb.start()                       # start flow graph
223         
224     # generate and send packets
225     nbytes = int(1e6 * options.megabytes)
226     n = 0
227     pktno = 0
228     pkt_size = int(options.size)
229
230     while n < nbytes:
231         if options.from_file is None:
232             data = (pkt_size - 2) * chr(pktno & 0xff) 
233         else:
234             data = source_file.read(pkt_size - 2)
235             if data == '':
236                 break;
237
238         payload = struct.pack('!H', pktno & 0xffff) + data
239         send_pkt(payload)
240         n += len(payload)
241         sys.stderr.write('.')
242         if options.discontinuous and pktno % 5 == 4:
243             time.sleep(1)
244         pktno += 1
245         
246     send_pkt(eof=True)
247
248     tb.wait()                       # wait for it to finish
249
250 if __name__ == '__main__':
251     try:
252         main()
253     except KeyboardInterrupt:
254         pass