3 # Copyright 2004,2005,2006,2007 Free Software Foundation, Inc.
5 # This file is part of GNU Radio
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)
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.
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.
23 # print "Loading revised usrp_oscope with additional options for scopesink..."
25 from gnuradio import gr, gru
26 from gnuradio import usrp
27 from gnuradio import eng_notation
28 from gnuradio.eng_option import eng_option
29 from gnuradio.wxgui import stdgui2, scopesink2, form, slider
30 from optparse import OptionParser
33 from usrpm import usrp_dbid
36 def pick_subdevice(u):
38 The user didn't specify a subdevice on the command line.
39 If there's a daughterboard on A, select A.
40 If there's a daughterboard on B, select B.
43 if u.db(0, 0).dbid() >= 0: # dbid is < 0 if there's no d'board or a problem
45 if u.db(0, 0).dbid() >= 0:
50 class app_top_block(stdgui2.std_top_block):
51 def __init__(self, frame, panel, vbox, argv):
52 stdgui2.std_top_block.__init__(self, frame, panel, vbox, argv)
57 parser = OptionParser(option_class=eng_option)
58 parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None,
59 help="select USRP Rx side A or B (default=first one with a daughterboard)")
60 parser.add_option("-d", "--decim", type="int", default=16,
61 help="set fgpa decimation rate to DECIM [default=%default]")
62 parser.add_option("-f", "--freq", type="eng_float", default=None,
63 help="set frequency to FREQ", metavar="FREQ")
64 parser.add_option("-g", "--gain", type="eng_float", default=None,
65 help="set gain in dB (default is midpoint)")
66 parser.add_option("-8", "--width-8", action="store_true", default=False,
67 help="Enable 8-bit samples across USB")
68 parser.add_option( "--no-hb", action="store_true", default=False,
69 help="don't use halfband filter in usrp")
70 parser.add_option("-C", "--basic-complex", action="store_true", default=False,
71 help="Use both inputs of a basicRX or LFRX as a single Complex input channel")
72 parser.add_option("-D", "--basic-dualchan", action="store_true", default=False,
73 help="Use both inputs of a basicRX or LFRX as seperate Real input channels")
74 parser.add_option("-n", "--frame-decim", type="int", default=1,
75 help="set oscope frame decimation factor to n [default=1]")
76 parser.add_option("-v", "--v-scale", type="eng_float", default=1000,
77 help="set oscope initial V/div to SCALE [default=%default]")
78 parser.add_option("-t", "--t-scale", type="eng_float", default=49e-6,
79 help="set oscope initial s/div to SCALE [default=50us]")
80 (options, args) = parser.parse_args()
85 self.show_debug_info = True
88 if options.basic_dualchan:
92 if options.no_hb or (options.decim<8):
93 #Min decimation of this firmware is 4.
94 #contains 4 Rx paths without halfbands and 0 tx paths.
95 self.fpga_filename="std_4rx_0tx.rbf"
96 self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim, fpga_filename=self.fpga_filename)
98 #Min decimation of standard firmware is 8.
99 #standard fpga firmware "std_2rxhb_2tx.rbf"
100 #contains 2 Rx paths with halfband filters and 2 tx paths (the default)
101 self.u = usrp.source_c(nchan=self.num_inputs,decim_rate=options.decim)
103 if options.rx_subdev_spec is None:
104 options.rx_subdev_spec = pick_subdevice(self.u)
109 format = self.u.make_format(width, shift)
110 #print "format =", hex(format)
111 r = self.u.set_format(format)
112 #print "set_format =", r
114 # determine the daughterboard subdevice we're using
115 self.subdev = usrp.selected_subdev(self.u, options.rx_subdev_spec)
116 if (options.basic_complex or options.basic_dualchan ):
117 if ((self.subdev.dbid()==usrp_dbid.BASIC_RX) or (self.subdev.dbid()==usrp_dbid.LF_RX)):
118 side = options.rx_subdev_spec[0] # side A = 0, side B = 1
119 if options.basic_complex:
120 #force Basic_RX and LF_RX in complex mode (use both I and Q channel)
121 print "Receiver daughterboard forced in complex mode. Both inputs will combined to form a single complex channel."
124 self.u.set_mux(0x00000010) #enable adc 0 and 1 to form a single complex input on side A
126 self.u.set_mux(0x00000032) #enable adc 3 and 2 to form a single complex input on side B
127 elif options.basic_dualchan:
128 #force Basic_RX and LF_RX in dualchan mode (use input A for channel 0 and input B for channel 1)
129 print "Receiver daughterboard forced in dualchannel mode. Each input will be used to form a seperate channel."
132 self.u.set_mux(gru.hexint(0xf0f0f1f0)) #enable adc 0, side A to form a real input on channel 0 and adc1,side A to form a real input on channel 1
134 self.u.set_mux(0xf0f0f3f2) #enable adc 2, side B to form a real input on channel 0 and adc3,side B to form a real input on channel 1
136 sys.stderr.write('options basic_dualchan or basic_complex is only supported for Basic Rx or LFRX at the moment\n')
140 self.u.set_mux(usrp.determine_rx_mux_value(self.u, options.rx_subdev_spec))
142 input_rate = self.u.adc_freq() / self.u.decim_rate()
144 self.scope = scopesink2.scope_sink_c(panel, sample_rate=input_rate,
145 frame_decim=options.frame_decim,
146 v_scale=options.v_scale,
147 t_scale=options.t_scale,
148 num_inputs=self.num_inputs)
150 # deinterleave two channels from FPGA
151 self.di = gr.deinterleave(gr.sizeof_gr_complex)
152 self.connect(self.u,self.di)
153 self.connect((self.di,0),(self.scope,0))
154 self.connect((self.di,1),(self.scope,1))
156 self.connect(self.u, self.scope)
158 self._build_gui(vbox)
162 if options.gain is None:
163 # if no gain was specified, use the mid-point in dB
164 g = self.subdev.gain_range()
165 options.gain = float(g[0]+g[1])/2
167 if options.freq is None:
168 if ((self.subdev.dbid()==usrp_dbid.BASIC_RX) or (self.subdev.dbid()==usrp_dbid.LF_RX)):
169 #for Basic RX and LFRX if no freq is specified you probably want 0.0 Hz and not 45 GHz
172 # if no freq was specified, use the mid-point
173 r = self.subdev.freq_range()
174 options.freq = float(r[0]+r[1])/2
176 self.set_gain(options.gain)
178 if self.show_debug_info:
179 self.myform['decim'].set_value(self.u.decim_rate())
180 self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate())
181 self.myform['dbname'].set_value(self.subdev.name())
182 self.myform['baseband'].set_value(0)
183 self.myform['ddc'].set_value(0)
184 if self.num_inputs==2:
185 self.myform['baseband2'].set_value(0)
186 self.myform['ddc2'].set_value(0)
188 if not(self.set_freq(options.freq)):
189 self._set_status_msg("Failed to set initial frequency")
190 if self.num_inputs==2:
191 if not(self.set_freq2(options.freq)):
192 self._set_status_msg("Failed to set initial frequency for channel 2")
195 def _set_status_msg(self, msg):
196 self.frame.GetStatusBar().SetStatusText(msg, 0)
198 def _build_gui(self, vbox):
200 def _form_set_freq(kv):
201 return self.set_freq(kv['freq'])
203 def _form_set_freq2(kv):
204 return self.set_freq2(kv['freq2'])
205 vbox.Add(self.scope.win, 10, wx.EXPAND)
207 # add control area at the bottom
208 self.myform = myform = form.form()
209 hbox = wx.BoxSizer(wx.HORIZONTAL)
210 hbox.Add((5,0), 0, 0)
211 myform['freq'] = form.float_field(
212 parent=self.panel, sizer=hbox, label="Center freq", weight=1,
213 callback=myform.check_input_and_call(_form_set_freq, self._set_status_msg))
214 if self.num_inputs==2:
215 myform['freq2'] = form.float_field(
216 parent=self.panel, sizer=hbox, label="Center freq2", weight=1,
217 callback=myform.check_input_and_call(_form_set_freq2, self._set_status_msg))
218 hbox.Add((5,0), 0, 0)
219 g = self.subdev.gain_range()
220 myform['gain'] = form.slider_field(parent=self.panel, sizer=hbox, label="Gain",
222 min=int(g[0]), max=int(g[1]),
223 callback=self.set_gain)
225 hbox.Add((5,0), 0, 0)
226 vbox.Add(hbox, 0, wx.EXPAND)
228 self._build_subpanel(vbox)
230 def _build_subpanel(self, vbox_arg):
231 # build a secondary information panel (sometimes hidden)
233 # FIXME figure out how to have this be a subpanel that is always
234 # created, but has its visibility controlled by foo.Show(True/False)
236 def _form_set_decim(kv):
237 return self.set_decim(kv['decim'])
239 if not(self.show_debug_info):
246 #panel = wx.Panel(self.panel, -1)
247 #vbox = wx.BoxSizer(wx.VERTICAL)
249 hbox = wx.BoxSizer(wx.HORIZONTAL)
252 myform['decim'] = form.int_field(
253 parent=panel, sizer=hbox, label="Decim",
254 callback=myform.check_input_and_call(_form_set_decim, self._set_status_msg))
257 myform['fs@usb'] = form.static_float_field(
258 parent=panel, sizer=hbox, label="Fs@USB")
261 myform['dbname'] = form.static_text_field(
262 parent=panel, sizer=hbox)
265 myform['baseband'] = form.static_float_field(
266 parent=panel, sizer=hbox, label="Analog BB")
269 myform['ddc'] = form.static_float_field(
270 parent=panel, sizer=hbox, label="DDC")
271 if self.num_inputs==2:
273 myform['baseband2'] = form.static_float_field(
274 parent=panel, sizer=hbox, label="BB2")
276 myform['ddc2'] = form.static_float_field(
277 parent=panel, sizer=hbox, label="DDC2")
280 vbox.Add(hbox, 0, wx.EXPAND)
283 def set_freq(self, target_freq):
285 Set the center frequency we're interested in.
287 @param target_freq: frequency in Hz
290 Tuning is a two step process. First we ask the front-end to
291 tune as close to the desired frequency as it can. Then we use
292 the result of that operation and our target_frequency to
293 determine the value for the digital down converter.
295 r = usrp.tune(self.u, 0, self.subdev, target_freq)
298 self.myform['freq'].set_value(target_freq) # update displayed value
299 if self.show_debug_info:
300 self.myform['baseband'].set_value(r.baseband_freq)
301 self.myform['ddc'].set_value(r.dxc_freq)
306 def set_freq2(self, target_freq):
308 Set the center frequency of we're interested in for the second channel.
310 @param target_freq: frequency in Hz
313 Tuning is a two step process. First we ask the front-end to
314 tune as close to the desired frequency as it can. Then we use
315 the result of that operation and our target_frequency to
316 determine the value for the digital down converter.
318 r = usrp.tune(self.u, 1, self.subdev, target_freq)
321 self.myform['freq2'].set_value(target_freq) # update displayed value
322 if self.show_debug_info:
323 self.myform['baseband2'].set_value(r.baseband_freq)
324 self.myform['ddc2'].set_value(r.dxc_freq)
329 def set_gain(self, gain):
330 self.myform['gain'].set_value(gain) # update displayed value
331 self.subdev.set_gain(gain)
333 def set_decim(self, decim):
334 ok = self.u.set_decim_rate(decim)
336 print "set_decim failed"
337 input_rate = self.u.adc_freq() / self.u.decim_rate()
338 self.scope.set_sample_rate(input_rate)
339 if self.show_debug_info: # update displayed values
340 self.myform['decim'].set_value(self.u.decim_rate())
341 self.myform['fs@usb'].set_value(self.u.adc_freq() / self.u.decim_rate())
345 app = stdgui2.stdapp(app_top_block, "USRP O'scope", nstatus=1)
348 if __name__ == '__main__':