diff options
Diffstat (limited to 'gnuradio-core')
-rw-r--r-- | gnuradio-core/gnuradio-core.conf | 1 | ||||
-rw-r--r-- | gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc | 64 | ||||
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_top_block.cc | 16 | ||||
-rw-r--r-- | gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py | 682 | ||||
-rwxr-xr-x | gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor | 66 |
5 files changed, 366 insertions, 463 deletions
diff --git a/gnuradio-core/gnuradio-core.conf b/gnuradio-core/gnuradio-core.conf index 3ed9892c73..cf3df4aea7 100644 --- a/gnuradio-core/gnuradio-core.conf +++ b/gnuradio-core/gnuradio-core.conf @@ -12,4 +12,5 @@ export = True [ControlPort] on = False +edges_list = False config = # ${prefix}/etc/gnuradio/ctrlport.conf diff --git a/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc b/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc index f19c7303d2..5287257d77 100644 --- a/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc +++ b/gnuradio-core/src/examples/ctrlport/pfb_sync_test-qt.grc @@ -1,6 +1,6 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Thu Feb 21 19:08:22 2013</timestamp> + <timestamp>Tue Feb 26 14:26:03 2013</timestamp> <block> <key>options</key> <param> @@ -613,37 +613,6 @@ </param> </block> <block> - <key>blocks_throttle</key> - <param> - <key>id</key> - <value>blocks_throttle_0</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>type</key> - <value>byte</value> - </param> - <param> - <key>samples_per_second</key> - <value>samp_rate</value> - </param> - <param> - <key>vlen</key> - <value>1</value> - </param> - <param> - <key>_coordinate</key> - <value>(623, 64)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> <key>gr_vector_source_x</key> <param> <key>id</key> @@ -748,6 +717,37 @@ <value>0</value> </param> </block> + <block> + <key>blocks_throttle</key> + <param> + <key>id</key> + <value>blocks_throttle_0</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>samples_per_second</key> + <value>samp_rate</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> + <param> + <key>_coordinate</key> + <value>(623, 64)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> <connection> <source_block_id>blocks_throttle_0</source_block_id> <sink_block_id>digital_psk_mod_0</sink_block_id> diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.cc b/gnuradio-core/src/lib/runtime/gr_top_block.cc index e5859768de..c6118bcfdd 100644 --- a/gnuradio-core/src/lib/runtime/gr_top_block.cc +++ b/gnuradio-core/src/lib/runtime/gr_top_block.cc @@ -138,13 +138,15 @@ gr_top_block::setup_rpc() "items", "Max number of output items", RPC_PRIVLVL_MIN, DISPNULL))); - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_get<gr_top_block, std::string>( - alias(), "edge list", - &gr_top_block::edge_list, - pmt::mp(""), pmt::mp(""), pmt::mp(""), - "edges", "List of edges in the graph", - RPC_PRIVLVL_MIN, DISPNULL))); + if(gr_prefs::singleton()->get_bool("ControlPort", "edges_list", false)) { + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<gr_top_block, std::string>( + alias(), "edge list", + &gr_top_block::edge_list, + pmt::mp(""), pmt::mp(""), pmt::mp(""), + "edges", "List of edges in the graph", + RPC_PRIVLVL_MIN, DISPNULL))); + } // Setters add_rpc_variable( diff --git a/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py b/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py index 091f0642c6..f797271970 100644 --- a/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py +++ b/gnuradio-core/src/python/gnuradio/ctrlport/GrDataPlotter.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2012 Free Software Foundation, Inc. +# Copyright 2012,2013 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -32,34 +32,68 @@ except ImportError: print "Error: Program requires PyQt4 and gr-qtgui." sys.exit(1) -class GrDataPlotterC(gr.top_block): - def __init__(self, name, rate, pmin=None, pmax=None, stripchart=False): +class GrDataPlotParent(gr.top_block, QtGui.QWidget): + # Setup signals + plotupdated = QtCore.pyqtSignal(QtGui.QWidget) + + def __init__(self, name, rate, pmin=None, pmax=None): gr.top_block.__init__(self) + QtGui.QWidget.__init__(self, None) - self._stripchart = stripchart self._name = name self._npts = 500 - samp_rate = 1.0 + self._rate = rate + self.knobnames = [name,] + + self.layout = QtGui.QVBoxLayout() + self.setLayout(self.layout) + + self.setAcceptDrops(True) - self._last_data = self._npts*[0,] - self._data_len = 0 + def _setup(self, nconnections): + self.stop() + self.wait() - self.src = gr.vector_source_c([]) - self.thr = blocks.throttle(gr.sizeof_gr_complex, rate) - self.snk = qtgui.time_sink_c(self._npts, samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) + if(self.layout.count() > 0): + # Remove and disconnect. Making sure no references to snk + # remain so that the plot gets deleted. + self.layout.removeWidget(self.py_window) + self.disconnect(self.thr, (self.snk, 0)) + self.disconnect(self.src[0], self.thr) + for n in xrange(1, self._ncons): + self.disconnect(self.src[n], (self.snk,n)) - self.connect(self.src, self.thr, (self.snk, 0)) + self._ncons = nconnections + self._data_len = self._ncons*[0,] - self.snk.set_line_label(0, "Real") - self.snk.set_line_label(1, "Imag") + self.thr = blocks.throttle(self._datasize, self._rate) + self.snk = self.get_qtsink() + + self.connect(self.thr, (self.snk, 0)) + + self._last_data = [] + self.src = [] + for n in xrange(self._ncons): + self.set_line_label(n, self.knobnames[n]) + + self._last_data.append(int(self._npts)*[0,]) + self.src.append(self.get_vecsource()) + + if(n == 0): + self.connect(self.src[n], self.thr) + else: + self.connect(self.src[n], (self.snk,n)) self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + self.layout.addWidget(self.py_window) + def __del__(self): pass + def close(self): + self.snk.close() + def qwidget(self): return self.py_window @@ -69,162 +103,172 @@ class GrDataPlotterC(gr.top_block): def semilogy(self, en=True): self.snk.enable_semilogy(en) - def stem(self, en=True): - self.snk.enable_stem_plot(en) + def dragEnterEvent(self, e): + e.acceptProposedAction() + + def dropEvent(self, e): + if(e.mimeData().hasFormat("text/plain")): + data = str(e.mimeData().text()) + + #"PlotData:{0}:{1}".format(tag, iscomplex) + datalst = data.split(":::") + tag = datalst[0] + name = datalst[1] + cpx = datalst[2] != "0" + + if(tag == "PlotData" and cpx == self._iscomplex): + self.knobnames.append(name) + + # create a new qwidget plot with the new data stream. + self._setup(len(self.knobnames)) + + # emit that this plot has been updated with a new qwidget. + self.plotupdated.emit(self) + + e.acceptProposedAction() + + def data_to_complex(self, data): + if(self._iscomplex): + data_r = data[0::2] + data_i = data[1::2] + data = [complex(r,i) for r,i in zip(data_r, data_i)] + return data def update(self, data): # Ask GUI if there has been a change in nsamps - npts = self.snk.nsamps() + npts = self.get_npts() if(self._npts != npts): # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] + for n in xrange(self._ncons): + if(npts < self._npts): + if(self._data_len[n] < npts): + self._last_data[n] = self._last_data[n][0:npts] + else: + self._last_data[n] = self._last_data[n][self._data_len[n]-npts:self._data_len[n]] + self._data_len[n] = npts else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] + self._last_data[n] += (npts - self._npts)*[0,] self._npts = npts self.snk.reset() - + if(self._stripchart): # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + for n in xrange(self._ncons): + if(type(data[n]) == list): + data[n] = self.data_to_complex(data[n]) + if(len(data[n]) > self._npts): + self.src[n].set_data(data[n]) + self._last_data[n] = data[n][-self._npts:] + else: + newdata = self._last_data[n][-(self._npts-len(data)):] + newdata += data[n] + self.src[n].set_data(newdata) + self._last_data[n] = newdata + + else: # single value update + if(self._iscomplex): + data[n] = complex(data[n][0], data[n][1]) + if(self._data_len[n] < self._npts): + self._last_data[n][self._data_len[n]] = data[n] + self._data_len[n] += 1 + else: + self._last_data[n] = self._last_data[n][1:] + self._last_data[n].append(data[n]) + self.src[n].set_data(self._last_data[n]) else: - if(type(data) != list): - data = [data,] - self.src.set_data(data) + for n in xrange(self._ncons): + if(type(data[n]) != list): + data[n] = [data[n],] + data[n] = self.data_to_complex(data[n]) + self.src[n].set_data(data[n]) + + -class GrDataPlotterF(gr.top_block): +class GrDataPlotterC(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None, stripchart=False): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) self._stripchart = stripchart - self._name = name - self._npts = 500 - samp_rate = 1.0 + self._datasize = gr.sizeof_gr_complex + self._iscomplex = True - self._last_data = self._npts*[0,] - self._data_len = 0 + self._setup(1) - self.src = gr.vector_source_f([]) - self.thr = blocks.throttle(gr.sizeof_float, rate) - self.snk = qtgui.time_sink_f(self._npts, samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) + def stem(self, en=True): + self.snk.enable_stem_plot(en) - self.connect(self.src, self.thr, (self.snk, 0)) + def get_qtsink(self): + snk = qtgui.time_sink_c(self._npts, 1.0, + self._name, self._ncons) + snk.enable_autoscale(True) + return snk - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + def get_vecsource(self): + return gr.vector_source_c([]) - def __del__(self): - pass + def get_npts(self): + self._npts = self.snk.nsamps() + return self._npts - def qwidget(self): - return self.py_window + def set_line_label(self, n, name): + self.snk.set_line_label(2*n+0, "Re{" + self.knobnames[n] + "}") + self.snk.set_line_label(2*n+1, "Im{" + self.knobnames[n] + "}") - def name(self): - return self._name - def semilogy(self, en=True): - self.snk.enable_semilogy(en) +class GrDataPlotterF(GrDataPlotParent): + def __init__(self, name, rate, pmin=None, pmax=None, stripchart=False): + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - def stem(self, en=True): - self.snk.enable_stem_plot(en) + self._stripchart = stripchart + self._datasize = gr.sizeof_float + self._iscomplex = False - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = self.snk.nsamps() - if(self._npts != npts): + self._setup(1) - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() + def stem(self, en=True): + self.snk.enable_stem_plot(en) - if(self._stripchart): - # Update the plot data depending on type - if(type(data) == list): - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) - else: - if(type(data) != list): - data = [data,] - self.src.set_data(data) + def get_qtsink(self): + snk = qtgui.time_sink_f(self._npts, 1.0, + self._name, self._ncons) + snk.enable_autoscale(True) + return snk + + def get_vecsource(self): + return gr.vector_source_f([]) + + def get_npts(self): + self._npts = self.snk.nsamps() + return self._npts + + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrDataPlotterConst(gr.top_block): - def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) - - self._name = name - self._npts = 500 - samp_rate = 1.0 - self._last_data = self._npts*[0,] - self._data_len = 0 - - self.src = gr.vector_source_c([]) - self.thr = blocks.throttle(gr.sizeof_gr_complex, rate) - self.snk = qtgui.const_sink_c(self._npts, - self._name, 1) - self.snk.enable_autoscale(True) +class GrDataPlotterConst(GrDataPlotParent): + def __init__(self, name, rate, pmin=None, pmax=None): + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self.connect(self.src, self.thr, (self.snk, 0)) + self._datasize = gr.sizeof_gr_complex + self._stripchart = False + self._iscomplex = True - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + self._setup(1) - def __del__(self): - pass + def get_qtsink(self): + snk = qtgui.const_sink_c(self._npts, + self._name, + self._ncons) + snk.enable_autoscale(True) + return snk - def qwidget(self): - return self.py_window + def get_vecsource(self): + return gr.vector_source_c([]) - def name(self): - return self._name + def get_npts(self): + self._npts = self.snk.nsamps() + return self._npts def scatter(self, en=True): if(en): @@ -232,327 +276,133 @@ class GrDataPlotterConst(gr.top_block): else: self.snk.set_line_style(0, 1) - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = self.snk.nsamps() - if(self._npts != npts): - - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrDataPlotterPsdC(gr.top_block): +class GrDataPlotterPsdC(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._name = name - self._samp_rate = 1.0 - self._fftsize = 2048 + self._datasize = gr.sizeof_gr_complex + self._stripchart = True + self._iscomplex = True + + self._npts = 2048 self._wintype = gr.firdes.WIN_BLACKMAN_hARRIS self._fc = 0 - - self._last_data = self._fftsize*[0,] - self._data_len = 0 - self.src = gr.vector_source_c([]) - self.thr = blocks.throttle(gr.sizeof_gr_complex, rate) - self.snk = qtgui.freq_sink_c(self._fftsize, self._wintype, - self._fc, self._samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) + self._setup(1) - self.connect(self.src, self.thr, (self.snk, 0)) + def get_qtsink(self): + snk = qtgui.freq_sink_c(self._npts, self._wintype, + self._fc, 1.0, + self._name, + self._ncons) + snk.enable_autoscale(True) + return snk - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) - - def __del__(self): - pass + def get_vecsource(self): + return gr.vector_source_c([]) - def qwidget(self): - return self.py_window + def get_npts(self): + self._npts = self.snk.fft_size() + return self._npts - def name(self): - return self._name + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) - def update(self, data): - # Ask GUI if there has been a change in nsamps - fftsize = self.snk.fft_size() - if(self._fftsize != fftsize): - - # Adjust buffers to accomodate new settings - if(fftsize < self._fftsize): - if(self._data_len < fftsize): - self._last_data = self._last_data[0:fftsize] - else: - self._last_data = self._last_data[self._data_len-fftsize:self._data_len] - self._data_len = fftsize - else: - self._last_data += (fftsize - self._fftsize)*[0,] - self._fftsize = fftsize - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._fftsize): - self.src.set_data(data) - self._last_data = data[-self._fftsize:] - else: - newdata = self._last_data[-(self._fftsize-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._fftsize): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) -class GrDataPlotterPsdF(gr.top_block): +class GrDataPlotterPsdF(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._name = name - self._samp_rate = 1.0 - self._fftsize = 2048 + self._datasize = gr.sizeof_float + self._stripchart = True + self._iscomplex = False + + self._npts = 2048 self._wintype = gr.firdes.WIN_BLACKMAN_hARRIS self._fc = 0 - - self._last_data = self._fftsize*[0,] - self._data_len = 0 - self.src = gr.vector_source_f([]) - self.thr = blocks.throttle(gr.sizeof_float, rate) - self.snk = qtgui.freq_sink_f(self._fftsize, self._wintype, - self._fc, self._samp_rate, - self._name, 1) - self.snk.enable_autoscale(True) + self._setup(1) - self.connect(self.src, self.thr, (self.snk, 0)) + def get_qtsink(self): + snk = qtgui.freq_sink_f(self._npts, self._wintype, + self._fc, 1.0, + self._name, + self._ncons) + snk.enable_autoscale(True) + return snk - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) - - def __del__(self): - pass + def get_vecsource(self): + return gr.vector_source_f([]) - def qwidget(self): - return self.py_window + def get_npts(self): + self._npts = self.snk.fft_size() + return self._npts - def name(self): - return self._name + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) - def update(self, data): - # Ask GUI if there has been a change in nsamps - fftsize = self.snk.fft_size() - if(self._fftsize != fftsize): - - # Adjust buffers to accomodate new settings - if(fftsize < self._fftsize): - if(self._data_len < fftsize): - self._last_data = self._last_data[0:fftsize] - else: - self._last_data = self._last_data[self._data_len-fftsize:self._data_len] - self._data_len = fftsize - else: - self._last_data += (fftsize - self._fftsize)*[0,] - self._fftsize = fftsize - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - data_r = data[0::2] - data_i = data[1::2] - data = [complex(r,i) for r,i in zip(data_r, data_i)] - if(len(data) > self._fftsize): - self.src.set_data(data) - self._last_data = data[-self._fftsize:] - else: - newdata = self._last_data[-(self._fftsize-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._fftsize): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) - -class GrTimeRasterF(gr.top_block): +class GrTimeRasterF(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) - - self._name = name - self._npts = 100 - self._rows = 100 - samp_rate = 1.0 - - self._last_data = self._npts*[0,] - self._data_len = 0 + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self.src = gr.vector_source_f([]) - self.thr = blocks.throttle(gr.sizeof_float, rate) - self.snk = qtgui.time_raster_sink_f(samp_rate, self._npts, self._rows, - [], [], self._name, 1) + self._npts = 10 + self._rows = 40 - self.connect(self.src, self.thr, (self.snk, 0)) + self._datasize = gr.sizeof_float + self._stripchart = False + self._iscomplex = False - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + self._setup(1) - def __del__(self): - pass + def get_qtsink(self): + snk = qtgui.time_raster_sink_f(1.0, self._npts, self._rows, + [], [], self._name, + self._ncons) + return snk - def qwidget(self): - return self.py_window + def get_vecsource(self): + return gr.vector_source_f([]) - def name(self): - return self._name + def get_npts(self): + self._npts = self.snk.num_cols() + return self._npts - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = int(self.snk.num_cols()) - if(self._npts != npts): - - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) -class GrTimeRasterB(gr.top_block): +class GrTimeRasterB(GrDataPlotParent): def __init__(self, name, rate, pmin=None, pmax=None): - gr.top_block.__init__(self) - - self._name = name - self._npts = 100 - self._rows = 100 - samp_rate = 1.0 + GrDataPlotParent.__init__(self, name, rate, pmin, pmax) - self._last_data = self._npts*[0,] - self._data_len = 0 + self._npts = 10 + self._rows = 40 - self.src = gr.vector_source_b([]) - self.thr = blocks.throttle(gr.sizeof_char, rate) - self.snk = qtgui.time_raster_sink_b(samp_rate, self._npts, self._rows, - [], [], self._name, 1) + self._datasize = gr.sizeof_char + self._stripchart = False + self._iscomplex = False - self.connect(self.src, self.thr, (self.snk, 0)) + self._setup(1) - self.py_window = sip.wrapinstance(self.snk.pyqwidget(), QtGui.QWidget) + def get_qtsink(self): + snk = qtgui.time_raster_sink_b(1.0, self._npts, self._rows, + [], [], self._name, + self._ncons) + return snk - def __del__(self): - pass - - def qwidget(self): - return self.py_window - - def name(self): - return self._name + def get_vecsource(self): + return gr.vector_source_b([]) - def update(self, data): - # Ask GUI if there has been a change in nsamps - npts = self.snk.num_cols() - if(self._npts != npts): + def get_npts(self): + self._npts = self.snk.num_cols() + return self._npts - # Adjust buffers to accomodate new settings - if(npts < self._npts): - if(self._data_len < npts): - self._last_data = self._last_data[0:npts] - else: - self._last_data = self._last_data[self._data_len-npts:self._data_len] - self._data_len = npts - else: - self._last_data += (npts - self._npts)*[0,] - self._npts = npts - self.snk.reset() - - # Update the plot data depending on type - if(type(data) == list): - if(len(data) > self._npts): - self.src.set_data(data) - self._last_data = data[-self._npts:] - else: - newdata = self._last_data[-(self._npts-len(data)):] - newdata += data - self.src.set_data(newdata) - self._last_data = newdata - - else: # single value update - if(self._data_len < self._npts): - self._last_data[self._data_len] = data - self._data_len += 1 - else: - self._last_data = self._last_data[1:] - self._last_data.append(data) - self.src.set_data(self._last_data) + def set_line_label(self, n, name): + self.snk.set_line_label(n, self.knobnames[n]) class GrDataPlotterValueTable: diff --git a/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor b/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor index 60a810b04e..e71cd92ab7 100755 --- a/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor +++ b/gnuradio-core/src/python/gnuradio/ctrlport/gr-ctrlport-monitor @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2012 Free Software Foundation, Inc. +# Copyright 2012,2013 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -24,7 +24,7 @@ from gnuradio import gr, ctrlport from PyQt4 import QtCore,Qt import PyQt4.QtGui as QtGui -import sys, time +import os, sys, time import Ice from gnuradio.ctrlport.IceRadioClient import * @@ -55,7 +55,7 @@ class MAINWindow(QtGui.QMainWindow): def __init__(self, radio, port, interface): super(MAINWindow, self).__init__() - self.updateRate = 2000; + self.updateRate = 1000; self.conns = [] self.plots = [] self.knobprops = [] @@ -83,6 +83,11 @@ class MAINWindow(QtGui.QMainWindow): icon = QtGui.QIcon(ctrlport.__path__[0] + "/icon.png" ) self.setWindowIcon(icon) + # Locally turn off ControlPort export from GR. This prevents + # our GR-based plotters from launching their own ControlPort + # instance (and possibly causing a port collision if one has + # been specified). + os.environ['GR_CONF_CONTROLPORT_ON'] = 'False' def setUpdateRate(self,nur): self.updateRate = int(nur); @@ -217,17 +222,55 @@ class MAINWindow(QtGui.QMainWindow): else: self.newPlotPsdC(tag, uid, title) + def startDrag(self, e): + drag = QtGui.QDrag(self) + mime_data = QtCore.QMimeData() + + tag = str(e.text(0)) + tree = e.treeWidget().parent() + knobprop = self.knobprops[tree.uid][tag] + disp = knobprop.display + iscomplex = (disp & gr.DISPOPTCPLX) or (disp & gr.DISPXY) + + if(disp != gr.DISPNULL): + data = "PlotData:::{0}:::{1}".format(tag, iscomplex) + else: + data = "OtherData:::{0}:::{1}".format(tag, iscomplex) + + mime_data.setText(data) + drag.setMimeData(mime_data) + + drop = drag.start() + def createPlot(self, plot, uid, title): plot.start() self.plots[uid].append(plot) - self.mdiArea.addSubWindow(plot.qwidget()) - plot.qwidget().setWindowTitle("{0}: {1}".format(title, plot.name())) + self.mdiArea.addSubWindow(plot) + plot.setWindowTitle("{0}: {1}".format(title, plot.name())) self.connect(plot.qwidget(), QtCore.SIGNAL('destroyed(QObject*)'), self.destroyPlot) - plot.qwidget().show() + # when the plot is updated via drag-and-drop, we need to be + # notified of the new qwidget that's created so we can + # properly destroy it. + plot.plotupdated.connect(self.plotUpdated) + + plot.show() + + def plotUpdated(self, q): + # the plot has been updated with a new qwidget; make sure this + # gets dies to the destroyPlot function. + for i, plots in enumerate(self.plots): + for p in plots: + if(p == q): + #plots.remove(p) + #plots.append(q) + self.connect(q.qwidget(), + QtCore.SIGNAL('destroyed(QObject*)'), + self.destroyPlot) + break def destroyPlot(self, obj): for plots in self.plots: @@ -275,7 +318,9 @@ class MAINWindow(QtGui.QMainWindow): def update(self, knobs, uid): #sys.stderr.write("KNOB KEYS: {0}\n".format(knobs.keys())) for plot in self.plots[uid]: - data = knobs[plot.name()].value + data = [] + for n in plot.knobnames: + data.append(knobs[n].value) plot.update(data) plot.stop() plot.wait() @@ -639,7 +684,7 @@ class MForm(QtGui.QWidget): self.table.treeWidget.setEditTriggers(QtGui.QAbstractItemView.EditKeyPressed) self.table.treeWidget.setSortingEnabled(True) self.table.treeWidget.setDragEnabled(True) - + # add things to layouts self.horizontalLayout.addWidget(self.table.treeWidget) @@ -657,6 +702,11 @@ class MForm(QtGui.QWidget): QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.parent.newSub); + # Allow drag/drop event from table item to plotter + self.connect(self.table.treeWidget, + QtCore.SIGNAL('itemPressed(QTreeWidgetItem*, int)'), + self.parent.startDrag) + def openMenu(self, pos): index = self.table.treeWidget.selectedIndexes() item = self.table.treeWidget.itemFromIndex(index[0]) |