Using Meshtastic in GNURadio

Hi,

I’m trying to create a GNURadio Receive block that receives a message from a LORA radio connected via laptop using Meshtastic and pubsub. I keep getting the following error and I’m unsure why:
ERROR:root:Unexpected error in deferred execution <class ‘pubsub.core.topicargspec.SenderUnknownMsgDataError’>
Traceback (most recent call last):
File “/home/mylaptop/.local/lib/python3.10/site-packages/meshtastic/util.py”, line 214, in _run
o()
File “/home/mylaptop/.local/lib/python3.10/site-packages/meshtastic/mesh_interface.py”, line 751, in
publishingThread.queueWork(lambda: pub.sendMessage(
File “/home/mylaptop/.local/lib/python3.10/site-packages/pubsub/core/publisher.py”, line 216, in sendMessage
topicObj.publish(**msgData)
File “/home/mylaptop/.local/lib/python3.10/site-packages/pubsub/core/topicobj.py”, line 433, in publish
self._getListenerSpec().check(msgData)
File “/home/mylaptop/.local/lib/python3.10/site-packages/pubsub/core/topicargspec.py”, line 229, in check
raise SenderUnknownMsgDataError(self.topicNameTuple,
pubsub.core.topicargspec.SenderUnknownMsgDataError: Some optional args unknown in call to sendMessage(‘(‘meshtastic’, ‘receive’, ‘text’)’, packet,interface): packet

Below is GNURadio embedded Python block code:

import numpy as np
import pmt
import time
import meshtastic
import meshtastic.serial_interface
from pubsub import pub
from gnuradio import gr

class blk(gr.sync_block): # other base classes are basic_block, decim_block, interp_block
“”“Embedded Python Block example -”“”

def __init__(self):  # only default arguments here
    """arguments to this function show up as parameters in GRC"""
    gr.sync_block.__init__(
        self,
        name='Meshtastic LORA RX',   # will show up in GRC
        in_sig=[np.complex64],
        out_sig=[np.complex64]
    )
    # if an attribute with the same name as a parameter is found,
    # a callback is registered (properties work, too).
    
    self.portName = 'messageOutput'
    self.message_port_register_out(pmt.intern(self.portName))
    
def onReceive(packet,interface): # called when a packet arrives   
    msg = f"{packet['decoded']['text']}"
    #print(f"\nMessage: {packet['decoded']['text']}\n")
    if msg:
        print("Message: ", msg)
        PMT_msg = pmt.intern(msg)
        self.message_port_pub(pmt.intern(self.portName), PMT_msg)


def onConnection(interface, topic=pub.AUTO_TOPIC): # called when we (re)connect to the radio
# defaults to broadcast, specify a destination ID if you wish
    self.interface.sendText("hello mesh")

def work(self, input_items, output_items):
    """example: multiply with constant"""
    self.interface = meshtastic.serial_interface.SerialInterface()
    pub.subscribe(self.onReceive, "meshtastic.receive.text")
    #pub.subscribe(self.onConnection, "meshtastic.connection.established")
    self.interface.close()        
    
    output_items[0][:] = input_items[0] 
    return len(output_items[0])

The code structure seems to work fine in a separate Python script but it doesn’t seem to like it when I port it over to GNURadio. Any ideas? Can we use pubsub in GNURadio? Thanks.

1 Like

Since the normal Python script works, you might have better luck when asking whether you can use pubsub on the GNURadio forums. It seems that GNURadio has its own pubsub using ZeroMQ.
Would be nice to get it working though.

I finally got it working. You need to set it in the initialization of the block code. See below:
import numpy as np
import pmt
import time
import meshtastic
import meshtastic.serial_interface
from pubsub import pub
from gnuradio import gr

class blk(gr.sync_block): # other base classes are basic_block, decim_block, interp_block
def init(self):
gr.sync_block.init(
self,
name=‘Meshtastic LORA RX’,
in_sig=None,
out_sig=None
)
self.portName = ‘messageOutput’
self.message_port_register_out(pmt.intern(self.portName))
self.interface = meshtastic.serial_interface.SerialInterface()
pub.subscribe(self.onReceive, “meshtastic.receive.text”)

def __del__(self):
    self.interface.close()

def onReceive(self, packet,interface):
    msg = f"{packet['decoded']['text']}"
    if msg:
        print("Message: ", msg)
        PMT_msg = pmt.intern(msg)
        self.message_port_pub(pmt.intern(self.portName), PMT_msg)
        #self.interface.sendText(msg)

def work(self, input_items, output_items):
    pass
    #output_items[0][:] = input_items[0] 
    #return len(output_items[0])
4 Likes