3 # Copyright 2005,2006,2007,2008,2009 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 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
34 from gnuradio.qtgui import qtgui
35 from PyQt4 import QtGui, QtCore
38 print "Please install gr-qtgui."
42 from qt_wfm_interface import Ui_InterfaceWindow
44 print "Error: could not find qt_wfm_interface.py:"
45 print "\tPlease run: \"pyuic4 qt_wfm_interface.ui -o qt_wfm_interface.py\""
48 print "This program is not in a proper working state. Comment this out if you want to play."
52 # ////////////////////////////////////////////////////////////////////
53 # Define the QT Interface and Control Dialog
54 # ////////////////////////////////////////////////////////////////////
57 class dialog_box(QtGui.QMainWindow):
58 def __init__(self, snk_usrp, snk_vol, fg, parent=None):
60 QtGui.QWidget.__init__(self, parent)
61 self.gui = Ui_InterfaceWindow()
62 self.gui.setupUi(self)
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())
72 # Add the qtsnk widgets to the hlayout box
73 self.gui.sinkLayout.addWidget(snk_usrp)
74 self.gui.sinkLayout.addWidget(snk_vol)
77 # Connect up some signals
78 self.connect(self.gui.pauseButton, QtCore.SIGNAL("clicked()"),
81 self.connect(self.gui.bandwidthEdit, QtCore.SIGNAL("editingFinished()"),
83 self.connect(self.gui.freqEdit, QtCore.SIGNAL("editingFinished()"),
85 self.connect(self.gui.gainEdit, QtCore.SIGNAL("editingFinished()"),
88 self.connect(self.gui.volumeEdit, QtCore.SIGNAL("editingFinished()"),
93 if(self.gui.pauseButton.text() == "Pause"):
96 self.gui.pauseButton.setText("Unpause")
99 self.gui.pauseButton.setText("Pause")
102 # Accessor functions for Gui to manipulate USRP
103 def set_bw(self, bw):
104 self.gui.bandwidthEdit.setText(QtCore.QString("%1").arg(bw))
106 def set_freq(self, freq):
107 self.gui.freqEdit.setText(QtCore.QString("%1").arg(freq))
109 def set_gain(self, gain):
110 self.gui.gainEdit.setText(QtCore.QString("%1").arg(gain))
112 def set_volume(self, vol):
113 self.gui.volumeEdit.setText(QtCore.QString("%1").arg(vol))
115 def bwEditText(self):
117 bw = self.gui.bandwidthEdit.text().toDouble()[0]
118 self.fg.set_usrp_bw(bw)
122 def freqEditText(self):
124 freq = self.gui.freqEdit.text().toDouble()[0]
125 self.fg.set_freq(freq)
129 def gainEditText(self):
131 gain = self.gui.gainEdit.text().toDouble()[0]
132 self.fg.set_gain(gain)
136 def volumeEditText(self):
138 vol = self.gui.volumeEdit.text().toDouble()[0]
139 self.fg.set_volume(vol)
146 # ////////////////////////////////////////////////////////////////////
147 # Define the GNU Radio Top Block
148 # ////////////////////////////////////////////////////////////////////
151 class wfm_rx_block (gr.top_block):
153 gr.top_block.__init__(self)
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")
171 (options, args) = parser.parse_args()
176 self._volume = options.volume
177 self._usrp_freq = options.freq
178 self._usrp_gain = options.gain
179 self._audio_rate = int(32e3)
183 self.u = usrp2.source_32fc(options.interface, options.mac_addr)
185 # calculate decimation values to get USRP BW at 320 kHz
186 self.calculate_usrp_bw(320e3)
188 self.set_decim(self._usrp_decim)
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.")
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)
214 self.guts = blks2.wfm_rcv (self._demod_rate, self._audio_decim)
216 self.volume_control = gr.multiply_const_ff(1)
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)
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
232 if self._volume is None:
233 g = self.volume_range()
234 self._volume = float(g[0]+g[1])/2
236 if abs(self._usrp_freq) < 1e6:
237 self._usrp_freq *= 1e6
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")
246 # Define a GUI sink to display the received signal
247 self.qapp = QtGui.QApplication(sys.argv)
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,
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)
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)
263 usrp_rx_widget = sip.wrapinstance(self.usrp_rx.pyqwidget(), QtGui.QWidget)
264 usrp_rx2_widget = sip.wrapinstance(self.usrp_rx2.pyqwidget(), QtGui.QWidget)
266 self.main_box = dialog_box(usrp_rx_widget, usrp_rx2_widget, self)
270 def calculate_usrp_bw(self, bw):
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'
277 adc_rate = self.u.adc_rate()
278 d_usrp = int(adc_rate/bw)
279 bw_real = adc_rate / float(d_usrp)
282 demod_rate = bw_real / d_chan
284 d_audio = int(bw_real / self._audio_rate)
285 audio_rate = demod_rate / d_audio
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
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
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))
303 def set_freq(self, target_freq):
305 Set the center frequency we're interested in.
307 @param target_freq: frequency in Hz
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.
315 r = self.u.set_center_freq(target_freq)
317 self._usrp_freq = target_freq
321 def set_usrp_bw(self, bw):
322 self.calculate_usrp_bw(bw)
324 def set_gain(self, gain):
325 self._usrp_gain = gain
326 self.u.set_gain(gain)
328 def set_decim(self, decim):
329 self._usrp_decim = int(decim)
330 self.u.set_decim(self._usrp_decim)
336 return self._usrp_freq
339 return self._usrp_rate
342 return self._usrp_gain
345 return self._usrp_decim
347 def volume_range(self):
348 return (-20.0, 0.0, 0.5)
351 if __name__ == '__main__':