We've started down the path of providing more capabilities with ControlPort. Specifically, I'd like to get us to have more blocks within the GNU Radio main source code that support configuration over ControlPort. We are going to rely heavily on ControlPort for our Android work where the Java application space will talk to and control the running GNU Radio flowgraph almost solely over ControlPort.
One of the main things missing from our ControlPort capabilities here is the ability to control the settings of a UHD device. The main reason is that the generic interface for ControlPort comes in two forms:
void setter_method(<value type> <value>);
This interface does not work for the UHD interface for most of the important parameters. For example, setting the frequency of a USRP source looks like:
tune_result_t set_center_freq(double freq, size_t chan)
So it takes two arguments and returns a data structure. This kind of thing isn't easily encompassed in ControlPort's generic interfaces.
However, instead of trying to expand the interfaces for all of these types of commands, we have one more general format interface that we can use for lots of these things, the message handler, which looks like:
void message_handler_function_name(pmt::pmt_t message);
It just makes sense to make use of these already-available message handling functions in blocks to handle setting values over ControlPort as well. So I've recently added a new interface to our ControlPort system called "postMessage". This function takes three arguments:
- alias: the block's alias in the system as a serialized PMT string.
- port: the port name of the block's message handler as a serialized PMT string.
- msg: the actual message to be passed to the message handler as a serialized PMT.
The msg PMT can be any form of a PMT that would be created especially for the type of message expected by the message handler. All of this can be easily constructed in Python or any other supported language. In fact, in Python, we use our RPCConnection abstracted interface to take these values in as a (string alias, string port, PMT message) -- internally, these are serialized and posted to ControlPort. For example, if we have a copy block that we want to enable the copy function, we would use the following postMessage to send to block named "copy0" on the enable message port "en" with a PMT True value.
radioclient.postMessage("copy0", "en", pmt.PMT_T)
Let's take a more complicated example where we are trying to change the frequency of a USRP source. First, we have to know the alias of the USRP source in the flowgraph. As an aside, I'm hoping to provide some discovery mechanisms for available handlers exported through ControlPort soon. In our case, let's assume the alias is 'usrp_source0,' and we know from the manual that it has a port named 'command' that takes a key:value pair. One command key is 'freq' to set the frequency based on a floating point value. We've already created the ControlPort radio interface, called 'radio' here, so we just need to do:
radio.postMessage('usrp_source0', 'command', pmt.cons(pmt.intern('freq'), pmt.from_double(101e6)))
The only tricky thing here is to know that the command takes a PMT pair of a string and the correct value. The pmt.cons constructs a pair with the 'freq' as the first part and a double PMT for 101 MHz. This would get posted to the USRP devices to change the channel over our remote ControlPort interface.
I have added a couple of simple examples to GNU Radio to exercise this new feature. First is the simple_copy.grc file that runs a graph that has a copy block. We can use the simple_copy_controller.py program to toggle the copy block's enable port either True or False to start and stop data flowing.
The second and more exciting example is the usrp_source_control.grc. This just runs a flowgraph where data is sourced from a USRP device and plotted in time and frequency. It is set up with a sample rate of 1 MHz, but no gain, frequency, or antenna are selected as shown below.
We expect to see nothing since we have no tuning or gain set, and in my case, there is no antenna connected to the default RX2 port. In the running flowgraph, we've provided no application controls for this like QTGUI slider or chooser widgets.
But since we have a ControlPort endpoint available on localhost port 9090, we can control it remotely. In this case, I'm using the program on the same machine and talking over the localhost interface.
I've used the usrp_source_controller.py application to issue ControlPort commands that will post a message to set the frequency, gain, antenna port, and sample rate to the USRP device allowing me to see the signal now shown above.
This new interface should prove to be quite powerful in controlling GNU Radio flowgraphs over ControlPort. It will also force us to expand the available message handling support on many blocks that we will be wanting to manipulate over ControlPort and in Android apps. The use of the message passing infrastructure also means we have a lot more flexibility in structuring our ControlPort commands.