summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnathan Corgan <johnathan@corganlabs.com>2015-04-26 16:13:41 -0700
committerJohnathan Corgan <johnathan@corganlabs.com>2015-04-26 16:13:41 -0700
commit5d6e87870328ce45eab28805e456324f14b8bfed (patch)
treeef5591d4eccdaaa66d8ac87986916b67ecde7cbf
parentc5e6d08637be1703af6f5905f21deceed49470a8 (diff)
parent327f07093aa75ff08a2509f77e8cbf4a840d3eed (diff)
Merge branch 'master' into next
-rw-r--r--gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx143
-rwxr-xr-xgnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py32
-rw-r--r--gnuradio-runtime/python/gnuradio/gr/tag_utils.py33
-rw-r--r--gr-analog/grc/analog_pwr_squelch_xx.xml2
-rw-r--r--gr-analog/include/gnuradio/analog/pwr_squelch_cc.h10
-rw-r--r--gr-analog/include/gnuradio/analog/pwr_squelch_ff.h10
-rw-r--r--gr-analog/lib/squelch_base_cc_impl.cc101
-rw-r--r--gr-analog/lib/squelch_base_cc_impl.h2
-rw-r--r--gr-analog/lib/squelch_base_ff_impl.cc105
-rw-r--r--gr-analog/lib/squelch_base_ff_impl.h3
-rw-r--r--gr-blocks/examples/CMakeLists.txt1
-rw-r--r--gr-blocks/examples/peak_detector2.grc1045
-rw-r--r--gr-blocks/grc/blocks_peak_detector2_fb.xml5
-rw-r--r--gr-blocks/lib/ctrlport_probe2_b_impl.cc30
-rw-r--r--gr-blocks/lib/ctrlport_probe2_b_impl.h2
-rw-r--r--gr-blocks/lib/ctrlport_probe2_c_impl.cc30
-rw-r--r--gr-blocks/lib/ctrlport_probe2_c_impl.h1
-rw-r--r--gr-blocks/lib/ctrlport_probe2_f_impl.cc31
-rw-r--r--gr-blocks/lib/ctrlport_probe2_f_impl.h1
-rw-r--r--gr-blocks/lib/ctrlport_probe2_i_impl.cc31
-rw-r--r--gr-blocks/lib/ctrlport_probe2_i_impl.h1
-rw-r--r--gr-blocks/lib/ctrlport_probe2_s_impl.cc27
-rw-r--r--gr-blocks/lib/ctrlport_probe2_s_impl.h1
-rw-r--r--gr-blocks/lib/peak_detector2_fb_impl.cc103
-rw-r--r--gr-blocks/lib/peak_detector2_fb_impl.h10
-rw-r--r--gr-blocks/python/blocks/qa_peak_detector2.py87
-rw-r--r--gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t10
-rw-r--r--gr-digital/lib/burst_shaper_XX_impl.cc.t88
-rw-r--r--gr-digital/lib/burst_shaper_XX_impl.h.t4
-rwxr-xr-xgr-digital/python/digital/qa_burst_shaper.py102
-rw-r--r--gr-qtgui/grc/qtgui_range.xml209
-rwxr-xr-xgr-qtgui/python/qtgui/range.py67
-rwxr-xr-xgrc/scripts/gnuradio-companion9
33 files changed, 1910 insertions, 426 deletions
diff --git a/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx b/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx
index 23e11d4174..cebc00dcf4 100644
--- a/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx
+++ b/gnuradio-runtime/python/gnuradio/ctrlport/gr-perf-monitorx
@@ -254,18 +254,23 @@ class DataTable(QtGui.QWidget):
def update(self):
print "update"
+ def closeEvent(self, event):
+ self.timer = None
+
def __init__(self, radioclient, G):
QtGui.QWidget.__init__( self)
- self.layout = QtGui.QVBoxLayout(self);
- self.hlayout = QtGui.QHBoxLayout();
- self.layout.addLayout(self.hlayout);
+ self.layout = QtGui.QVBoxLayout(self)
+ self.hlayout = QtGui.QHBoxLayout()
+ self.layout.addLayout(self.hlayout)
- self.G = G;
- self.radioclient = radioclient;
+ self.G = G
+ self.radioclient = radioclient
self._keymap = None
+ self.disp = None
+
# Create a combobox to set the type of statistic we want.
self._statistic = "Instantaneous"
self._statistics_table = {"Instantaneous": "",
@@ -276,7 +281,7 @@ class DataTable(QtGui.QWidget):
self.stattype.addItem("Average")
self.stattype.addItem("Variance")
self.stattype.setMaximumWidth(200)
- self.hlayout.addWidget(self.stattype);
+ self.hlayout.addWidget(self.stattype)
self.stattype.currentIndexChanged.connect(self.stat_changed)
# Create a checkbox to toggle sorting of graphs
@@ -287,18 +292,18 @@ class DataTable(QtGui.QWidget):
self.checksort.stateChanged.connect(self.checksort_changed)
# set up table
- self.perfTable = Qt.QTableWidget();
+ self.perfTable = Qt.QTableWidget()
self.perfTable.setColumnCount(2)
- self.perfTable.verticalHeader().hide();
- self.perfTable.setHorizontalHeaderLabels( ["Block Name", "Percent Runtime"] );
- self.perfTable.horizontalHeader().setStretchLastSection(True);
+ self.perfTable.verticalHeader().hide()
+ self.perfTable.setHorizontalHeaderLabels( ["Block Name", "Percent Runtime"] )
+ self.perfTable.horizontalHeader().setStretchLastSection(True)
self.perfTable.setSortingEnabled(True)
nodes = self.G.nodes(data=True)
# set up plot
self.f = plt.figure(figsize=(10,8), dpi=90)
- self.sp = self.f.add_subplot(111);
- self.sp.autoscale_view(True,True,True);
+ self.sp = self.f.add_subplot(111)
+ self.sp.autoscale_view(True,True,True)
self.sp.set_autoscale_on(True)
self.canvas = FigureCanvas(self.f)
@@ -339,63 +344,71 @@ class DataTable(QtGui.QWidget):
class DataTableBuffers(DataTable):
def __init__(self, radioclient, G):
super(DataTableBuffers, self).__init__(radioclient, G)
- self.perfTable.setHorizontalHeaderLabels( ["Block Name", "Percent Buffer Full"] );
+ self.perfTable.setHorizontalHeaderLabels( ["Block Name", "Percent Buffer Full"] )
def update(self):
nodes = self.G.nodes();
# get buffer fullness for all blocks
kl = map(lambda x: "%s::%soutput %% full" % \
- (x, self._statistics_table[self._statistic]),
+ (x, self._statistics_table[self._statistic]),
nodes);
buf_knobs = self.radioclient.getKnobs(kl)
# strip values out of ctrlport response
buffer_fullness = dict(zip(
- map(lambda x: x.split("::")[0], buf_knobs.keys()),
- map(lambda x: x.value, buf_knobs.values())))
+ map(lambda x: x.split("::")[0], buf_knobs.keys()),
+ map(lambda x: x.value, buf_knobs.values())))
blockport_fullness = {}
for blk in buffer_fullness:
bdata = buffer_fullness[blk]
if bdata:
for port in range(0,len(bdata)):
- blockport_fullness["%s:%d"%(blk,port)] = bdata[port];
+ blockport_fullness["%s:%d"%(blk,port)] = bdata[port]
- self.table_update(blockport_fullness);
+ if(self.perfTable.isVisible()):
+ self.table_update(blockport_fullness);
- if(self._sort):
- sorted_fullness = sorted(blockport_fullness.iteritems(), key=operator.itemgetter(1))
- self._keymap = map(operator.itemgetter(0), sorted_fullness)
else:
- if self._keymap:
- sorted_fullness = len(self._keymap)*['',]
- for b in blockport_fullness:
- sorted_fullness[self._keymap.index(b)] = (b, blockport_fullness[b])
+ if(self._sort):
+ sorted_fullness = sorted(blockport_fullness.iteritems(),
+ key=operator.itemgetter(1))
+ self._keymap = map(operator.itemgetter(0), sorted_fullness)
+ else:
+ if self._keymap:
+ sorted_fullness = len(self._keymap)*['',]
+ for b in blockport_fullness:
+ sorted_fullness[self._keymap.index(b)] = (b, blockport_fullness[b])
+ else:
+ sorted_fullness = blockport_fullness.items()
+
+ if(not self.disp):
+ self.disp = self.sp.bar(range(0,len(sorted_fullness)),
+ map(lambda x: x[1], sorted_fullness),
+ alpha=0.5)
+ self.sp.set_ylabel("% Buffers Full");
+ self.sp.set_xticks( map(lambda x: x+0.5, range(0,len(sorted_fullness))))
+ self.sp.set_xticklabels(map(lambda x: " " + x, map(lambda x: x[0], sorted_fullness)),
+ rotation="vertical", verticalalignment="bottom")
else:
- sorted_fullness = blockport_fullness.items()
+ self.sp.set_xticklabels(map(lambda x: " " + x, map(lambda x: x[0], sorted_fullness)),
+ rotation="vertical", verticalalignment="bottom")
+ for r,w in zip(self.disp, sorted_fullness):
+ r.set_height(w[1])
- self.sp.clear();
- self.sp.bar(range(0,len(sorted_fullness)), map(lambda x: x[1], sorted_fullness),
- alpha=0.5)
- self.sp.set_ylabel("% Buffers Full");
- self.sp.set_xticks( map(lambda x: x+0.5, range(0,len(sorted_fullness))))
- self.sp.set_xticklabels( map(lambda x: " " + x, map(lambda x: x[0], sorted_fullness)),
- rotation="vertical", verticalalignment="bottom" )
- self.canvas.draw()
- self.canvas.show()
+ self.canvas.draw()
class DataTableRuntimes(DataTable):
def __init__(self, radioclient, G):
super(DataTableRuntimes, self).__init__( radioclient, G)
- #self.perfTable.setRowCount(len( self.G.nodes() ))
def update(self):
nodes = self.G.nodes();
# get work time for all blocks
kl = map(lambda x: "%s::%swork time" % \
- (x, self._statistics_table[self._statistic]),
+ (x, self._statistics_table[self._statistic]),
nodes);
wrk_knobs = self.radioclient.getKnobs(kl)
@@ -408,31 +421,37 @@ class DataTableRuntimes(DataTable):
map(lambda x: x.value/total_work, wrk_knobs.values())))
# update table view
- self.table_update(work_times)
+ if(self.perfTable.isVisible()):
+ self.table_update(work_times)
- if(self._sort):
- sorted_work = sorted(work_times.iteritems(), key=operator.itemgetter(1))
- self._keymap = map(operator.itemgetter(0), sorted_work)
else:
- if self._keymap:
- sorted_work = len(self._keymap)*['',]
- for b in work_times:
- sorted_work[self._keymap.index(b)] = (b, work_times[b])
+ if(self._sort):
+ sorted_work = sorted(work_times.iteritems(), key=operator.itemgetter(1))
+ self._keymap = map(operator.itemgetter(0), sorted_work)
else:
- sorted_work = work_times.items()
-
- self.sp.clear();
- plt.figure(self.f.number)
- plt.subplot(111);
- self.sp.bar(range(0,len(sorted_work)), map(lambda x: x[1], sorted_work),
- alpha=0.5)
- self.sp.set_ylabel("% Runtime");
- self.sp.set_xticks( map(lambda x: x+0.5, range(0,len(sorted_work))))
- self.sp.set_xticklabels( map(lambda x: " " + x[0], sorted_work),
- rotation="vertical", verticalalignment="bottom" )
+ if self._keymap:
+ sorted_work = len(self._keymap)*['',]
+ for b in work_times:
+ sorted_work[self._keymap.index(b)] = (b, work_times[b])
+ else:
+ sorted_work = work_times.items()
+
+ f = plt.figure(self.f.number)
+ if(not self.disp):
+ self.disp = self.sp.bar(range(0,len(sorted_work)),
+ map(lambda x: x[1], sorted_work),
+ alpha=0.5)
+ self.sp.set_ylabel("% Runtime");
+ self.sp.set_xticks( map(lambda x: x+0.5, range(0,len(sorted_work))))
+ self.sp.set_xticklabels( map(lambda x: " " + x[0], sorted_work),
+ rotation="vertical", verticalalignment="bottom" )
+ else:
+ self.sp.set_xticklabels( map(lambda x: " " + x[0], sorted_work),
+ rotation="vertical", verticalalignment="bottom" )
+ for r,w in zip(self.disp, sorted_work):
+ r.set_height(w[1])
- self.canvas.draw();
- self.canvas.show();
+ self.canvas.draw()
class MForm(QtGui.QWidget):
def update(self):
@@ -835,10 +854,10 @@ class MForm(QtGui.QWidget):
class MyApp(object):
def __init__(self, args):
p = gr.prefs()
- cp_on = p.get_bool("ControlPort", "on", None)
- cp_edges = p.get_bool("ControlPort", "edges_list", None)
- pcs_on = p.get_bool("PerfCounters", "on", None)
- pcs_exported = p.get_bool("PerfCounters", "export", None)
+ cp_on = p.get_bool("ControlPort", "on", False)
+ cp_edges = p.get_bool("ControlPort", "edges_list", False)
+ pcs_on = p.get_bool("PerfCounters", "on", False)
+ pcs_exported = p.get_bool("PerfCounters", "export", False)
if(not (pcs_on and cp_on and pcs_exported and cp_edges)):
print("Configuration has not turned on all of the appropriate ControlPort features:")
print("\t[ControlPort] on = {0}".format(cp_on))
diff --git a/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py b/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py
index 1a08ac5ae6..55b62a12ac 100755
--- a/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py
+++ b/gnuradio-runtime/python/gnuradio/gr/qa_tag_utils.py
@@ -76,6 +76,38 @@ class test_tag_utils (gr_unittest.TestCase):
self.assertTrue(pmt.equal(t_tuple.value, value))
self.assertEqual(t_tuple.offset, offset)
+ def test_003(self):
+ offsets = (6, 3, 8)
+ key = pmt.string_to_symbol('key')
+ srcid = pmt.string_to_symbol('qa_tag_utils')
+ tags = []
+
+ for k in offsets:
+ t = gr.tag_t()
+ t.offset = k
+ t.key = key
+ t.value = pmt.from_long(k)
+ t.srcid = srcid
+ tags.append(t)
+
+ for k, t in zip(sorted(offsets),
+ sorted(tags, key=gr.tag_t_offset_compare_key())):
+ self.assertEqual(t.offset, k)
+ self.assertTrue(pmt.equal(t.key, key))
+ self.assertTrue(pmt.equal(t.value, pmt.from_long(k)))
+ self.assertTrue(pmt.equal(t.srcid, srcid))
+
+ tmin = min(tags, key=gr.tag_t_offset_compare_key())
+ self.assertEqual(tmin.offset, min(offsets))
+ self.assertTrue(pmt.equal(tmin.key, key))
+ self.assertTrue(pmt.equal(tmin.value, pmt.from_long(min(offsets))))
+ self.assertTrue(pmt.equal(tmin.srcid, srcid))
+
+ tmax = max(tags, key=gr.tag_t_offset_compare_key())
+ self.assertEqual(tmax.offset, max(offsets))
+ self.assertTrue(pmt.equal(tmax.key, key))
+ self.assertTrue(pmt.equal(tmax.value, pmt.from_long(max(offsets))))
+ self.assertTrue(pmt.equal(tmax.srcid, srcid))
if __name__ == '__main__':
diff --git a/gnuradio-runtime/python/gnuradio/gr/tag_utils.py b/gnuradio-runtime/python/gnuradio/gr/tag_utils.py
index dc36e05250..a7745428c7 100644
--- a/gnuradio-runtime/python/gnuradio/gr/tag_utils.py
+++ b/gnuradio-runtime/python/gnuradio/gr/tag_utils.py
@@ -108,3 +108,36 @@ def python_to_tag(tag_struct):
return tag
else:
return None
+
+def tag_t_offset_compare_key():
+ """
+ Convert a tag_t_offset_compare function into a key=function
+ This method is modeled after functools.cmp_to_key(_func_).
+ It can be used by functions that accept a key function, such as
+ sorted(), min(), max(), etc. to compare tags by their offsets,
+ e.g., sorted(tag_list, key=gr.tag_t_offset_compare_key()).
+ """
+ class K(object):
+ def __init__(self, obj, *args):
+ self.obj = obj
+ def __lt__(self, other):
+ # x.offset < y.offset
+ return gr.tag_t_offset_compare(self.obj, other.obj)
+ def __gt__(self, other):
+ # y.offset < x.offset
+ return gr.tag_t_offset_compare(other.obj, self.obj)
+ def __eq__(self, other):
+ # not (x.offset < y.offset) and not (y.offset < x.offset)
+ return not gr.tag_t_offset_compare(self.obj, other.obj) and \
+ not gr.tag_t_offset_compare(other.obj, self.obj)
+ def __le__(self, other):
+ # not (y.offset < x.offset)
+ return not gr.tag_t_offset_compare(other.obj, self.obj)
+ def __ge__(self, other):
+ # not (x.offset < y.offset)
+ return not gr.tag_t_offset_compare(self.obj, other.obj)
+ def __ne__(self, other):
+ # (x.offset < y.offset) or (y.offset < x.offset)
+ return gr.tag_t_offset_compare(self.obj, other.obj) or \
+ gr.tag_t_offset_compare(other.obj, self.obj)
+ return K
diff --git a/gr-analog/grc/analog_pwr_squelch_xx.xml b/gr-analog/grc/analog_pwr_squelch_xx.xml
index 32d9c0e947..a75f85cf10 100644
--- a/gr-analog/grc/analog_pwr_squelch_xx.xml
+++ b/gr-analog/grc/analog_pwr_squelch_xx.xml
@@ -34,11 +34,13 @@
<param>
<name>Alpha</name>
<key>alpha</key>
+ <value>1e-4</value>
<type>real</type>
</param>
<param>
<name>Ramp</name>
<key>ramp</key>
+ <value>0</value>
<type>int</type>
</param>
<param>
diff --git a/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h b/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h
index 6913d62934..324743d965 100644
--- a/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h
+++ b/gr-analog/include/gnuradio/analog/pwr_squelch_cc.h
@@ -49,10 +49,14 @@ namespace gr {
* \brief Make power-based squelch block.
*
* \param db threshold (in dB) for power squelch
- * \param alpha Gain of averaging filter
- * \param ramp sets response characteristic.
+ * \param alpha Gain of averaging filter. Defaults to 0.0001.
+ * \param ramp sets response characteristic. Defaults to 0.
* \param gate if true, no output if no squelch tone.
- * if false, output 0's if no squelch tone.
+ * if false, output 0's if no squelch tone (default).
+ *
+ * The block will emit a tag with the key pmt::intern("squelch_sob")
+ * with the value of pmt::PMT_NIL on the first item it passes, and with
+ * the key pmt::intern("squelch:eob") on the last item it passes.
*/
static sptr make(double db, double alpha=0.0001,
int ramp=0, bool gate=false);
diff --git a/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h b/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h
index 46046eae07..a65cedaa57 100644
--- a/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h
+++ b/gr-analog/include/gnuradio/analog/pwr_squelch_ff.h
@@ -49,10 +49,14 @@ namespace gr {
* \brief Make power-based squelch block.
*
* \param db threshold (in dB) for power squelch
- * \param alpha Gain of averaging filter
- * \param ramp sets response characteristic.
+ * \param alpha Gain of averaging filter. Defaults to 0.0001.
+ * \param ramp sets response characteristic. Defaults to 0.
* \param gate if true, no output if no squelch tone.
- * if false, output 0's if no squelch tone.
+ * if false, output 0's if no squelch tone (default).
+ *
+ * The block will emit a tag with the key pmt::intern("squelch_sob")
+ * with the value of pmt::PMT_NIL on the first item it passes, and with
+ * the key pmt::intern("squelch:eob") on the last item it passes.
*/
static sptr make(double db, double alpha=0.0001,
int ramp=0, bool gate=false);
diff --git a/gr-analog/lib/squelch_base_cc_impl.cc b/gr-analog/lib/squelch_base_cc_impl.cc
index 3255d3bde4..b5c153558b 100644
--- a/gr-analog/lib/squelch_base_cc_impl.cc
+++ b/gr-analog/lib/squelch_base_cc_impl.cc
@@ -32,8 +32,11 @@ namespace gr {
squelch_base_cc_impl::squelch_base_cc_impl(const char *name, int ramp, bool gate)
: block(name,
- io_signature::make(1, 1, sizeof(float)),
- io_signature::make(1, 1, sizeof(float)))
+ io_signature::make(1, 1, sizeof(float)),
+ io_signature::make(1, 1, sizeof(float))),
+ d_sob_key(pmt::intern("squelch_sob")),
+ d_eob_key(pmt::intern("squelch_eob")),
+ d_tag_next_unmuted(true)
{
set_ramp(ramp);
set_gate(gate);
@@ -92,48 +95,58 @@ namespace gr {
gr::thread::scoped_lock l(d_setlock);
for(int i = 0; i < noutput_items; i++) {
- update_state(in[i]);
-
- // Adjust envelope based on current state
- switch(d_state) {
- case ST_MUTED:
- if(!mute()) {
- d_state = d_ramp ? ST_ATTACK : ST_UNMUTED; // If not ramping, go straight to unmuted
- }
- break;
-
- case ST_UNMUTED:
- if(mute()) {
- d_state = d_ramp ? ST_DECAY : ST_MUTED; // If not ramping, go straight to muted
- }
- break;
-
- case ST_ATTACK:
- d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed
- if(d_ramped >= d_ramp) { // use >= in case d_ramp is set to lower value elsewhere
- d_state = ST_UNMUTED;
- d_envelope = 1.0;
- }
- break;
-
- case ST_DECAY:
- d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed
- if(d_ramped == 0.0) {
- d_state = ST_MUTED;
- }
- break;
- };
-
- // If unmuted, copy input times envelope to output
- // Otherwise, if not gating, copy zero to output
- if(d_state != ST_MUTED) {
- out[j++] = in[i]*gr_complex(d_envelope, 0.0);
- }
- else {
- if(!d_gate) {
- out[j++] = 0.0;
- }
- }
+ update_state(in[i]);
+
+ // Adjust envelope based on current state
+ switch(d_state) {
+ case ST_MUTED:
+ if(!mute()) {
+ d_state = d_ramp ? ST_ATTACK : ST_UNMUTED; // If not ramping, go straight to unmuted
+ if(d_state == ST_UNMUTED)
+ d_tag_next_unmuted = true;
+ }
+ break;
+
+ case ST_UNMUTED:
+ if(d_tag_next_unmuted) {
+ d_tag_next_unmuted = false;
+ add_item_tag(0, nitems_written(0) + j, d_sob_key, pmt::PMT_NIL);
+ }
+ if(mute()) {
+ d_state = d_ramp ? ST_DECAY : ST_MUTED; // If not ramping, go straight to muted
+ if(d_state == ST_MUTED)
+ add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL);
+ }
+ break;
+
+ case ST_ATTACK:
+ d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed
+ if(d_ramped >= d_ramp) { // use >= in case d_ramp is set to lower value elsewhere
+ d_state = ST_UNMUTED;
+ d_tag_next_unmuted = true;
+ d_envelope = 1.0;
+ }
+ break;
+
+ case ST_DECAY:
+ d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0; // FIXME: precalculate window for speed
+ if(d_ramped == 0.0) {
+ d_state = ST_MUTED;
+ add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL);
+ }
+ break;
+ };
+
+ // If unmuted, copy input times envelope to output
+ // Otherwise, if not gating, copy zero to output
+ if(d_state != ST_MUTED) {
+ out[j++] = in[i]*gr_complex(d_envelope, 0.0);
+ }
+ else {
+ if(!d_gate) {
+ out[j++] = 0.0;
+ }
+ }
}
consume_each(noutput_items); // Use all the inputs
diff --git a/gr-analog/lib/squelch_base_cc_impl.h b/gr-analog/lib/squelch_base_cc_impl.h
index 58802df91c..68ed1bb2b8 100644
--- a/gr-analog/lib/squelch_base_cc_impl.h
+++ b/gr-analog/lib/squelch_base_cc_impl.h
@@ -36,6 +36,8 @@ namespace gr {
bool d_gate;
double d_envelope;
enum { ST_MUTED, ST_ATTACK, ST_UNMUTED, ST_DECAY } d_state;
+ const pmt::pmt_t d_sob_key, d_eob_key;
+ bool d_tag_next_unmuted;
protected:
virtual void update_state(const gr_complex &sample) {};
diff --git a/gr-analog/lib/squelch_base_ff_impl.cc b/gr-analog/lib/squelch_base_ff_impl.cc
index a729fedb24..ea2d29bd97 100644
--- a/gr-analog/lib/squelch_base_ff_impl.cc
+++ b/gr-analog/lib/squelch_base_ff_impl.cc
@@ -26,14 +26,18 @@
#include "squelch_base_ff_impl.h"
#include <gnuradio/io_signature.h>
+#include <pmt/pmt.h>
namespace gr {
namespace analog {
squelch_base_ff_impl::squelch_base_ff_impl(const char *name, int ramp, bool gate)
: block(name,
- io_signature::make(1, 1, sizeof(float)),
- io_signature::make(1, 1, sizeof(float)))
+ io_signature::make(1, 1, sizeof(float)),
+ io_signature::make(1, 1, sizeof(float))),
+ d_sob_key(pmt::intern("squelch_sob")),
+ d_eob_key(pmt::intern("squelch_eob")),
+ d_tag_next_unmuted(true)
{
set_ramp(ramp);
set_gate(gate);
@@ -88,48 +92,61 @@ namespace gr {
int j = 0;
for(int i = 0; i < noutput_items; i++) {
- update_state(in[i]);
-
- // Adjust envelope based on current state
- switch(d_state) {
- case ST_MUTED:
- if(!mute())
- // If not ramping, go straight to unmuted
- d_state = d_ramp ? ST_ATTACK : ST_UNMUTED;
- break;
-
- case ST_UNMUTED:
- if(mute())
- // If not ramping, go straight to muted
- d_state = d_ramp ? ST_DECAY : ST_MUTED;
- break;
-
- case ST_ATTACK:
- // FIXME: precalculate window for speed
- d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0;
-
- // use >= in case d_ramp is set to lower value elsewhere
- if(d_ramped >= d_ramp) {
- d_state = ST_UNMUTED;
- d_envelope = 1.0;
- }
- break;
-
- case ST_DECAY:
- // FIXME: precalculate window for speed
- d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0;
- if(d_ramped == 0.0)
- d_state = ST_MUTED;
- break;
- };
-
- // If unmuted, copy input times envelope to output
- // Otherwise, if not gating, copy zero to output
- if(d_state != ST_MUTED)
- out[j++] = in[i]*d_envelope;
- else
- if(!d_gate)
- out[j++] = 0.0;
+ update_state(in[i]);
+
+ // Adjust envelope based on current state
+ switch(d_state) {
+ case ST_MUTED:
+ if(!mute()) {
+ // If not ramping, go straight to unmuted
+ d_state = d_ramp ? ST_ATTACK : ST_UNMUTED;
+ if(d_state == ST_UNMUTED)
+ d_tag_next_unmuted = true;
+ }
+ break;
+
+ case ST_UNMUTED:
+ if(d_tag_next_unmuted) {
+ d_tag_next_unmuted = false;
+ add_item_tag(0, nitems_written(0) + j, d_sob_key, pmt::PMT_NIL);
+ }
+ if(mute()) {
+ // If not ramping, go straight to muted
+ d_state = d_ramp ? ST_DECAY : ST_MUTED;
+ if(d_state == ST_MUTED)
+ add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL);
+ }
+ break;
+
+ case ST_ATTACK:
+ // FIXME: precalculate window for speed
+ d_envelope = 0.5-std::cos(M_PI*(++d_ramped)/d_ramp)/2.0;
+
+ // use >= in case d_ramp is set to lower value elsewhere
+ if(d_ramped >= d_ramp) {
+ d_state = ST_UNMUTED;
+ d_tag_next_unmuted = true;
+ d_envelope = 1.0;
+ }
+ break;
+
+ case ST_DECAY:
+ // FIXME: precalculate window for speed
+ d_envelope = 0.5-std::cos(M_PI*(--d_ramped)/d_ramp)/2.0;
+ if(d_ramped == 0.0) {
+ d_state = ST_MUTED;
+ add_item_tag(0, nitems_written(0) + j, d_eob_key, pmt::PMT_NIL);
+ }
+ break;
+ };
+
+ // If unmuted, copy input times envelope to output
+ // Otherwise, if not gating, copy zero to output
+ if(d_state != ST_MUTED)
+ out[j++] = in[i]*d_envelope;
+ else
+ if(!d_gate)
+ out[j++] = 0.0;
}
consume_each(noutput_items); // Use all the inputs
diff --git a/gr-analog/lib/squelch_base_ff_impl.h b/gr-analog/lib/squelch_base_ff_impl.h
index 343dc5f610..b6a7efe609 100644
--- a/gr-analog/lib/squelch_base_ff_impl.h
+++ b/gr-analog/lib/squelch_base_ff_impl.h
@@ -24,6 +24,7 @@
#define INCLUDED_GR_SQUELCH_BASE_FF_IMPL_H
#include <gnuradio/analog/squelch_base_ff.h>
+#include <pmt/pmt.h>
namespace gr {
namespace analog {
@@ -36,6 +37,8 @@ namespace gr {
bool d_gate;
double d_envelope;
enum { ST_MUTED, ST_ATTACK, ST_UNMUTED, ST_DECAY } d_state;
+ const pmt::pmt_t d_sob_key, d_eob_key;
+ bool d_tag_next_unmuted;
protected:
virtual void update_state(const float &sample) {};
diff --git a/gr-blocks/examples/CMakeLists.txt b/gr-blocks/examples/CMakeLists.txt
index bb07cdc2b5..0ecf9d7a91 100644
--- a/gr-blocks/examples/CMakeLists.txt
+++ b/gr-blocks/examples/CMakeLists.txt
@@ -20,6 +20,7 @@
install(
FILES
matrix_multiplexer.grc
+ peak_detector2.grc
vector_source_with_tags.grc
DESTINATION ${GR_PKG_DATA_DIR}/examples/blocks
COMPONENT "runtime_python"
diff --git a/gr-blocks/examples/peak_detector2.grc b/gr-blocks/examples/peak_detector2.grc
new file mode 100644
index 0000000000..c49febdce4
--- /dev/null
+++ b/gr-blocks/examples/peak_detector2.grc
@@ -0,0 +1,1045 @@
+<?xml version='1.0' encoding='ASCII'?>
+<?grc format='1' created='3.7.8'?>
+<flow_graph>
+ <timestamp>Wed Apr 8 18:17:58 2015</timestamp>
+ <block>
+ <key>options</key>
+ <param>
+ <key>id</key>
+ <value>test_peak2</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>title</key>
+ <value></value>
+ </param>
+ <param>
+ <key>author</key>
+ <value></value>
+ </param>
+ <param>
+ <key>description</key>
+ <value></value>
+ </param>
+ <param>
+ <key>window_size</key>
+ <value>1280, 1024</value>
+ </param>
+ <param>
+ <key>generate_options</key>
+ <value>qt_gui</value>
+ </param>
+ <param>
+ <key>category</key>
+ <value>Custom</value>
+ </param>
+ <param>
+ <key>run_options</key>
+ <value>run</value>
+ </param>
+ <param>
+ <key>run</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>max_nouts</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>realtime_scheduling</key>
+ <value></value>
+ </param>
+ <param>
+ <key>thread_safe_setters</key>
+ <value></value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(16, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>factor</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0.3</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(264, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>alpha</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0.001</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(440, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>lookahead</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>int(samp_rate/1e3/1.1)</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(352, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable</key>
+ <param>
+ <key>id</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>100e3</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(176, 11)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>qtgui_time_sink_x</key>
+ <param>
+ <key>id</key>
+ <value>qtgui_time_sink_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>name</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>ylabel</key>
+ <value>Amplitude</value>
+ </param>
+ <param>
+ <key>yunit</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>size</key>
+ <value>512</value>
+ </param>
+ <param>
+ <key>srate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>grid</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>autoscale</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>ymin</key>
+ <value>-1.5</value>
+ </param>
+ <param>
+ <key>ymax</key>
+ <value>1.5</value>
+ </param>
+ <param>
+ <key>nconnections</key>
+ <value>3</value>
+ </param>
+ <param>
+ <key>update_time</key>
+ <value>0.10</value>
+ </param>
+ <param>
+ <key>entags</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value></value>
+ </param>
+ <param>
+ <key>tr_mode</key>
+ <value>qtgui.TRIG_MODE_AUTO</value>
+ </param>
+ <param>
+ <key>tr_slope</key>
+ <value>qtgui.TRIG_SLOPE_POS</value>
+ </param>
+ <param>
+ <key>tr_level</key>
+ <value>0.0</value>
+ </param>
+ <param>
+ <key>tr_delay</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_chan</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>tr_tag</key>
+ <value>""</value>
+ </param>
+ <param>
+ <key>ctrlpanel</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>legend</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label1</key>
+ <value>Input</value>
+ </param>
+ <param>
+ <key>width1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color1</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>style1</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker1</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha1</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label2</key>
+ <value>Peaks</value>
+ </param>
+ <param>
+ <key>width2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color2</key>
+ <value>"red"</value>
+ </param>
+ <param>
+ <key>style2</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker2</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha2</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label3</key>
+ <value>Average</value>
+ </param>
+ <param>
+ <key>width3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color3</key>
+ <value>"green"</value>
+ </param>
+ <param>
+ <key>style3</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker3</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha3</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label4</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color4</key>
+ <value>"black"</value>
+ </param>
+ <param>
+ <key>style4</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker4</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha4</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label5</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color5</key>
+ <value>"cyan"</value>
+ </param>
+ <param>
+ <key>style5</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker5</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha5</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label6</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color6</key>
+ <value>"magenta"</value>
+ </param>
+ <param>
+ <key>style6</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker6</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha6</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label7</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color7</key>
+ <value>"yellow"</value>
+ </param>
+ <param>
+ <key>style7</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker7</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha7</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label8</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color8</key>
+ <value>"dark red"</value>
+ </param>
+ <param>
+ <key>style8</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker8</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha8</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label9</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color9</key>
+ <value>"dark green"</value>
+ </param>
+ <param>
+ <key>style9</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker9</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha9</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>label10</key>
+ <value></value>
+ </param>
+ <param>
+ <key>width10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>color10</key>
+ <value>"blue"</value>
+ </param>
+ <param>
+ <key>style10</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>marker10</key>
+ <value>-1</value>
+ </param>
+ <param>
+ <key>alpha10</key>
+ <value>1.0</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(808, 152)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_char_to_float</key>
+ <param>
+ <key>id</key>
+ <value>blocks_char_to_float_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>scale</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(624, 83)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_peak_detector2_fb</key>
+ <param>
+ <key>id</key>
+ <value>blocks_peak_detector2_fb_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>threshold_factor_rise</key>
+ <value>factor</value>
+ </param>
+ <param>
+ <key>look_ahead</key>
+ <value>lookahead</value>
+ </param>
+ <param>
+ <key>alpha</key>
+ <value>alpha</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(408, 83)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_sink</key>
+ <param>
+ <key>id</key>
+ <value>blocks_file_sink_0_1</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>flag.data</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>unbuffered</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>append</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(808, 51)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_sink</key>
+ <param>
+ <key>id</key>
+ <value>blocks_file_sink_0_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>avg.data</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>unbuffered</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>append</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(784, 259)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>blocks_file_sink</key>
+ <param>
+ <key>id</key>
+ <value>blocks_file_sink_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>file</key>
+ <value>in.data</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>unbuffered</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>append</key>
+ <value>False</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(408, 187)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>variable_qtgui_range</key>
+ <param>
+ <key>id</key>
+ <value>offset</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>label</key>
+ <value></value>
+ </param>
+ <param>
+ <key>value</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>start</key>
+ <value>-1.5</value>
+ </param>
+ <param>
+ <key>stop</key>
+ <value>1.5</value>
+ </param>
+ <param>
+ <key>step</key>
+ <value>0.1</value>
+ </param>
+ <param>
+ <key>widget</key>
+ <value>counter_slider</value>
+ </param>
+ <param>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ </param>
+ <param>
+ <key>min_len</key>
+ <value>200</value>
+ </param>
+ <param>
+ <key>gui_hint</key>
+ <value></value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(16, 235)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <block>
+ <key>analog_sig_source_x</key>
+ <param>
+ <key>id</key>
+ <value>analog_sig_source_x_0</value>
+ </param>
+ <param>
+ <key>_enabled</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>type</key>
+ <value>float</value>
+ </param>
+ <param>
+ <key>samp_rate</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>waveform</key>
+ <value>analog.GR_SAW_WAVE</value>
+ </param>
+ <param>
+ <key>freq</key>
+ <value>1000</value>
+ </param>
+ <param>
+ <key>amp</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>offset</key>
+ <value>offset</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(16, 115)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <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>float</value>
+ </param>
+ <param>
+ <key>samples_per_second</key>
+ <value>samp_rate</value>
+ </param>
+ <param>
+ <key>vlen</key>
+ <value>1</value>
+ </param>
+ <param>
+ <key>ignoretag</key>
+ <value>True</value>
+ </param>
+ <param>
+ <key>alias</key>
+ <value></value>
+ </param>
+ <param>
+ <key>affinity</key>
+ <value></value>
+ </param>
+ <param>
+ <key>minoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>maxoutbuf</key>
+ <value>0</value>
+ </param>
+ <param>
+ <key>comment</key>
+ <value></value>
+ </param>
+ <param>
+ <key>_coordinate</key>
+ <value>(224, 147)</value>
+ </param>
+ <param>
+ <key>_rotation</key>
+ <value>0</value>
+ </param>
+ </block>
+ <connection>
+ <source_block_id>blocks_char_to_float_0</source_block_id>
+ <sink_block_id>blocks_file_sink_0_1</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_peak_detector2_fb_0</source_block_id>
+ <sink_block_id>blocks_file_sink_0_0</sink_block_id>
+ <source_key>1</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_char_to_float_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>1</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_peak_detector2_fb_0</source_block_id>
+ <sink_block_id>qtgui_time_sink_x_0</sink_block_id>
+ <source_key>1</source_key>
+ <sink_key>2</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>blocks_peak_detector2_fb_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_peak_detector2_fb_0</source_block_id>
+ <sink_block_id>blocks_char_to_float_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>blocks_throttle_0</source_block_id>
+ <sink_block_id>blocks_file_sink_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+ <connection>
+ <source_block_id>analog_sig_source_x_0</source_block_id>
+ <sink_block_id>blocks_throttle_0</sink_block_id>
+ <source_key>0</source_key>
+ <sink_key>0</sink_key>
+ </connection>
+</flow_graph>
diff --git a/gr-blocks/grc/blocks_peak_detector2_fb.xml b/gr-blocks/grc/blocks_peak_detector2_fb.xml
index 584e7a1fb3..0b25e01680 100644
--- a/gr-blocks/grc/blocks_peak_detector2_fb.xml
+++ b/gr-blocks/grc/blocks_peak_detector2_fb.xml
@@ -38,4 +38,9 @@
<name>out</name>
<type>byte</type>
</source>
+ <source>
+ <name>debug</name>
+ <type>float</type>
+ <optional>1</optional>
+ </source>
</block>
diff --git a/gr-blocks/lib/ctrlport_probe2_b_impl.cc b/gr-blocks/lib/ctrlport_probe2_b_impl.cc
index 3cf2ae0167..996e997d96 100644
--- a/gr-blocks/lib/ctrlport_probe2_b_impl.cc
+++ b/gr-blocks/lib/ctrlport_probe2_b_impl.cc
@@ -64,21 +64,26 @@ namespace gr {
}
std::vector<signed char>
- ctrlport_probe2_b_impl::get() {
+ ctrlport_probe2_b_impl::get()
+ {
return buffered_get.get();
}
void
ctrlport_probe2_b_impl::set_length(int len)
{
+ gr::thread::scoped_lock guard(d_setlock);
+
if(len > 8191) {
- std::cerr << "probe2_b: length " << len
- << " exceeds maximum buffer size of 8191" << std::endl;
+ GR_LOG_WARN(d_logger,
+ boost::format("probe2_b: length %1% exceeds maximum"
+ " buffer size of 8191") % len);
len = 8191;
}
d_len = len;
- d_buffer.reserve(d_len);
+ d_buffer.resize(d_len);
+ d_index = 0;
}
int
@@ -94,20 +99,21 @@ namespace gr {
{
const char *in = (const char*)input_items[0];
+ gr::thread::scoped_lock guard(d_setlock);
+
// copy samples to get buffer if we need samples
- if(d_buffer.size() < d_len) {
+ if(d_index < d_len) {
// copy smaller of remaining buffer space and num inputs to work()
- int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+ int num_copy = std::min( (int)(d_len - d_index), noutput_items );
- // TODO: convert this to a copy operator for speed...
- for(int i = 0; i < num_copy; i++) {
- d_buffer.push_back(in[i]);
- }
+ memcpy(&d_buffer[d_index], in, num_copy*sizeof(char));
+ d_index += num_copy;
}
// notify the waiting get() if we fill up the buffer
- if(d_buffer.size() == d_len) {
- buffered_get.offer_data(d_buffer);
+ if(d_index == d_len) {
+ buffered_get.offer_data(d_buffer);
+ d_index = 0;
}
return noutput_items;
diff --git a/gr-blocks/lib/ctrlport_probe2_b_impl.h b/gr-blocks/lib/ctrlport_probe2_b_impl.h
index 490af9b040..165f0d33db 100644
--- a/gr-blocks/lib/ctrlport_probe2_b_impl.h
+++ b/gr-blocks/lib/ctrlport_probe2_b_impl.h
@@ -38,6 +38,7 @@ namespace gr {
size_t d_len;
unsigned int d_disp_mask;
+ size_t d_index;
std::vector<signed char> d_buffer;
rpcbufferedget< std::vector<signed char> > buffered_get;
@@ -64,4 +65,3 @@ namespace gr {
} /* namespace gr */
#endif /* INCLUDED_CTRLPORT_PROBE2_C_IMPL_H */
-
diff --git a/gr-blocks/lib/ctrlport_probe2_c_impl.cc b/gr-blocks/lib/ctrlport_probe2_c_impl.cc
index bd43130be5..b8ed0af444 100644
--- a/gr-blocks/lib/ctrlport_probe2_c_impl.cc
+++ b/gr-blocks/lib/ctrlport_probe2_c_impl.cc
@@ -65,21 +65,26 @@ namespace gr {
}
std::vector<gr_complex>
- ctrlport_probe2_c_impl::get() {
+ ctrlport_probe2_c_impl::get()
+ {
return buffered_get.get();
}
void
ctrlport_probe2_c_impl::set_length(int len)
{
+ gr::thread::scoped_lock guard(d_setlock);
+
if(len > 8191) {
- std::cerr << "probe2_c: length " << len
- << " exceeds maximum buffer size of 8191" << std::endl;
+ GR_LOG_WARN(d_logger,
+ boost::format("probe2_c: length %1% exceeds maximum"
+ " buffer size of 8191") % len);
len = 8191;
}
d_len = len;
- d_buffer.reserve(d_len);
+ d_buffer.resize(d_len);
+ d_index = 0;
}
int
@@ -95,20 +100,21 @@ namespace gr {
{
const gr_complex *in = (const gr_complex*)input_items[0];
+ gr::thread::scoped_lock guard(d_setlock);
+
// copy samples to get buffer if we need samples
- if(d_buffer.size() < d_len) {
+ if(d_index < d_len) {
// copy smaller of remaining buffer space and num inputs to work()
- int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+ int num_copy = std::min( (int)(d_len - d_index), noutput_items );
- // TODO: convert this to a copy operator for speed...
- for(int i = 0; i < num_copy; i++) {
- d_buffer.push_back(in[i]);
- }
+ memcpy(&d_buffer[d_index], in, num_copy*sizeof(gr_complex));
+ d_index += num_copy;
}
// notify the waiting get() if we fill up the buffer
- if(d_buffer.size() == d_len) {
- buffered_get.offer_data(d_buffer);
+ if(d_index == d_len) {
+ buffered_get.offer_data(d_buffer);
+ d_index = 0;
}
return noutput_items;
diff --git a/gr-blocks/lib/ctrlport_probe2_c_impl.h b/gr-blocks/lib/ctrlport_probe2_c_impl.h
index fa74216202..119738a481 100644
--- a/gr-blocks/lib/ctrlport_probe2_c_impl.h
+++ b/gr-blocks/lib/ctrlport_probe2_c_impl.h
@@ -38,6 +38,7 @@ namespace gr {
size_t d_len;
unsigned int d_disp_mask;
+ size_t d_index;
std::vector<gr_complex> d_buffer;
rpcbufferedget< std::vector<gr_complex> > buffered_get;
diff --git a/gr-blocks/lib/ctrlport_probe2_f_impl.cc b/gr-blocks/lib/ctrlport_probe2_f_impl.cc
index 05d67da9dd..ff37401e88 100644
--- a/gr-blocks/lib/ctrlport_probe2_f_impl.cc
+++ b/gr-blocks/lib/ctrlport_probe2_f_impl.cc
@@ -63,21 +63,26 @@ namespace gr {
}
std::vector<float>
- ctrlport_probe2_f_impl::get() {
+ ctrlport_probe2_f_impl::get()
+ {
return buffered_get.get();
}
void
ctrlport_probe2_f_impl::set_length(int len)
{
+ gr::thread::scoped_lock guard(d_setlock);
+
if(len > 8191) {
- std::cerr << "probe2_f: length " << len
- << " exceeds maximum buffer size of 8191" << std::endl;
+ GR_LOG_WARN(d_logger,
+ boost::format("probe2_f: length %1% exceeds maximum"
+ " buffer size of 8191") % len);
len = 8191;
}
d_len = len;
- d_buffer.reserve(d_len);
+ d_buffer.resize(d_len);
+ d_index = 0;
}
int
@@ -93,21 +98,21 @@ namespace gr {
{
const float *in = (const float*)input_items[0];
+ gr::thread::scoped_lock guard(d_setlock);
+
// copy samples to get buffer if we need samples
- if(d_buffer.size() < d_len) {
+ if(d_index < d_len) {
// copy smaller of remaining buffer space and num inputs to work()
- int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+ int num_copy = std::min( (int)(d_len - d_index), noutput_items );
- // TODO: convert this to a copy operator for speed...
- for(int i = 0; i < num_copy; i++) {
- d_buffer.push_back(in[i]);
- }
+ memcpy(&d_buffer[d_index], in, num_copy*sizeof(float));
+ d_index += num_copy;
}
-
// notify the waiting get() if we fill up the buffer
- if(d_buffer.size() == d_len) {
- buffered_get.offer_data(d_buffer);
+ if(d_index == d_len) {
+ buffered_get.offer_data(d_buffer);
+ d_index = 0;
}
return noutput_items;
diff --git a/gr-blocks/lib/ctrlport_probe2_f_impl.h b/gr-blocks/lib/ctrlport_probe2_f_impl.h
index 8d406db927..6aec0789f4 100644
--- a/gr-blocks/lib/ctrlport_probe2_f_impl.h
+++ b/gr-blocks/lib/ctrlport_probe2_f_impl.h
@@ -38,6 +38,7 @@ namespace gr {
size_t d_len;
unsigned int d_disp_mask;
+ size_t d_index;
std::vector<float> d_buffer;
rpcbufferedget< std::vector<float> > buffered_get;
diff --git a/gr-blocks/lib/ctrlport_probe2_i_impl.cc b/gr-blocks/lib/ctrlport_probe2_i_impl.cc
index 086ebe7cf0..7e17d8e8fe 100644
--- a/gr-blocks/lib/ctrlport_probe2_i_impl.cc
+++ b/gr-blocks/lib/ctrlport_probe2_i_impl.cc
@@ -65,21 +65,26 @@ namespace gr {
}
std::vector<int>
- ctrlport_probe2_i_impl::get() {
+ ctrlport_probe2_i_impl::get()
+ {
return buffered_get.get();
}
void
ctrlport_probe2_i_impl::set_length(int len)
{
+ gr::thread::scoped_lock guard(d_setlock);
+
if(len > 8191) {
- std::cerr << "probe2_i: length " << len
- << " exceeds maximum buffer size of 8191" << std::endl;
+ GR_LOG_WARN(d_logger,
+ boost::format("probe2_i: length %1% exceeds maximum"
+ " buffer size of 8191") % len);
len = 8191;
}
d_len = len;
- d_buffer.reserve(d_len);
+ d_buffer.resize(d_len);
+ d_index = 0;
}
int
@@ -94,20 +99,22 @@ namespace gr {
gr_vector_void_star &output_items)
{
const int *in = (const int*)input_items[0];
+
+ gr::thread::scoped_lock guard(d_setlock);
+
// copy samples to get buffer if we need samples
- if(d_buffer.size() < d_len) {
+ if(d_index < d_len) {
// copy smaller of remaining buffer space and num inputs to work()
- int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+ int num_copy = std::min( (int)(d_len - d_index), noutput_items );
- // TODO: convert this to a copy operator for speed...
- for(int i = 0; i < num_copy; i++) {
- d_buffer.push_back(in[i]);
- }
+ memcpy(&d_buffer[d_index], in, num_copy*sizeof(int));
+ d_index += num_copy;
}
// notify the waiting get() if we fill up the buffer
- if(d_buffer.size() == d_len) {
- buffered_get.offer_data(d_buffer);
+ if(d_index == d_len) {
+ buffered_get.offer_data(d_buffer);
+ d_index = 0;
}
return noutput_items;
diff --git a/gr-blocks/lib/ctrlport_probe2_i_impl.h b/gr-blocks/lib/ctrlport_probe2_i_impl.h
index 3a976550eb..2832af07ec 100644
--- a/gr-blocks/lib/ctrlport_probe2_i_impl.h
+++ b/gr-blocks/lib/ctrlport_probe2_i_impl.h
@@ -38,6 +38,7 @@ namespace gr {
size_t d_len;
unsigned int d_disp_mask;
+ size_t d_index;
std::vector<int> d_buffer;
rpcbufferedget< std::vector<int> > buffered_get;
diff --git a/gr-blocks/lib/ctrlport_probe2_s_impl.cc b/gr-blocks/lib/ctrlport_probe2_s_impl.cc
index d6a15faaef..9924243db0 100644
--- a/gr-blocks/lib/ctrlport_probe2_s_impl.cc
+++ b/gr-blocks/lib/ctrlport_probe2_s_impl.cc
@@ -65,21 +65,26 @@ namespace gr {
}
std::vector<short>
- ctrlport_probe2_s_impl::get() {
+ ctrlport_probe2_s_impl::get()
+ {
return buffered_get.get();
}
void
ctrlport_probe2_s_impl::set_length(int len)
{
+ gr::thread::scoped_lock guard(d_setlock);
+
if(len > 8191) {
- std::cerr << "probe2_s: length " << len
- << " exceeds maximum buffer size of 8191" << std::endl;
+ GR_LOG_WARN(d_logger,
+ boost::format("probe2_s: length %1% exceeds maximum"
+ " buffer size of 8191") % len);
len = 8191;
}
d_len = len;
- d_buffer.reserve(d_len);
+ d_buffer.resize(d_len);
+ d_index = 0;
}
int
@@ -95,19 +100,19 @@ namespace gr {
{
const short *in = (const short*)input_items[0];
+ gr::thread::scoped_lock guard(d_setlock);
+
// copy samples to get buffer if we need samples
- if(d_buffer.size() < d_len) {
+ if(d_index < d_len) {
// copy smaller of remaining buffer space and num inputs to work()
- int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items );
+ int num_copy = std::min( (int)(d_len - d_index), noutput_items );
- // TODO: convert this to a copy operator for speed...
- for(int i = 0; i < num_copy; i++) {
- d_buffer.push_back(in[i]);
- }
+ memcpy(&d_buffer[d_index], in, num_copy*sizeof(short));
+ d_index += num_copy;
}
// notify the waiting get() if we fill up the buffer
- if(d_buffer.size() == d_len) {
+ if(d_index == d_len) {
buffered_get.offer_data(d_buffer);
}
diff --git a/gr-blocks/lib/ctrlport_probe2_s_impl.h b/gr-blocks/lib/ctrlport_probe2_s_impl.h
index 49533ced6f..a608a7898c 100644
--- a/gr-blocks/lib/ctrlport_probe2_s_impl.h
+++ b/gr-blocks/lib/ctrlport_probe2_s_impl.h
@@ -38,6 +38,7 @@ namespace gr {
size_t d_len;
unsigned int d_disp_mask;
+ size_t d_index;
std::vector<short> d_buffer;
rpcbufferedget< std::vector<short> > buffered_get;
diff --git a/gr-blocks/lib/peak_detector2_fb_impl.cc b/gr-blocks/lib/peak_detector2_fb_impl.cc
index 7ff7f542ec..dc13e66dbe 100644
--- a/gr-blocks/lib/peak_detector2_fb_impl.cc
+++ b/gr-blocks/lib/peak_detector2_fb_impl.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2010,2013 Free Software Foundation, Inc.
+ * Copyright 2007,2010,2013,2015 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -45,15 +45,46 @@ namespace gr {
: sync_block("peak_detector2_fb",
io_signature::make(1, 1, sizeof(float)),
io_signature::make2(1, 2, sizeof(char), sizeof(float))),
- d_threshold_factor_rise(threshold_factor_rise),
- d_look_ahead(look_ahead), d_alpha(alpha), d_avg(0.0f), d_found(false)
+ d_avg(0.0f), d_found(false)
{
+ set_threshold_factor_rise(threshold_factor_rise);
+ set_look_ahead(look_ahead);
+ set_alpha(alpha);
}
peak_detector2_fb_impl::~peak_detector2_fb_impl()
{
}
+ void
+ peak_detector2_fb_impl::set_threshold_factor_rise(float thr)
+ {
+ gr::thread::scoped_lock lock(d_setlock);
+ d_threshold_factor_rise = thr;
+ invalidate();
+ }
+
+ void
+ peak_detector2_fb_impl::set_look_ahead(int look)
+ {
+ gr::thread::scoped_lock lock(d_setlock);
+ d_look_ahead = look;
+ invalidate();
+ }
+
+ void
+ peak_detector2_fb_impl::set_alpha(float alpha)
+ {
+ d_alpha = alpha;
+ }
+
+ void
+ peak_detector2_fb_impl::invalidate()
+ {
+ d_found = false;
+ set_output_multiple(1);
+ }
+
int
peak_detector2_fb_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
@@ -61,53 +92,53 @@ namespace gr {
{
float *iptr = (float *)input_items[0];
char *optr = (char *)output_items[0];
+ float *sigout;
+
+ if(output_items.size() == 2)
+ sigout = (float *)output_items[1];
memset(optr, 0, noutput_items*sizeof(char));
- for(int i = 0; i < noutput_items; i++) {
- if(!d_found) {
- // Have not yet detected presence of peak
+ gr::thread::scoped_lock lock(d_setlock);
+
+ // have not crossed threshold yet
+ if(d_found==false) {
+ for(int i = 0; i < noutput_items; i++) {
+ d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg;
+ if(output_items.size() == 2)
+ sigout[i]=d_avg;
if(iptr[i] > d_avg * (1.0f + d_threshold_factor_rise)) {
d_found = true;
- d_look_ahead_remaining = d_look_ahead;
d_peak_val = -(float)INFINITY;
- }
- else {
- d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg;
+ set_output_multiple(d_look_ahead);
+ return i;
}
}
- else {
- // Detected presence of peak
+ return noutput_items;
+ } // end d_found==false
+
+ // can complete in this call
+ else if(noutput_items >= d_look_ahead) {
+ for(int i = 0; i < d_look_ahead; i++) {
+ d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg;
+ if(output_items.size() == 2)
+ sigout[i]=d_avg;
if(iptr[i] > d_peak_val) {
d_peak_val = iptr[i];
- d_peak_ind = i;
- }
- else if(d_look_ahead_remaining <= 0) {
- optr[d_peak_ind] = 1;
- d_found = false;
- d_avg = iptr[i];
+ d_peak_ind =i;
}
-
- // Have not yet located peak, loop and keep searching.
- d_look_ahead_remaining--;
- }
-
- // Every iteration of the loop, write debugging signal out if
- // connected:
- if(output_items.size() == 2) {
- float *sigout = (float *)output_items[1];
- sigout[i] = d_avg;
}
- } // loop
-
- if(!d_found)
- return noutput_items;
+ optr[d_peak_ind] = 1;
- // else if detected presence, keep searching during the next call to work.
- int tmp = d_peak_ind;
- d_peak_ind = 1;
+ // restart the search
+ invalidate();
+ return d_look_ahead;
+ } // end can complete in this call
- return tmp - 1;
+ // cannot complete in this call
+ else {
+ return 0; // ask for more
+ }
}
} /* namespace blocks */
diff --git a/gr-blocks/lib/peak_detector2_fb_impl.h b/gr-blocks/lib/peak_detector2_fb_impl.h
index f5a8ac1a6b..4e16c93dac 100644
--- a/gr-blocks/lib/peak_detector2_fb_impl.h
+++ b/gr-blocks/lib/peak_detector2_fb_impl.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2013 Free Software Foundation, Inc.
+ * Copyright 2007,2013,2015 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -40,14 +40,16 @@ namespace gr {
float d_avg;
bool d_found;
+ void invalidate();
+
public:
peak_detector2_fb_impl(float threshold_factor_rise,
int look_ahead, float alpha);
~peak_detector2_fb_impl();
- void set_threshold_factor_rise(float thr) { d_threshold_factor_rise = thr; }
- void set_look_ahead(int look) { d_look_ahead = look; }
- void set_alpha(float alpha) { d_alpha = alpha; }
+ void set_threshold_factor_rise(float thr);
+ void set_look_ahead(int look);
+ void set_alpha(float alpha);
float threshold_factor_rise() { return d_threshold_factor_rise; }
int look_ahead() { return d_look_ahead; }
diff --git a/gr-blocks/python/blocks/qa_peak_detector2.py b/gr-blocks/python/blocks/qa_peak_detector2.py
index 475897eac2..d6fd4fe95f 100644
--- a/gr-blocks/python/blocks/qa_peak_detector2.py
+++ b/gr-blocks/python/blocks/qa_peak_detector2.py
@@ -30,18 +30,20 @@ class test_peak_detector2(gr_unittest.TestCase):
def tearDown(self):
self.tb = None
- def test_regen1(self):
+ def test_peak1(self):
+ #print "\n\nTEST 1"
tb = self.tb
- data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
- 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
+ n=10
+ data = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,)+n*(0,)
expected_result = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)+n*(0,)
src = blocks.vector_source_f(data, False)
- regen = blocks.peak_detector2_fb()
+ regen = blocks.peak_detector2_fb(7.0, 25, 0.001)
dst = blocks.vector_sink_b()
tb.connect(src, regen)
@@ -52,5 +54,80 @@ class test_peak_detector2(gr_unittest.TestCase):
self.assertEqual(expected_result, dst_data)
+ def test_peak2(self):
+ #print "\n\nTEST 2"
+ tb = self.tb
+
+ n=10
+ data = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,)+n*(0,)
+
+ expected_result = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)+n*(0,)
+
+
+ src = blocks.vector_source_f(data, False)
+ regen = blocks.peak_detector2_fb(7.0, 1000, 0.001) # called with a LONG window
+ dst = blocks.vector_sink_b()
+
+ tb.connect(src, regen)
+ tb.connect(regen, dst)
+ tb.run()
+
+ dst_data = dst.data()
+
+ # here we know that the block will terminate prematurely, so we compare only part of the expected_result
+ self.assertEqual(expected_result[0:len(dst_data)], dst_data)
+
+
+ def test_peak3(self):
+ #print "\n\nTEST 3"
+ tb = self.tb
+
+ l = 8100
+ m = 100
+ n = 10
+ data = l*(0,)+ (10,)+ m*(0,)+(100,)+ n*(0,)
+ expected_result = l*(0,)+ (0,)+ m*(0,)+(1,)+ n*(0,)
+
+
+ src = blocks.vector_source_f(data, False)
+ regen = blocks.peak_detector2_fb(7.0, 105, 0.001)
+ dst = blocks.vector_sink_b()
+
+ tb.connect(src, regen)
+ tb.connect(regen, dst)
+ tb.run()
+
+ dst_data = dst.data()
+
+ self.assertEqual(expected_result, dst_data)
+
+
+ def test_peak4(self):
+ #print "\n\nTEST 4"
+ tb = self.tb
+
+ l = 8100
+ m = 100
+ n = 10
+ data = l*(0,)+ (10,)+ m*(0,)+(100,)+ n*(0,)
+ expected_result = l*(0,)+ (0,)+ m*(0,)+(1,)+ n*(0,)
+
+
+ src = blocks.vector_source_f(data, False)
+ regen = blocks.peak_detector2_fb(7.0, 150, 0.001)
+ dst = blocks.vector_sink_b()
+
+ tb.connect(src, regen)
+ tb.connect(regen, dst)
+ tb.run()
+
+ dst_data = dst.data()
+
+ # here we know that the block will terminate prematurely, so we compare only part of the expected_result
+ self.assertEqual(expected_result[0:len(dst_data)], dst_data)
+
+
if __name__ == '__main__':
gr_unittest.run(test_peak_detector2, "test_peak_detector2.xml")
diff --git a/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t b/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t
index 43d422ba80..fd7b69060e 100644
--- a/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t
+++ b/gr-digital/include/gnuradio/digital/burst_shaper_XX.h.t
@@ -49,7 +49,15 @@ namespace gr {
* directly to the head and tail of each burst.
*
* Length tags will be updated to include the length of any added
- * zero padding or phasing symbols.
+ * zero padding or phasing symbols and will be placed at the
+ * beginning of the modified tagged stream. Any other tags found at
+ * the same offset as a length tag will also be placed at the
+ * beginning of the modified tagged stream, since these tags are
+ * assumed to be associated with the burst rather than a specific
+ * sample. For example, if "tx_time" tags are used to control
+ * bursts, their offsets should be consistent with their associated
+ * burst's length tags. Tags at other offsets will be placed with
+ * the samples on which they were found.
*
* \li input: stream of @I_TYPE@
* \li output: stream of @O_TYPE@
diff --git a/gr-digital/lib/burst_shaper_XX_impl.cc.t b/gr-digital/lib/burst_shaper_XX_impl.cc.t
index bd92665701..85add49115 100644
--- a/gr-digital/lib/burst_shaper_XX_impl.cc.t
+++ b/gr-digital/lib/burst_shaper_XX_impl.cc.t
@@ -68,7 +68,7 @@ namespace gr {
d_ncopy(0),
d_limit(0),
d_index(0),
- d_nprocessed(0),
+ d_length_tag_offset(0),
d_finished(false),
d_state(STATE_WAIT)
{
@@ -94,8 +94,8 @@ namespace gr {
void
@IMPL_NAME@::forecast(int noutput_items,
- gr_vector_int &ninput_items_required) {
- //if(d_state == STATE_COPY
+ gr_vector_int &ninput_items_required)
+ {
ninput_items_required[0] = noutput_items;
}
@@ -112,13 +112,11 @@ namespace gr {
int nread = 0;
int nspace = 0;
int nskip = 0;
- uint64_t curr_tag_index = nitems_read(0);
+ int curr_tag_index = 0;
- std::vector<tag_t> length_tags, tags;
+ std::vector<tag_t> length_tags;
get_tags_in_window(length_tags, 0, 0, ninput_items[0], d_length_tag_key);
- get_tags_in_window(tags, 0, 0, ninput_items[0]);
std::sort(length_tags.rbegin(), length_tags.rend(), tag_t::offset_compare);
- std::sort(tags.rbegin(), tags.rend(), tag_t::offset_compare);
while((nwritten < noutput_items) && (nread < ninput_items[0])) {
if(d_finished) {
@@ -128,12 +126,14 @@ namespace gr {
nspace = noutput_items - nwritten;
switch(d_state) {
case(STATE_WAIT):
- if(!tags.empty()) {
- curr_tag_index = tags.back().offset;
- d_ncopy = pmt::to_long(tags.back().value);
- tags.pop_back();
- nskip = (int)(curr_tag_index - d_nprocessed);
+ if(!length_tags.empty()) {
+ d_length_tag_offset = length_tags.back().offset;
+ curr_tag_index = (int)(d_length_tag_offset - nitems_read(0));
+ d_ncopy = pmt::to_long(length_tags.back().value);
+ length_tags.pop_back();
+ nskip = curr_tag_index - nread;
add_length_tag(nwritten);
+ propagate_tags(curr_tag_index, nwritten, 1, false);
enter_prepad();
}
else {
@@ -144,7 +144,7 @@ namespace gr {
boost::format("Dropping %1% samples") %
nskip);
nread += nskip;
- d_nprocessed += nskip;
+ in += nskip;
}
break;
@@ -189,19 +189,22 @@ namespace gr {
}
int
- @IMPL_NAME@::prefix_length() const {
+ @IMPL_NAME@::prefix_length() const
+ {
return (d_insert_phasing) ?
d_nprepad + d_up_ramp.size() : d_nprepad;
}
int
- @IMPL_NAME@::suffix_length() const {
+ @IMPL_NAME@::suffix_length() const
+ {
return (d_insert_phasing) ?
d_npostpad + d_down_ramp.size() : d_npostpad;
}
void
- @IMPL_NAME@::write_padding(@O_TYPE@ *&dst, int &nwritten, int nspace) {
+ @IMPL_NAME@::write_padding(@O_TYPE@ *&dst, int &nwritten, int nspace)
+ {
int nprocess = std::min(d_limit - d_index, nspace);
std::memset(dst, 0x00, nprocess * sizeof(@O_TYPE@));
dst += nprocess;
@@ -211,8 +214,10 @@ namespace gr {
void
@IMPL_NAME@::copy_items(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten,
- int &nread, int nspace) {
+ int &nread, int nspace)
+ {
int nprocess = std::min(d_limit - d_index, nspace);
+ propagate_tags(nread, nwritten, nprocess);
std::memcpy(dst, src, nprocess * sizeof(@O_TYPE@));
dst += nprocess;
nwritten += nprocess;
@@ -223,7 +228,8 @@ namespace gr {
void
@IMPL_NAME@::apply_ramp(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten,
- int &nread, int nspace) {
+ int &nread, int nspace)
+ {
int nprocess = std::min(d_limit - d_index, nspace);
@O_TYPE@ *phasing;
const @O_TYPE@ *ramp;
@@ -240,6 +246,7 @@ namespace gr {
if(d_insert_phasing)
std::memcpy(dst, phasing, nprocess * sizeof(@O_TYPE@));
else {
+ propagate_tags(nread, nwritten, nprocess);
VOLK_MULT_@O_TYPE@(dst, src, ramp, nprocess);
src += nprocess;
nread += nprocess;
@@ -260,34 +267,48 @@ namespace gr {
}
void
- @IMPL_NAME@::propagate_tags(std::vector<tag_t> &tags, int offset)
+ @IMPL_NAME@::propagate_tags(int in_offset, int out_offset, int count, bool skip)
{
- // FIXME: need to handle offsets correctly
- std::vector<tag_t>::iterator tag;
- for(tag = tags.begin(); tag != tags.end(); tag++) {
- tag_t new_tag = *tag;
- new_tag.offset = nitems_written(0) + offset;
- add_item_tag(0, new_tag);
+ uint64_t abs_start = nitems_read(0) + in_offset;
+ uint64_t abs_end = abs_start + count;
+ uint64_t abs_offset = nitems_written(0) + out_offset;
+ tag_t temp_tag;
+
+ std::vector<tag_t> tags;
+ std::vector<tag_t>::iterator it;
+
+ get_tags_in_range(tags, 0, abs_start, abs_end);
+
+ for(it = tags.begin(); it != tags.end(); it++) {
+ if(!pmt::equal(it->key, d_length_tag_key)) {
+ if(skip && (it->offset == d_length_tag_offset))
+ continue;
+ temp_tag = *it;
+ temp_tag.offset = abs_offset + it->offset - abs_start;
+ add_item_tag(0, temp_tag);
+ }
}
}
void
- @IMPL_NAME@::enter_wait() {
+ @IMPL_NAME@::enter_wait()
+ {
d_finished = true;
- d_nprocessed += d_ncopy;
d_index = 0;
d_state = STATE_WAIT;
}
void
- @IMPL_NAME@::enter_prepad() {
+ @IMPL_NAME@::enter_prepad()
+ {
d_limit = d_nprepad;
d_index = 0;
d_state = STATE_PREPAD;
}
void
- @IMPL_NAME@::enter_rampup() {
+ @IMPL_NAME@::enter_rampup()
+ {
if(d_insert_phasing)
d_limit = d_up_ramp.size();
else
@@ -297,7 +318,8 @@ namespace gr {
}
void
- @IMPL_NAME@::enter_copy() {
+ @IMPL_NAME@::enter_copy()
+ {
if(d_insert_phasing)
d_limit = d_ncopy;
else
@@ -309,7 +331,8 @@ namespace gr {
}
void
- @IMPL_NAME@::enter_rampdown() {
+ @IMPL_NAME@::enter_rampdown()
+ {
if(d_insert_phasing)
d_limit = d_down_ramp.size();
else
@@ -319,7 +342,8 @@ namespace gr {
}
void
- @IMPL_NAME@::enter_postpad() {
+ @IMPL_NAME@::enter_postpad()
+ {
d_limit = d_npostpad;
d_index = 0;
d_state = STATE_POSTPAD;
diff --git a/gr-digital/lib/burst_shaper_XX_impl.h.t b/gr-digital/lib/burst_shaper_XX_impl.h.t
index 90c7df8e88..99ad7fb08a 100644
--- a/gr-digital/lib/burst_shaper_XX_impl.h.t
+++ b/gr-digital/lib/burst_shaper_XX_impl.h.t
@@ -48,7 +48,7 @@ namespace gr {
int d_ncopy;
int d_limit;
int d_index;
- uint64_t d_nprocessed;
+ uint64_t d_length_tag_offset;
bool d_finished;
state_t d_state;
@@ -58,7 +58,7 @@ namespace gr {
void apply_ramp(@O_TYPE@ *&dst, const @I_TYPE@ *&src, int &nwritten,
int &nread, int nspace);
void add_length_tag(int offset);
- void propagate_tags(std::vector<tag_t> &tags, int offset);
+ void propagate_tags(int in_offset, int out_offset, int count, bool skip=true);
void enter_wait();
void enter_prepad();
void enter_rampup();
diff --git a/gr-digital/python/digital/qa_burst_shaper.py b/gr-digital/python/digital/qa_burst_shaper.py
index d00c23007b..f85b79ceec 100755
--- a/gr-digital/python/digital/qa_burst_shaper.py
+++ b/gr-digital/python/digital/qa_burst_shaper.py
@@ -25,6 +25,7 @@ from gnuradio import gr, gr_unittest
from gnuradio import blocks, digital
import pmt
import numpy as np
+import sys
def make_length_tag(offset, length):
return gr.python_to_tag({'offset' : offset,
@@ -32,13 +33,15 @@ def make_length_tag(offset, length):
'value' : pmt.from_long(length),
'srcid' : pmt.intern('qa_burst_shaper')})
+def make_tag(offset, key, value):
+ return gr.python_to_tag({'offset' : offset,
+ 'key' : pmt.intern(key),
+ 'value' : value,
+ 'srcid' : pmt.intern('qa_burst_shaper')})
+
def compare_tags(a, b):
- a = gr.tag_to_python(a)
- b = gr.tag_to_python(b)
- return a.key == b.key and a.offset == b.offset and \
- a.value == b.value
- #return a.key == b.key and a.offset == b.offset and \
- # a.srcid == b.srcid and a.value == b.value
+ return a.offset == b.offset and pmt.equal(a.key, b.key) and \
+ pmt.equal(a.value, b.value)
class qa_burst_shaper (gr_unittest.TestCase):
@@ -244,31 +247,94 @@ class qa_burst_shaper (gr_unittest.TestCase):
prepad = 10
postpad = 10
length = 20
- data = np.ones(2*length + 10) # need 10 more to push things through
+ gap_len = 5
+ data = np.arange(2*length + 10,
+ dtype=float) # need 10 more to push things through
window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5)))
- tags = (make_length_tag(0, length), make_length_tag(length + 5, length))
- expected = np.concatenate((np.zeros(prepad), window[0:5],
- np.ones(length - len(window)), window[5:10],
- np.zeros(postpad)))
- etags = (make_length_tag(0, length + prepad + postpad),
- make_length_tag(length + prepad + postpad,
- length + prepad + postpad))
+ ewindow = window * np.array([1,-1,1,-1,1,1,-1,1,-1,1],dtype=float)
+ tags = (make_length_tag(0, length),
+ make_length_tag(length + gap_len, length))
+ expected = np.concatenate((np.zeros(prepad), ewindow[0:5],
+ np.arange(0, length, dtype=float),
+ ewindow[5:10], np.zeros(postpad),
+ np.zeros(prepad), ewindow[0:5],
+ np.arange(length + gap_len,
+ 2*length + gap_len, dtype=float),
+ ewindow[5:10], np.zeros(postpad)))
+ burst_len = length + len(window) + prepad + postpad
+ etags = (make_length_tag(0, burst_len),
+ make_length_tag(burst_len, burst_len))
# flowgraph
source = blocks.vector_source_f(data, tags=tags)
shaper = digital.burst_shaper_ff(window, pre_padding=prepad,
- post_padding=postpad)
+ post_padding=postpad,
+ insert_phasing=True)
sink = blocks.vector_sink_f()
self.tb.connect(source, shaper, sink)
self.tb.run ()
# checks
- self.assertFloatTuplesAlmostEqual(sink.data(),
- np.concatenate((expected, expected),
- 6))
+ self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6)
for i in xrange(len(etags)):
self.assertTrue(compare_tags(sink.tags()[i], etags[i]))
+ def test_tag_propagation (self):
+ prepad = 10
+ postpad = 10
+ length1 = 15
+ length2 = 25
+ gap_len = 5
+ lentag1_offset = 0
+ lentag2_offset = length1 + gap_len
+ tag1_offset = 0 # accompanies first length tag
+ tag2_offset = length1 + gap_len # accompanies second length tag
+ tag3_offset = 2 # in ramp-up state
+ tag4_offset = length1 + 2 # in gap; tag will be dropped
+ tag5_offset = length1 + gap_len + 7 # in copy state
+
+ data = np.concatenate((np.ones(length1), np.zeros(gap_len),
+ -1.0*np.ones(length2), np.zeros(10)))
+ window = np.concatenate((-2.0*np.ones(5), -4.0*np.ones(5)))
+ tags = (make_length_tag(lentag1_offset, length1),
+ make_length_tag(lentag2_offset, length2),
+ make_tag(tag1_offset, 'head', pmt.intern('tag1')),
+ make_tag(tag2_offset, 'head', pmt.intern('tag2')),
+ make_tag(tag3_offset, 'body', pmt.intern('tag3')),
+ make_tag(tag4_offset, 'body', pmt.intern('tag4')),
+ make_tag(tag5_offset, 'body', pmt.intern('tag5')))
+ expected = np.concatenate((np.zeros(prepad), window[0:5],
+ np.ones(length1 - len(window)), window[5:10],
+ np.zeros(postpad + prepad), -1.0*window[0:5],
+ -1.0*np.ones(length2 - len(window)),
+ -1.0*window[5:10], np.zeros(postpad)))
+ elentag1_offset = 0
+ elentag2_offset = length1 + prepad + postpad
+ etag1_offset = 0
+ etag2_offset = elentag2_offset
+ etag3_offset = prepad + tag3_offset
+ etag5_offset = 2*prepad + postpad + tag5_offset - gap_len
+ etags = (make_length_tag(elentag1_offset, length1 + prepad + postpad),
+ make_length_tag(elentag2_offset, length2 + prepad + postpad),
+ make_tag(etag1_offset, 'head', pmt.intern('tag1')),
+ make_tag(etag2_offset, 'head', pmt.intern('tag2')),
+ make_tag(etag3_offset, 'body', pmt.intern('tag3')),
+ make_tag(etag5_offset, 'body', pmt.intern('tag5')))
+
+ # flowgraph
+ source = blocks.vector_source_f(data, tags=tags)
+ shaper = digital.burst_shaper_ff(window, pre_padding=prepad,
+ post_padding=postpad)
+ sink = blocks.vector_sink_f()
+ self.tb.connect(source, shaper, sink)
+ self.tb.run ()
+
+ # checks
+ self.assertFloatTuplesAlmostEqual(sink.data(), expected, 6)
+ for x, y in zip(sorted(sink.tags(), key=gr.tag_t_offset_compare_key()),
+ sorted(etags, key=gr.tag_t_offset_compare_key())):
+ self.assertTrue(compare_tags(x, y))
+
if __name__ == '__main__':
gr_unittest.run(qa_burst_shaper, "qa_burst_shaper.xml")
diff --git a/gr-qtgui/grc/qtgui_range.xml b/gr-qtgui/grc/qtgui_range.xml
index 05f3ffce9f..71b614cc5e 100644
--- a/gr-qtgui/grc/qtgui_range.xml
+++ b/gr-qtgui/grc/qtgui_range.xml
@@ -6,105 +6,126 @@
###################################################
-->
<block>
- <name>QT GUI Range</name>
- <key>variable_qtgui_range</key>
- <import>from gnuradio.qtgui import Range, RangeWidget</import>
- <var_make>self.$(id) = $(id) = $value</var_make>
- <make>#set $win = 'self._%s_win'%$id
+ <name>QT GUI Range</name>
+ <key>variable_qtgui_range</key>
+ <import>from gnuradio.qtgui import Range, RangeWidget</import>
+ <var_make>self.$(id) = $(id) = $value</var_make>
+ <make>#set $win = 'self._%s_win'%$id
#set $range = 'self._%s_range'%$id
#if not $label()
#set $label = '"%s"'%$id
#end if
$(range) = Range($start, $stop, $step, $value, $min_len)
-$(win) = RangeWidget($range, self.set_$(id), $label, "$widget")
+$(win) = RangeWidget($range, self.set_$(id), $label, "$widget", $rangeType)
$(gui_hint()($win))</make>
- <callback>self.set_$(id)($value)</callback>
- <param>
- <name>Label</name>
- <key>label</key>
- <value></value>
- <type>string</type>
- <hide>#if $label() then 'none' else 'part'#</hide>
- </param>
- <param>
- <name>Default Value</name>
- <key>value</key>
- <value>50</value>
- <type>real</type>
- </param>
- <param>
- <name>Start</name>
- <key>start</key>
- <value>0</value>
- <type>real</type>
- </param>
- <param>
- <name>Stop</name>
- <key>stop</key>
- <value>100</value>
- <type>real</type>
- </param>
- <param>
- <name>Step</name>
- <key>step</key>
- <value>1</value>
- <type>real</type>
- </param>
- <param>
- <name>Widget</name>
- <key>widget</key>
- <value>counter_slider</value>
- <type>enum</type>
- <hide>part</hide>
- <option><name>Counter + Slider</name><key>counter_slider</key></option>
- <option><name>Counter</name><key>counter</key></option>
- <option><name>Slider</name><key>slider</key></option>
- <option><name>Knob</name><key>dial</key></option>
- </param>
- <param>
- <name>Orientation</name>
- <key>orient</key>
- <value>Qt.Horizontal</value>
- <type>enum</type>
- <hide>#if $widget() == "slider" then 'part' else 'all'#</hide>
- <option>
- <name>Horizontal</name>
- <key>Qt.Horizontal</key>
- <opt>scalepos:BottomScale</opt>
- <opt>minfcn:setMinimumWidth</opt>
- </option>
- <option>
- <name>Vertical</name>
- <key>Qt.Vertical</key>
- <opt>scalepos:LeftScale</opt>
- <opt>minfcn:setMinimumHeight</opt>
- </option>
- </param>
- <param>
- <name>Minimum Length</name>
- <key>min_len</key>
- <value>200</value>
- <type>int</type>
- <hide>part</hide>
- </param>
-<!-- from min_len <hide>#if $widget().split('_')[0] in ("slider", "counter") then 'part' else 'all'#</hide>-->
- <param>
- <name>GUI Hint</name>
- <key>gui_hint</key>
- <value></value>
- <type>gui_hint</type>
- <hide>part</hide>
- </param>
- <check>$start &lt;= $value &lt;= $stop</check>
- <check>$start &lt; $stop</check>
- <doc>
-This block creates a variable with a slider. \
-Leave the label blank to use the variable id as the label. \
-The value must be a real number. \
-The value must be between the start and the stop.
+ <callback>self.set_$(id)($value)</callback>
-The GUI hint can be used to position the widget within the application. \
-The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \
-Both the tab specification and the grid position are optional.
- </doc>
+ <param>
+ <name>Label</name>
+ <key>label</key>
+ <value></value>
+ <type>string</type>
+ <hide>#if $label() then 'none' else 'part'#</hide>
+ </param>
+
+ <param>
+ <name>Type</name>
+ <key>rangeType</key>
+ <value>"float"</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option><name>Float</name><key>float</key><opt>type:float</opt></option>
+ <option><name>Int</name><key>int</key><opt>type:int</opt></option>
+ </param>
+
+ <param>
+ <name>Default Value</name>
+ <key>value</key>
+ <value>50</value>
+ <type>$rangeType.type</type>
+ </param>
+
+ <param>
+ <name>Start</name>
+ <key>start</key>
+ <value>0</value>
+ <type>$rangeType.type</type>
+ </param>
+
+ <param>
+ <name>Stop</name>
+ <key>stop</key>
+ <value>100</value>
+ <type>$rangeType.type</type>
+ </param>
+
+ <param>
+ <name>Step</name>
+ <key>step</key>
+ <value>1</value>
+ <type>$rangeType.type</type>
+ </param>
+
+ <param>
+ <name>Widget</name>
+ <key>widget</key>
+ <value>counter_slider</value>
+ <type>enum</type>
+ <hide>part</hide>
+ <option><name>Counter + Slider</name><key>counter_slider</key></option>
+ <option><name>Counter</name><key>counter</key></option>
+ <option><name>Slider</name><key>slider</key></option>
+ <option><name>Knob</name><key>dial</key></option>
+ </param>
+
+ <param>
+ <name>Orientation</name>
+ <key>orient</key>
+ <value>Qt.Horizontal</value>
+ <type>enum</type>
+ <hide>#if $widget() == "slider" then 'part' else 'all'#</hide>
+ <option>
+ <name>Horizontal</name>
+ <key>Qt.Horizontal</key>
+ <opt>scalepos:BottomScale</opt>
+ <opt>minfcn:setMinimumWidth</opt>
+ </option>
+ <option>
+ <name>Vertical</name>
+ <key>Qt.Vertical</key>
+ <opt>scalepos:LeftScale</opt>
+ <opt>minfcn:setMinimumHeight</opt>
+ </option>
+ </param>
+
+ <param>
+ <name>Minimum Length</name>
+ <key>min_len</key>
+ <value>200</value>
+ <type>int</type>
+ <hide>part</hide>
+ </param>
+ <!-- from min_len <hide>#if $widget().split('_')[0] in ("slider", "counter") then 'part' else 'all'#</hide>-->
+
+ <param>
+ <name>GUI Hint</name>
+ <key>gui_hint</key>
+ <value></value>
+ <type>gui_hint</type>
+ <hide>part</hide>
+ </param>
+
+ <check>$start &lt;= $value &lt;= $stop</check>
+ <check>$start &lt; $stop</check>
+
+ <doc>
+ This block creates a variable with a slider. \
+ Leave the label blank to use the variable id as the label. \
+ The value must be a real number. \
+ The value must be between the start and the stop.
+
+ The GUI hint can be used to position the widget within the application. \
+ The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \
+ Both the tab specification and the grid position are optional.
+ </doc>
</block>
diff --git a/gr-qtgui/python/qtgui/range.py b/gr-qtgui/python/qtgui/range.py
index 168e6662c3..3eafc9002e 100755
--- a/gr-qtgui/python/qtgui/range.py
+++ b/gr-qtgui/python/qtgui/range.py
@@ -64,13 +64,16 @@ class Range(object):
class RangeWidget(QtGui.QWidget):
- def __init__(self, ranges, slot, label, style):
+ def __init__(self, ranges, slot, label, style, rangeType=float):
""" Creates the QT Range widget """
QtGui.QWidget.__init__(self)
self.range = ranges
self.style = style
+ # rangeType tells the block how to return the value as a standard
+ self.rangeType = rangeType
+
# Top-block function to call when any value changes
# Some widgets call this directly when their value changes.
# Others have intermediate functions to map the value into the right range.
@@ -81,24 +84,26 @@ class RangeWidget(QtGui.QWidget):
layout.addWidget(label)
if style == "dial":
- self.d_widget = self.Dial(self, self.range, self.notifyChanged)
+ self.d_widget = self.Dial(self, self.range, self.notifyChanged, rangeType)
elif style == "slider":
- self.d_widget = self.Slider(self, self.range, self.notifyChanged)
+ self.d_widget = self.Slider(self, self.range, self.notifyChanged, rangeType)
elif style == "counter":
# The counter widget can be directly wired to the notifyChanged slot
- self.d_widget = self.Counter(self, self.range, self.notifyChanged)
+ self.d_widget = self.Counter(self, self.range, self.notifyChanged, rangeType)
else:
# The CounterSlider needs its own internal handlers before calling notifyChanged
- self.d_widget = self.CounterSlider(self, self.range, self.notifyChanged)
+ self.d_widget = self.CounterSlider(self, self.range, self.notifyChanged, rangeType)
layout.addWidget(self.d_widget)
self.setLayout(layout)
class Dial(QtGui.QDial):
""" Creates the range using a dial """
- def __init__(self, parent, ranges, slot):
+ def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QDial.__init__(self, parent)
+ self.rangeType = rangeType
+
# Setup the dial
self.setRange(0, ranges.nsteps-1)
self.setSingleStep(1)
@@ -116,13 +121,15 @@ class RangeWidget(QtGui.QWidget):
def changed(self, value):
""" Handles maping the value to the right range before calling the slot. """
val = self.range.map_range(value)
- self.notifyChanged(val)
+ self.notifyChanged(self.rangeType(val))
class Slider(QtGui.QSlider):
""" Creates the range using a slider """
- def __init__(self, parent, ranges, slot):
+ def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QSlider.__init__(self, QtCore.Qt.Horizontal, parent)
+ self.rangeType = rangeType
+
# Setup the slider
#self.setFocusPolicy(QtCore.Qt.NoFocus)
self.setRange(0, ranges.nsteps - 1)
@@ -149,7 +156,7 @@ class RangeWidget(QtGui.QWidget):
def changed(self, value):
""" Handle the valueChanged signal and map the value into the correct range """
val = self.range.map_range(value)
- self.notifyChanged(val)
+ self.notifyChanged(self.rangeType(val))
def mousePressEvent(self, event):
if((event.button() == QtCore.Qt.LeftButton)):
@@ -168,9 +175,11 @@ class RangeWidget(QtGui.QWidget):
class Counter(QtGui.QDoubleSpinBox):
""" Creates the range using a counter """
- def __init__(self, parent, ranges, slot):
+ def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QDoubleSpinBox.__init__(self, parent)
+ self.rangeType = rangeType
+
# Setup the counter
self.setRange(ranges.min, ranges.max)
self.setValue(ranges.default)
@@ -179,18 +188,25 @@ class RangeWidget(QtGui.QWidget):
self.setDecimals(ranges.precision)
# The counter already handles floats and can be connected directly.
- self.valueChanged.connect(slot)
+ self.valueChanged.connect(self.changed)
+ self.notifyChanged = slot
+
+ def changed(self, value):
+ """ Handle the valueChanged signal by converting to the right type """
+ self.notifyChanged(self.rangeType(value))
class CounterSlider(QtGui.QWidget):
""" Creates the range using a counter and slider """
- def __init__(self, parent, ranges, slot):
+ def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QWidget.__init__(self, parent)
+ self.rangeType = rangeType
+
# Slot to call in the parent
self.notifyChanged = slot
- self.slider = RangeWidget.Slider(parent, ranges, self.sliderChanged)
- self.counter = RangeWidget.Counter(parent, ranges, self.counterChanged)
+ self.slider = RangeWidget.Slider(parent, ranges, self.sliderChanged, rangeType)
+ self.counter = RangeWidget.Counter(parent, ranges, self.counterChanged, rangeType)
# Need another horizontal layout to wrap the other widgets.
layout = Qt.QHBoxLayout()
@@ -207,8 +223,8 @@ class RangeWidget(QtGui.QWidget):
# If the counter was changed, ignore any of these events
if not self.ignoreSlider:
# Value is already float. Just set the counter
- self.counter.setValue(value)
- self.notifyChanged(value)
+ self.counter.setValue(self.rangeType(value))
+ self.notifyChanged(self.rangeType(value))
self.ignoreSlider = False
def counterChanged(self, value):
@@ -223,4 +239,21 @@ class RangeWidget(QtGui.QWidget):
self.ignoreSlider = True
self.slider.setValue(new)
- self.notifyChanged(value)
+ self.notifyChanged(self.rangeType(value))
+
+
+if __name__ == "__main__":
+ from PyQt4 import Qt
+ import sys
+
+ def valueChanged(frequency):
+ print("Value updated - " + str(frequency))
+
+ app = Qt.QApplication(sys.argv)
+ widget = RangeWidget(Range(0, 100, 10, 1, 100), valueChanged, "Test", "counter_slider", int)
+
+ widget.show()
+ widget.setWindowTitle("Test Qt Range")
+ app.exec_()
+
+ widget = None
diff --git a/grc/scripts/gnuradio-companion b/grc/scripts/gnuradio-companion
index 7a407eaaf8..b8b960a91e 100755
--- a/grc/scripts/gnuradio-companion
+++ b/grc/scripts/gnuradio-companion
@@ -55,6 +55,14 @@ def show_gtk_error_dialog(title, message):
d.run()
+def check_gtk_init():
+ try:
+ gtk.init_check()
+ except RuntimeError:
+ print 'GTK initialization failed - bailing'
+ exit(-1)
+
+
def check_gnuradio_import():
try:
from gnuradio import gr
@@ -108,6 +116,7 @@ def main():
if __name__ == '__main__':
+ check_gtk_init()
check_gnuradio_import()
ensure_blocks_path()
main()