I created a Python-based sink block that works well in most cases. I
started having problems when I created a GUI checkbox (using GRC) to
control a Selector or Valve block in a separate subgraph. As soon as I
change the checkbox, the whole graph freezes.
So far I have tracked this down to the Python sink block. I grabbed
one of the built-in blocks and build a test that demonstrates the
problem in the simplest way. The graph looks like this (there are two
separate subgraphs):
Subgraph 1:
Constant Source #1 -> Throttle -> Python test sink
Subgraph 2:
Constant Source #2 -> Selector -> Throttle -> Null sink
Constant Source #3 -> ^ (points to the selector, also)
The checkbox switches the selector between Constant Source #2 and #3.
Whenever the Python test sink is part of the upper graph, switching
the lower graph (using the checkbox) causes everything to freeze.
Debugging steps:
I ran this graph via GDB and watched threads being created/destroyed.
Whenever the checkbox is changed, a bunch of threads are killed. Iām
guessing this is GR shutting down a bunch of blocks and trying to
restart them with different connections, but something in the Python
block isnāt getting shut down, so everything stalls.
In the code below, if you replace the reference to āself.sinkā with
āself.blocks_null_sink_1ā in the connection setup, the problem goes
away.
Hereās the code:
#!/usr/bin/env python
from gnuradio import blocks
from gnuradio import gr
from gnuradio.wxgui import forms
from grc_gnuradio import blks2 as grc_blks2
from grc_gnuradio import wxgui as grc_wxgui
import numpy
import wx
class sink_test(grc_wxgui.top_block_gui):
def __init__(self):
grc_wxgui.top_block_gui.__init__(self, title="Sink Test")
self.check = check = True
##################################################
# Blocks
##################################################
self._check_check_box = forms.check_box(
parent=self.GetWin(),
value=self.check,
callback=self.set_check,
label="check",
true=True,
false=False,
)
self.Add(self._check_check_box)
self.const_source_x_0_1 = gr.sig_source_c(0, gr.GR_CONST_WAVE,
0, 0, 12)
self.const_source_x_0_0 = gr.sig_source_c(0, gr.GR_CONST_WAVE,
0, 0, 0)
self.const_source_x_0 = gr.sig_source_f(0, gr.GR_CONST_WAVE, 0,
0, 0)
self.blocks_throttle_0 = blocks.throttle(gr.sizeof_float1,
1000)
self.blocks_throttle_1 = blocks.throttle(gr.sizeof_gr_complex1,
1000)
self.blocks_null_sink_0 =
blocks.null_sink(gr.sizeof_gr_complex1)
self.blocks_null_sink_1 = blocks.null_sink(gr.sizeof_float1)
# not used by default. enable by connecting below
self.blks2_selector_0 = grc_blks2.selector(
item_size=gr.sizeof_gr_complex*1,
num_inputs=2,
num_outputs=1,
input_index=0 if check else 1,
output_index=0,
)
self.sink = test_sink()
##################################################
# Connections
##################################################
self.connect((self.const_source_x_0, 0),
(self.blocks_throttle_0, 0))
self.connect((self.blocks_throttle_0, 0), (self.sink, 0))
change this from self.sink to self.blocks_null_sink_1 to see the
problem go away
self.connect((self.const_source_x_0_0, 0),
(self.blks2_selector_0, 1))
self.connect((self.blks2_selector_0, 0),
(self.blocks_throttle_1, 0))
self.connect((self.blocks_throttle_1, 0),
(self.blocks_null_sink_0, 0))
self.connect((self.const_source_x_0_1, 0),
(self.blks2_selector_0, 0))
def get_check(self):
return self.check
def set_check(self, check):
self.check = check
self._check_check_box.set_value(self.check)
self.blks2_selector_0.set_input_index(int(0 if self.check else
1))
Python block
class test_sink(gr.sync_block):
def init(self):
gr.sync_block.init(
self,
name = ātest_sinkā,
in_sig = [numpy.float32],
out_sig = None,
)
self.key = None
def work(self, input_items, output_items):
return len(input_items[0])
if name == āmainā:
tb = sink_test()
tb.Run(True)