switch source package format to 3.0 quilt
[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 or #usrp_dbid.TV_RX_REV_3
198         #        dbid == 0x0043 or #usrp_dbid.TV_RX_MIMO
199         #        dbid == 0x0044 or #usrp_dbid.TV_RX_REV_2_MIMO
200         #        dbid == 0x0045 ): #usrp_dbid.TV_RX_REV_3_MIMO
201         #    print "This daughterboard does not cover the required frequency range"
202         #    print "for this application.  Please use a BasicRX or TVRX daughterboard."
203         #    raw_input("Press ENTER to continue anyway, or Ctrl-C to exit.")
204
205         chan_filt_coeffs = optfir.low_pass (1,                 # gain
206                                             self._usrp_rate,   # sampling rate
207                                             80e3,        # passband cutoff
208                                             115e3,       # stopband cutoff
209                                             0.1,         # passband ripple
210                                             60)          # stopband attenuation
211         #print len(chan_filt_coeffs)
212         chan_filt = gr.fir_filter_ccf (self._chanfilt_decim, chan_filt_coeffs)
213
214         self.guts = blks2.wfm_rcv (self._demod_rate, self._audio_decim)
215
216         self.volume_control = gr.multiply_const_ff(1)
217
218         # sound card as final sink
219         #audio_sink = audio.sink (int (audio_rate),
220         #                         options.audio_output,
221         #                         False)  # ok_to_block
222         audio_sink = audio.sink (self._audio_rate,
223                                  options.audio_output)
224
225         
226         if self._usrp_gain is None:
227             # if no gain was specified, use the mid-point in dB
228             g = self.u.gain_range()
229             print "Gain range: ", g
230             self._usrp_gain = float(g[0]+g[1])/2
231
232         if self._volume is None:
233             g = self.volume_range()
234             self._volume = float(g[0]+g[1])/2
235             
236         if abs(self._usrp_freq) < 1e6:
237             self._usrp_freq *= 1e6
238
239         # set initial values
240         self.set_gain(self._usrp_gain)
241         self.set_volume(self._volume)
242         if not(self.set_freq(self._usrp_freq)):
243             print ("Failed to set initial frequency")
244
245
246         # Define a GUI sink to display the received signal
247         self.qapp = QtGui.QApplication(sys.argv)
248         fftsize = 2048
249         
250         self.usrp_rx = qtgui.sink_c(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS,
251                                     -self._usrp_rate/2.0, self._usrp_rate/2.0,
252                                     "Received Signal", True, True, False, True, False,
253                                     use_openGL=False)
254         self.usrp_rx2 = qtgui.sink_f(fftsize, gr.firdes.WIN_BLACKMAN_hARRIS,
255                                     -self._usrp_rate/2.0, self._usrp_rate/2.0,
256                                     "Received Signal", True, True, False, True, False)
257         
258         # now wire it all together
259         self.connect (self.u, chan_filt, self.guts, self.volume_control, audio_sink)
260         self.connect (self.u, self.usrp_rx)
261         self.connect (self.volume_control, self.usrp_rx2)
262         
263         usrp_rx_widget = sip.wrapinstance(self.usrp_rx.pyqwidget(), QtGui.QWidget)
264         usrp_rx2_widget = sip.wrapinstance(self.usrp_rx2.pyqwidget(), QtGui.QWidget)
265         
266         self.main_box = dialog_box(usrp_rx_widget, usrp_rx2_widget, self)
267         self.main_box.show()
268
269
270     def calculate_usrp_bw(self, bw):
271         """
272         Calculate the different decimation rates that make the USRP BW equal to the
273         input bandwidth parameter 'bw' and the audio bandwidth equal to the system-
274         wide bandwidth 'self._audio_rate'
275         """
276         
277         adc_rate = self.u.adc_rate()
278         d_usrp = int(adc_rate/bw)
279         bw_real = adc_rate / float(d_usrp)
280
281         d_chan = 1
282         demod_rate = bw_real / d_chan
283
284         d_audio = int(bw_real / self._audio_rate)
285         audio_rate = demod_rate / d_audio
286
287         self._usrp_decim  = d_usrp
288         self._chanfilt_decim = d_chan
289         self._audio_decim = d_audio
290         self._demod_rate = demod_rate
291         self._usrp_rate = bw_real
292
293         print "USRP Decimation:  ", self._usrp_decim
294         print "USRP Bandwidth:   ", bw_real
295         print "Audio Decimation: ", self._audio_decim
296         print "Audio Bandwidth:  ", audio_rate
297
298     def set_volume (self, vol):
299         g = self.volume_range()
300         self._volume = max(g[0], min(g[1], vol))
301         self.volume_control.set_k(10**(self._volume/10))
302                                         
303     def set_freq(self, target_freq):
304         """
305         Set the center frequency we're interested in.
306
307         @param target_freq: frequency in Hz
308         @rypte: bool
309
310         Tuning is a two step process.  First we ask the front-end to
311         tune as close to the desired frequency as it can.  Then we use
312         the result of that operation and our target_frequency to
313         determine the value for the digital down converter.
314         """
315         r = self.u.set_center_freq(target_freq)
316         if r:
317             self._usrp_freq = target_freq
318             return True
319         return False
320
321     def set_usrp_bw(self, bw):
322         self.calculate_usrp_bw(bw)
323
324     def set_gain(self, gain):
325         self._usrp_gain = gain
326         self.u.set_gain(gain)
327
328     def set_decim(self, decim):
329         self._usrp_decim = int(decim)
330         self.u.set_decim(self._usrp_decim)
331
332     def volume(self):
333         return self._volume
334     
335     def freq(self):
336         return self._usrp_freq
337
338     def usrp_bw(self):
339         return self._usrp_rate
340
341     def gain(self):
342         return self._usrp_gain
343
344     def decim(self):
345         return self._usrp_decim
346
347     def volume_range(self):
348         return (-20.0, 0.0, 0.5)
349         
350
351 if __name__ == '__main__':
352     tb = wfm_rx_block()
353     tb.start()
354     tb.qapp.exec_()
355