bda63805310db391026332e712abc54578cfbf4b
[debian/gnuradio] / gnuradio-examples / python / ofdm / benchmark_ofdm_tx.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2005, 2006 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 2, 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, math
30
31 # from current dir
32 from transmit_path import transmit_path
33 from pick_bitrate import pick_tx_bitrate
34 import ofdm, fusb_options
35
36 class usrp_graph(gr.flow_graph):
37     def __init__(self, options):
38         gr.flow_graph.__init__(self)
39
40         self._tx_freq            = options.tx_freq         # tranmitter's center frequency
41         self._tx_subdev_spec     = options.tx_subdev_spec  # daughterboard to use
42         self._bitrate            = options.bitrate         # desired bit rate
43         self._interp             = options.interp          # interpolating rate for the USRP (prelim)
44         self._fusb_block_size    = options.fusb_block_size # usb info for USRP
45         self._fusb_nblocks       = options.fusb_nblocks    # usb info for USRP
46
47         if self._tx_freq is None:
48             sys.stderr.write("-f FREQ or --freq FREQ or --tx-freq FREQ must be specified\n")
49             raise SystemExit
50
51         # Set up USRP sink; also adjusts interp, and bitrate
52         self._setup_usrp_sink()
53
54         # copy the final answers back into options for use by modulator
55         #options.bitrate = self._bitrate
56
57         self.txpath = transmit_path(self, options)
58
59         self.connect(self.txpath, self.u)
60
61     def _setup_usrp_sink(self):
62         """
63         Creates a USRP sink, determines the settings for best bitrate,
64         and attaches to the transmitter's subdevice.
65         """
66         self.u = usrp.sink_c(fusb_block_size=self._fusb_block_size,
67                              fusb_nblocks=self._fusb_nblocks)
68
69         self.u.set_interp_rate(self._interp)
70
71         # determine the daughterboard subdevice we're using
72         if self._tx_subdev_spec is None:
73             self._tx_subdev_spec = usrp.pick_tx_subdevice(self.u)
74         self.u.set_mux(usrp.determine_tx_mux_value(self.u, self._tx_subdev_spec))
75         self.subdev = usrp.selected_subdev(self.u, self._tx_subdev_spec)
76
77         # Set center frequency of USRP
78         ok = self.set_freq(self._tx_freq)
79         if not ok:
80             print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(self._tx_freq),)
81             raise ValueError
82
83         # Set the USRP for maximum transmit gain
84         # (Note that on the RFX cards this is a nop.)
85         self.set_gain(self.subdev.gain_range()[0])
86
87         # enable Auto Transmit/Receive switching
88         self.set_auto_tr(True)
89
90     def set_freq(self, target_freq):
91         """
92         Set the center frequency we're interested in.
93
94         @param target_freq: frequency in Hz
95         @rypte: bool
96
97         Tuning is a two step process.  First we ask the front-end to
98         tune as close to the desired frequency as it can.  Then we use
99         the result of that operation and our target_frequency to
100         determine the value for the digital up converter.
101         """
102         r = self.u.tune(self.subdev._which, self.subdev, target_freq)
103         if r:
104             return True
105
106         return False
107         
108     def set_gain(self, gain):
109         """
110         Sets the analog gain in the USRP
111         """
112         self.gain = gain
113         self.subdev.set_gain(gain)
114
115     def set_auto_tr(self, enable):
116         """
117         Turns on auto transmit/receive of USRP daughterboard (if exits; else ignored)
118         """
119         return self.subdev.set_auto_tr(enable)
120         
121     def interp(self):
122         return self._interp
123
124     def add_options(normal, expert):
125         """
126         Adds usrp-specific options to the Options Parser
127         """
128         add_freq_option(normal)
129         if not normal.has_option('--bitrate'):
130             normal.add_option("-r", "--bitrate", type="eng_float", default=None,
131                               help="specify bitrate.  samples-per-symbol and interp/decim will be derived.")
132         normal.add_option("-T", "--tx-subdev-spec", type="subdev", default=None,
133                           help="select USRP Tx side A or B")
134         normal.add_option("-v", "--verbose", action="store_true", default=False)
135
136         expert.add_option("-S", "--samples-per-symbol", type="int", default=None,
137                           help="set samples/symbol [default=%default]")
138         expert.add_option("", "--tx-freq", type="eng_float", default=None,
139                           help="set transmit frequency to FREQ [default=%default]", metavar="FREQ")
140         expert.add_option("-i", "--interp", type="intx", default=64,
141                           help="set fpga interpolation rate to INTERP [default=%default]")
142     # Make a static method to call before instantiation
143     add_options = staticmethod(add_options)
144
145     def _print_verbage(self):
146         """
147         Prints information about the transmit path
148         """
149         print "Using TX d'board %s"    % (self.subdev.side_and_name(),)
150         print "modulation:      %s"    % (self._modulator_class.__name__)
151         print "interp:          %3d"   % (self._interp)
152         print "Tx Frequency:    %s"    % (eng_notation.num_to_str(self._tx_freq))
153         
154
155 def add_freq_option(parser):
156     """
157     Hackery that has the -f / --freq option set both tx_freq and rx_freq
158     """
159     def freq_callback(option, opt_str, value, parser):
160         parser.values.rx_freq = value
161         parser.values.tx_freq = value
162
163     if not parser.has_option('--freq'):
164         parser.add_option('-f', '--freq', type="eng_float",
165                           action="callback", callback=freq_callback,
166                           help="set Tx and/or Rx frequency to FREQ [default=%default]",
167                           metavar="FREQ")
168
169 # /////////////////////////////////////////////////////////////////////////////
170 #                                   main
171 # /////////////////////////////////////////////////////////////////////////////
172
173 def main():
174
175     def send_pkt(payload='', eof=False):
176         return fg.txpath.send_pkt(payload, eof)
177
178     parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
179     expert_grp = parser.add_option_group("Expert")
180     parser.add_option("-s", "--size", type="eng_float", default=1450,
181                       help="set packet size [default=%default]")
182     parser.add_option("-M", "--megabytes", type="eng_float", default=1.0,
183                       help="set megabytes to transmit [default=%default]")
184     parser.add_option("-r", "--sample-rate", type="eng_float", default=1e5,
185                       help="set sample rate to RATE (%default)") 
186
187     usrp_graph.add_options(parser, expert_grp)
188     transmit_path.add_options(parser, expert_grp)
189     ofdm.ofdm_mod.add_options(parser, expert_grp)
190     fusb_options.add_options(expert_grp)
191
192     (options, args) = parser.parse_args ()
193
194     if(options.mtu < options.size):
195         sys.stderr.write("MTU (%.0f) must be larger than the packet size (%.0f)\n"
196                          % (options.mtu, options.size))
197         sys.exit(1)
198
199     # build the graph
200     fg = usrp_graph(options)
201
202     r = gr.enable_realtime_scheduling()
203     if r != gr.RT_OK:
204         print "Warning: failed to enable realtime scheduling"
205
206     fg.start()                       # start flow graph
207
208     # generate and send packets
209     nbytes = int(1e6 * options.megabytes)
210     n = 0
211     pktno = 0
212     pkt_size = int(options.size)
213
214     while n < nbytes:
215         send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff))
216         n += pkt_size
217         sys.stderr.write('.')
218         #if options.discontinuous and pktno % 5 == 4:
219         #    time.sleep(1)
220         pktno += 1
221         
222     send_pkt(eof=True)
223     fg.wait()                       # wait for it to finish
224
225 if __name__ == '__main__':
226     try:
227         main()
228     except KeyboardInterrupt:
229         pass