[Hackrf-dev] Software half-duplex operation via gr-osmosdr

Kevin Reid kpreid at switchb.org
Tue Jun 16 22:56:22 EDT 2015


On Jun 16, 2015, at 11:50, Gerhard Häring <gerdhaering at gmail.com> wrote:

> Hello Kevin,
> I want to use Hackrf as a FM-Transceiver. So I have built two flowcharts with gnuradio-companion, one as a receiver and one as a transmitter. If you start Gnuradio, it generates a python-file, called "top block ...py".
> This python-file can be executed manually. My next idea was to control these two files with a another python-program and switch the transceiver in this way. But this failed, because the receiver-flowchart did not stop. I must stop it by hand.
> My question: How can I combine your program with my two python-files?

I don't think you can do this fully generically, because in my testing, it was essential to destroy the source/sink blocks before stopping the flowgraph, which GRC-generated python can't be set up to do. But we can look at what would be necessary if that quirk didn't exist (and it's possible it's version- or platform-specific).

Note that the file GRC generates isn't necessarily named "top_block.py" -- you can change the generated name in GRC in the "Options" section ("ID"). Let's suppose you've named them "mytx.py" and "myrx.py".

Conveniently, GRC also puts the auto-start logic in an "if __name__ == '__main__'" block, so we can ignore it by importing. So our program will start out something like this:

    import mytx
    import myrx

What is needed to control the lifetime of a top block is simple: just don't call its .wait() or .run() right away. Instead, .start() it, then later .stop() it (and, if you intend to reuse it, .wait() it afterward).

In this case, we won't be reusing the top block, because we're using GRC and GRC doesn't do dynamic reconfigurations, but rather creating new ones. So, we conclude we have a main loop like this:

    def run_one(tb_class):
        tb = tb_class()
        tb.start()
        # do whatever you do to wait until time to switch
        tb.stop()
        tb.wait()
    
    def main():
        run_one(mytx.mytx)
        run_one(myrx.myrx)

And there you go.

However, as noted, my testing indicates this won't work without modifying the GRC output, and it's very inflexible -- for example, all state (e.g. any chosen frequency) is lost at every switch, and you pay the cost of rebuilding the flow graph.

Therefore, I would recommend a different strategy. (Well, actually, I would recommend improving gr-osmosdr so we don't have to jump through these hoops, but...)

Instead of trying to hook up two GRC-generated top blocks, put the guts of your transceiver in two _hierarchical blocks_ (this is under "Generate Options" in GRC), the TX one with an output (Pad Sink in GRC) and the RX one with an input (Pad Source). Then use a program like mine, replacing the RX null sink and the TX signal generator with your hier blocks. This allows you to build the details in GRC while still having an efficient switching strategy.

Or you can write your application in Python instead of using GRC at all.

-- 
Kevin Reid                                  <http://switchb.org/kpreid/>



More information about the HackRF-dev mailing list