GUI and Features Update July 2016

The LimeSDR campaign ended successfully! It was my first time directly participating in a crown-funded campaign. Keeping up with the demos, blogs, emails, and forums was a challenge; but it was worth it. Various ideas, suggestions, and bugs came up along the way, and now that the campaign is over, I can re-focus on Pothos. This blog covers some of the recent additions:

GUI reload

Its now possible to reload the plugin modules while the GUI is running. This should allow developers to fix, build, and re-install their blocks without closing and opening the GUI after every re-install. Reloading involves tearing down the GUI's evaluator, the scratch process, and any old handles kept around. The resulting operation is fairly transparent to the user other than the graphical widgets blinking out during the reload.

The Qt Caveat

We can reload the plugin modules in the scratch process or any other process other than the GUI. This means that developers cannot take advantage of the reload capability for graphical widgets or blocks located in the GUI affinity zone. But this wasn't for lack of trying. I had the GUI code setup to unload the modules in the reload hook... With proper cleanup and a sprinkle of Pothos::init() and Pothos::deinit() -- thats all it takes.

However, it turns out that there is a pretty disastrous Qt issue. Qt's QMetaType can't handle plugin unloading. Once registered, types are forever associated with the first address they were loaded under. So any type used within the QMetaType system cant be used once the module is reloaded. This causes the plotters toolkit, Qwt, and possible other widgets to segfault.

Widget state

Graphical widget blocks now have hooks to save and reload their widget state. Since the widget state exists outside of the block's parameters, its desirable to have some way to store and reload these settings with the rest of the topology. Besides restoring the state after closing and re-opening the GUI, this is also very useful for the new plugin reload feature; enabling widgets to maintain their state across reloads as well.

Whats a widget state?

The widget state is a set of values that configure the widget's appearance. For a slider, this is the slider position. For a plotter, this is enabled display channels and zoom level. And for the purposed graphical filter design block, which is now possible thanks to new state hooks, this state could be the position that the filter curves were dragged.

The state hooks

The state hooks are simply two public slots saveState() and restoreState() that operate on a QVariant type. We choose QVariant because its a known Qt type that can store many different internal data types, and it supports serialization. Pothos::Object could have also been an option, but QVariant felt more fitting since we are already in Qt space.

Class MyWidget
{

...etc...

public slots:

    QVariant saveState(void) const
    {
        //store widget state into a data type
        return int, float, string, list, map...
    }

    void restoreState(const QVariant &state)
    {
        auto value state.toInt, Float, String, List, Map...
        //apply the value to the widget
    }
};

New widgets

Qwt widgets

I have had it on my TODO list for some time now. We use Qwt pretty heavily for the plotters, but it also has some pretty nice widgets. The Slider and Thermo support linear entry and display while the the Knob and Dial support rotational entry and display. The widgets support optional log scaling, configurable axis scales, and colors.

The odometer

The odometer is a user-contributed widget from @pavel-demin's MiniTRX project. It controls an integer value with individual click regions or scrolling of each widget. Great for frequency entry!

JSON export

Its now possible to export graphically designed topologies to a simple JSON format that can be executed on the command line. This feature will enable developers to design in the GUI and deploy designs in embedded, headless, or server type environments. In addition, it may be easier to run exported designs in debuggers like gdb.

The exported topology can be run on the command line like so:

PothosUtil --run-topology=my_design.json

Its also possible to modify global variables from the design:

PothosUtil --run-topology=my_design.json --var=ampl:0.5

SDR thread

I finally finished off the SDR Block's threading options! The calling mode allows users to background setting calls to avoid blocking. The backgrounding is particularly useful for the GUI as some hardware can have lengthy call times (I should admit that the GUI could handle this better with a better evaluator implementation). And the backgrounding can be set to block when the topology is activated or to throw if not ready.

Problems solved

Prior to the the calling mode options, the SDR blocks would always background and throw in activate() when not ready -- which would cause hand-written designs and JSON exported designs to throw since all of the calls would background and the topology would be immediately committed. Also if an active design was reloaded while running, it would also throw for the same reason. So now the default mode for the SDR blocks is blocking calls, and in the GUI the default mode is to background, but to block in activate.

Event squashing

Event squashing is a threading option that can discard intermediate events. Suppose you have a slider controlling the frequency of the SDR. Dragging that slider will cause more setter events than the device can keep up with. You might have to wait to get your final setting applied while all of the undesired intermediate events are processed. Event squashing throws out all events but the most recent for a given setting. Even for fast devices, this can make a noticeable difference. Event squashing is currently disabled by default in case it might cause some unintended side-effects.

Last edited: Mon, Jul 11 2016 - 05:05AM