Simples case of message passing

Earlier today, I’ve posted a question on how to do frame detection and
extraction in GNU Radio (
http://gnuradio.4.n7.nabble.com/Simple-Frame-Detection-td52233.html). I
have a feeling that the best way to accomplish what I need is using the
message passing system.

But I simply can’t find an easy enough example to understand how message
passing works. So I tried to create two simple blocks in order to better
understand this system. I simply wanted a block that would receive a
stream
(not neccesarily tagged) of bytes and then post them as a message. The
other one would receive this message and then output the same stream of
bytes. I know there are message source/sink blocks that do this, but as
I
understand, they work on a previous message passing system.

My blocks were written this way:

Message writing:
message_write_b_impl::message_write_b_impl()
: gr::sync_block(“message_write_b”,
gr::io_signature::make(1, 1, sizeof(char)),
gr::io_signature::make(0, 0, 0))
{
message_port_register_out(pmt::mp(“out”));
buffer = new char[128];
counter = 0;
}

/*
 * Our virtual destructor.
 */
message_write_b_impl::~message_write_b_impl()
{
    delete[] buffer;
}

void
message_write_b_impl::send_message()
{
    pmt::pmt_t meta = pmt::make_dict();
    pmt::pmt_t payload = pmt::from_long(long(buffer[counter++]));
    message_port_pub(pmt::mp("out"), pmt::cons(meta, payload));
    std::memset(buffer, 0, sizeof(buffer));
}

int
message_write_b_impl::work(int noutput_items,
                      gr_vector_const_void_star &input_items,
                      gr_vector_void_star &output_items)
{
    const char *in = (const char *) input_items[0];

    for(int i = 0; i < noutput_items; i++)
    {
        buffer[counter] = in[i];
        this->send_message();

        if(counter >= 128)
        {
            counter = 0;
        }
    }
    consume_each(noutput_items);

    return 0;
}

Message read:
message_read_b_impl::message_read_b_impl()
: gr::sync_block(“message_read_b”,
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(1, 1, sizeof(char)))
{
message_port_register_in(pmt::mp(“in”));
set_msg_handler(pmt::mp(“in”),
boost::bind(&message_read_b_impl::in_handling, this, _1));

    buffer = new char[128];
    counter = 0;
    rx_check = false;
}

/*
 * Our virtual destructor.
 */
message_read_b_impl::~message_read_b_impl()
{
    delete[] buffer;
}

void
message_read_b_impl::in_handling(pmt::pmt_t msg)
{
    if(pmt::is_integer(msg))
    {
        buffer[counter++] = char(pmt::from_long(msg));
        rx_check = true;
    }
    if(counter == 128)
    {
        counter = 0;
        rx_check = false;
    }
}

int
message_read_b_impl::work(int noutput_items,
                      gr_vector_const_void_star &input_items,
                      gr_vector_void_star &output_items)
{
    char *out = (char *) output_items[0];

    for(int i = 0; i < noutput_items; i++)
    {
        while(!rx_check);
        out[i] = buffer[i];
    }
    return noutput_items;
}

As far as I understand, this could be the simplest case to send bytes
through messages. But I feel there is something wrong, as the pmt
doesn’t
seem to have a method to deal with chars, so I have to do lots of
conversions. Still, this didn’t seem to be a reason of bigger concerns.

My python QA block simply does a message connect between their message
ports. But when I try to run the test, the tb simply freezes and I have
to
finish with ctrl+C.

Is there any easier way to implement message passing?

Thanks in advance,
Dan Franch

Hello Daniel, hi Rich,

if you actually want to pass a string as PMT, the pmt::intern(“…”) is
ok (although it has a performance penalty[0]).
If you want to simply sent byte buffers, the uniform vectors approach
would be the best (have a look at make_uvector8).

As for a simple example of message passing: I didn’t try very thoroughly
to understand your code, but it seems a bit complicated for what it
tries to achieve (which is simply sending a message when there’s stream
items available). For one, there’s message_sink / _source which already
converts from stream to message port for you; secondly, I don’t
understand your meta object at all, sorry.

I think there’s a simpler example for message sending in our guided
tutorials [1], specifically in part 5, with the chat application’s
source code here [2], but that’s python; however, C++ and python
implementations would closely resemble each other here.

Now, that example is far more general purpose – but there’s a whole
framework dedicated to processing digital signals in gr-digital. I do
recommend looking at the OFDM examples [3], but for your classical
preamble method, the test_corr_and_sync.grc[4] example is likely close
to what you want. It’s centered around digital::correlate_and_sync_cc
[5]. You’ll notice that it just passes through all samples, and whenever
it detects a preamble, adds stream tags [important concept here, 6]
denoting that estimate. The downstream PFB time sync and the costas loop
then use the time_est and the phase_est tag to synchronize to the
transmitter. Of course, you’d still have to “throw away” everything
that’s not part of a packet yourself.

With that functionality in mind, I’d like to direct your attention to
the tx_ofdm.grc example:

  1. It uses tagged streams; these are just sample streams (not message
    ports), but for blocks that do care, the GNU Radio scheduler makes sure
    that there’s always exactly one “packet” worth of items available (as
    marked by a specified tag). That’s the preferred way of dealing with
    packeted data – it lets you use all the standard blocks on items (eg.
    multiply etc), whilst still keeping the packeted structure.
  2. It uses the packet header generator [7], which takes in bytes of
    data, and generates a header for these – which will enable the
    header_payload_demux[8] to function. You’d still need a preamble and a
    correlation – but correlate_and_sync emits tags, any one of which’s
    keys you can use as trigger key for header_payload_demux.

Now, I must admit that I’m not absolutely sure where correlate_and_sync
adds its tags (ie. at the center of the detected preamble or somewhere
else), so it’s possible you’d have to account for a fixed distance.

I hope that this gives you a few useful hints.
Best regards & happy hacking,

Marcus M

PS: By the way, simple_{framer,correlator} are in the deprecated
group[10], which I guess is the reason writing documentation had had a
low priority.

[0] Strings are internalized in PMT, ie. they are hashed upon creation
and a new PMT is only
[1] https://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorials
[2]
gr-tutorial/python/chat_blocks.py at master · gnuradio/gr-tutorial · GitHub
[3]
gnuradio/gr-digital/examples/ofdm at master · gnuradio/gnuradio · GitHub
;
These files are usually installed somewhere like
/usr/share/gnuradio/examples/digital
[4]
https://github.com/gnuradio/gnuradio/blob/master/gr-digital/examples/demod/test_corr_and_sync.grc
[5]
http://gnuradio.org/doc/doxygen/classgr_1_1digital_1_1correlate__and__sync__cc.html
[6]
https://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_Programming_Topics#52-Stream-Tags
[7]
GNU Radio Manual and C++ API Reference: gr::digital::packet_headergenerator_bb Class Reference
[8]
GNU Radio Manual and C++ API Reference: gr::digital::header_payload_demux Class Reference
[10] GNU Radio Manual and C++ API Reference: Deprecated

Thank you very much for your reply.

I took a look at the examples you referred to, but the OFDM bits become
a
little bit distracting for me. Actually, in my system, I use a simple
QPSK
modulation. I already used the correlate and sync example to do some
things.
I insert a preamble using the stream mux and I used the correlate and
sync
block also. I do some synchronization with the PFB and the Costas Loop
blocks and I also do some equalization with the CMA block.

My biggest problem now lies with the an interleaver I have created. I
have
an interleaver that fills a matrix line by line and once it is full,
sends
it column by column. There is a deinterleaver that would basically the
same
thing. But if there is any delay, it will start filling the matrix
before it
should and then it scrambles the samples even further.

What I needed was something that would take this tags by the correlate
and
sync block and indicate to the deitnerleaver when to start. I have spent
the
whole weekend working on this, but I still have lots of problems.

Regards,
Dan Franch


View this message in context:
http://gnuradio.4.n7.nabble.com/Simples-case-of-message-passing-tp52238p52262.html
Sent from the GnuRadio mailing list archive at Nabble.com.