Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-examples / python / usrp2 / usrp2_wfm_qt.py
1 #!/usr/bin/env python
2 #
3 # Copyright 2005,2006,2007,2008,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, eng_notation, optfir
24 from gnuradio import audio
25 from gnuradio import usrp2
26 from gnuradio import blks2
27 from gnuradio.eng_option import eng_option
28 from optparse import OptionParser
29 import sys
30 import math
31
32
33 try:
34     from gnuradio.qtgui import qtgui
35     from PyQt4 import QtGui, QtCore
36     import sip
37 except ImportError:
38     print "Please install gr-qtgui."
39     sys.exit(1)
40     
41 try:
42     from qt_wfm_interface import Ui_InterfaceWindow
43 except ImportError:
44     print "Error: could not find qt_wfm_interface.py:"
45     print "\tPlease run: \"pyuic4 qt_wfm_interface.ui -o qt_wfm_interface.py\""
46     sys.exit(1)
47
48 print "This program is not in a proper working state. Comment this out if you want to play."
49 sys.exit(1)
50
51
52 # ////////////////////////////////////////////////////////////////////
53 #        Define the QT Interface and Control Dialog
54 # ////////////////////////////////////////////////////////////////////
55
56
57 class dialog_box(QtGui.QMainWindow):
58     def __init__(self, snk_usrp, snk_vol, fg, parent=None):
59
60         QtGui.QWidget.__init__(self, parent)
61         self.gui = Ui_InterfaceWindow()
62         self.gui.setupUi(self)
63
64         self.fg = fg
65
66         # Set USRP parameters
67         self.set_bw(self.fg.usrp_bw())
68         self.set_freq(self.fg.freq())
69         self.set_gain(self.fg.gain())
70         self.set_volume(self.fg.volume())
71
72         # Add the qtsnk widgets to the hlayout box
73         self.gui.sinkLayout.addWidget(snk_usrp)
74         self.gui.sinkLayout.addWidget(snk_vol)
75
76
77         # Connect up some signals
78         self.connect(self.gui.pauseButton, QtCore.SIGNAL("clicked()"),
79                      self.pauseFg)
80
81         self.connect(self.gui.bandwidthEdit, QtCore.SIGNAL("editingFinished()"),
82                      self.bwEditText)
83         self.connect(self.gui.freqEdit, QtCore.SIGNAL("editingFinished()"),
84                      self.freqEditText)
85         self.connect(self.gui.gainEdit, QtCore.SIGNAL("editingFinished()"),
86                      self.gainEditText)
87
88         self.connect(self.gui.volumeEdit, QtCore.SIGNAL("editingFinished()"),
89                      self.volumeEditText)
90
91
92     def pauseFg(self):
93         if(self.gui.pauseButton.text() == "Pause"):
94             self.fg.stop()
95             self.fg.wait()
96             self.gui.pauseButton.setText("Unpause")
97         else:
98             self.fg.start()
99             self.gui.pauseButton.setText("Pause")
100
101
102     # Accessor functions for Gui to manipulate USRP
103     def set_bw(self, bw):
104         self.gui.bandwidthEdit.setText(QtCore.QString("%1").arg(bw))
105
106     def set_freq(self, freq):
107         self.gui.freqEdit.setText(QtCore.QString("%1").arg(freq))
108
109     def set_gain(self, gain):
110         self.gui.gainEdit.setText(QtCore.QString("%1").arg(gain))
111
112     def set_volume(self, vol):
113         self.gui.volumeEdit.setText(QtCore.QString("%1").arg(vol))
114
115     def bwEditText(self):
116         try:
117             bw = self.gui.bandwidthEdit.text().toDouble()[0]
118             self.fg.set_usrp_bw(bw)
119         except RuntimeError:
120             pass
121
122     def freqEditText(self):
123         try:
124             freq = self.gui.freqEdit.text().toDouble()[0]
125             self.fg.set_freq(freq)
126         except RuntimeError:
127             pass
128
129     def gainEditText(self):
130         try:
131             gain = self.gui.gainEdit.text().toDouble()[0]
132             self.fg.set_gain(gain)
133         except RuntimeError:
134             pass
135
136     def volumeEditText(self):
137         try:
138             vol = self.gui.volumeEdit.text().toDouble()[0]
139             self.fg.set_volume(vol)
140         except RuntimeError:
141             pass
142
143
144
145
146 # ////////////////////////////////////////////////////////////////////
147 #        Define the GNU Radio Top Block
148 # ////////////////////////////////////////////////////////////////////
149
150
151 class wfm_rx_block (gr.top_block):
152     def __init__(self):
153         gr.top_block.__init__(self)
154         
155         parser = OptionParser(option_class=eng_option)
156         parser.add_option("-e", "--interface", type="string", default="eth0",
157                           help="select Ethernet interface, default is eth0")
158         parser.add_option("-m", "--mac-addr", type="string", default="",
159                           help="select USRP by MAC address, default is auto-select")
160         #parser.add_option("-A", "--antenna", default=None,
161         #                  help="select Rx Antenna (only on RFX-series boards)")
162         parser.add_option("-f", "--freq", type="eng_float", default=100.1,
163                           help="set frequency to FREQ", metavar="FREQ")
164         parser.add_option("-g", "--gain", type="eng_float", default=None,
165                           help="set gain in dB (default is midpoint)")
166         parser.add_option("-V", "--volume", type="eng_float", default=None,
167                           help="set volume (default is midpoint)")
168         parser.add_option("-O", "--audio-output", type="string", default="",
169                           help="pcm device name.  E.g., hw:0,0 or surround51 or /dev/dsp")
170
171         (options, args) = parser.parse_args()
172         if len(args) != 0:
173             parser.print_help()
174             sys.exit(1)
175         
176         self._volume = options.volume
177         self._usrp_freq = options.freq
178         self._usrp_gain = options.gain
179         self._audio_rate = int(32e3)
180
181         # build graph
182      
183         self.u = usrp2.source_32fc(options.interface, options.mac_addr)
184
185         # calculate decimation values to get USRP BW at 320 kHz
186         self.calculate_usrp_bw(320e3)
187
188         self.set_decim(self._usrp_decim)
189
190         #FIXME: need named constants and text descriptions available to (gr-)usrp2 even
191         #when usrp(1) module is not built.  A usrp_common module, perhaps?
192         dbid = self.u.daughterboard_id()
193         print "Using RX d'board 0x%04X" % (dbid,)
194         #if not (dbid == 0x0001 or #usrp_dbid.BASIC_RX
195         #        dbid == 0x0003 or #usrp_dbid.TV_RX
196         #        dbid == 0x000c or #usrp_dbid.TV_RX_REV_2
197         #        dbid == 0x0040):  #usrp_dbid.TV_RX_REV_3    
198         #    print "This daughterboard does not cover the required frequency range"
199         #    print "for this application.  Please use a BasicRX or TVRX daughterboard."
200         #    raw_input("Press ENTER to continue anyway, or Ctrl-C to exit.")
201
202         chan_filt_coeffs = optfir.low_pass (1,                 # gain
203                                             self._usrp_rate,   # sampling rate
204                                             80e3,        # passband cutoff
205                                             115e3,       # stopband cutoff
206                                             0.1,         # passband ripple
207                                             60)          # stopband attenuation
208         #print len(chan_filt_coeffs)
209         chan_filt = gr.fir_filter_ccf (self._chanfilt_decim, chan_filt_coeffs)
210
211         self.guts = blks2.wfm_rcv (self._demod_rate, self._audio_decim)
212
213         self.volume_control = gr.multiply_const_ff(1)
214
215         # sound card as final sink
216         #audio_sink = audio.sink (int (audio_rate),
217         #                         options.audio_output,
218         #                         False)  # ok_to_block
219         audio_sink = audio.sink (self._audio_rate,
220                                  options.audio_output)
221
222         
223         if self._usrp_gain is None:
224             # if no gain was specified, use the mid-point in dB
225             g = self.u.gain_range()
226             print "Gain range: ", g
227             self._usrp_gain = float(g[0]+g[1])/2
228
229         if self._volume is None:
230             g = self.volume_range()
231             self._volume = float(g[0]+g[1])/2
232             
233         if abs(self._usrp_freq) < 1e6:
234             self._usrp_freq *= 1e6
235
236         # set initial values
237         self.set_gain(self._usrp_gain)
238         self.set_volume(self._volume)
239         if not(self.set_freq(self._usrp_freq)):
240             print ("Failed to set initial frequency")
241
242
243         # Define a GUI sink to display the received signal
244         self.qapp = QtGui.QApplication(sys.argv)
245         fftsize = 2048
246         
247         self.usrp_rx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS,
248                                     -self._usrp_rate/2.0, self._usrp_rate/2.0,
249                                     "Received Signal", True, True, False, True, False,
250                                     use_openGL=False)
251         self.usrp_rx2 = qtgui.sink_f(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS,
252                                     -self._usrp_rate/2.0, self._usrp_rate/2.0,
253                                     "Received Signal", True, True, False, True, False)
254         
255         # now wire it all together
256         self.connect (self.u, chan_filt, self.guts, self.volume_control, audio_sink)
257         self.connect (self.u, self.usrp_rx)
258         self.connect (self.volume_control, self.usrp_rx2)
259         
260         usrp_rx_widget = sip.wrapinstance(self.usrp_rx.pyqwidget(), QtGui.QWidget)
261         usrp_rx2_widget = sip.wrapinstance(self.usrp_rx2.pyqwidget(), QtGui.QWidget)
262         
263         self.main_box = dialog_box(usrp_rx_widget, usrp_rx2_widget, self)
264         self.main_box.show()
265
266
267     def calculate_usrp_bw(self, bw):
268         """
269         Calculate the different decimation rates that make the USRP BW equal to the
270         input bandwidth parameter 'bw' and the audio bandwidth equal to the system-
271         wide bandwidth 'self._audio_rate'
272         """
273         
274         adc_rate = self.u.adc_rate()
275         d_usrp = int(adc_rate/bw)
276         bw_real = adc_rate / float(d_usrp)
277
278         d_chan = 1
279         demod_rate = bw_real / d_chan
280
281         d_audio = int(bw_real / self._audio_rate)
282         audio_rate = demod_rate / d_audio
283
284         self._usrp_decim  = d_usrp
285         self._chanfilt_decim = d_chan
286         self._audio_decim = d_audio
287         self._demod_rate = demod_rate
288         self._usrp_rate = bw_real
289
290         print "USRP Decimation:  ", self._usrp_decim
291         print "USRP Bandwidth:   ", bw_real
292         print "Audio Decimation: ", self._audio_decim
293         print "Audio Bandwidth:  ", audio_rate
294
295     def set_volume (self, vol):
296         g = self.volume_range()
297         self._volume = max(g[0], min(g[1], vol))
298         self.volume_control.set_k(10**(self._volume/10))
299                                         
300     def set_freq(self, target_freq):
301         """
302         Set the center frequency we're interested in.
303
304         @param target_freq: frequency in Hz
305         @rypte: bool
306
307         Tuning is a two step process.  First we ask the front-end to
308         tune as close to the desired frequency as it can.  Then we use
309         the result of that operation and our target_frequency to
310         determine the value for the digital down converter.
311         """
312         r = self.u.set_center_freq(target_freq)
313         if r:
314             self._usrp_freq = target_freq
315             return True
316         return False
317
318     def set_usrp_bw(self, bw):
319         self.calculate_usrp_bw(bw)
320
321     def set_gain(self, gain):
322         self._usrp_gain = gain
323         self.u.set_gain(gain)
324
325     def set_decim(self, decim):
326         self._usrp_decim = int(decim)
327         self.u.set_decim(self._usrp_decim)
328
329     def volume(self):
330         return self._volume
331     
332     def freq(self):
333         return self._usrp_freq
334
335     def usrp_bw(self):
336         return self._usrp_rate
337
338     def gain(self):
339         return self._usrp_gain
340
341     def decim(self):
342         return self._usrp_decim
343
344     def volume_range(self):
345         return (-20.0, 0.0, 0.5)
346         
347
348 if __name__ == '__main__':
349     tb = wfm_rx_block()
350     tb.start()
351     tb.qapp.exec_()
352