FASSWG msg actions

From GNU Radio
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

msg_actions PROPOSAL

Problem

Millions of setters in GNU Radio. Some safe to call from another thread whilst general_work is running, others not. No unified scheme of communicating settings.

Approach

Harnessing the power of message passing, and using a bit of old school boost magic to put functions into STL containers, so that they can be automagically called.

Theory of operation:

  • Registering a "normal" class methods or functions as action to be executed on message won't work, because "normal" methods don't take pmt_t.
  • Define a combined converter + "normal" method: Input is pmt_t, output is void, but in between, pmt_t gets converted to the native argument type of the method
  • Define a converter function; in most case, the PMT standard converters do, e.g. pmt::to_long
  • Find a way to do something like a lambda without breaking with old Boost / C++-pre-0x
  • Registry can then be of function(al)s that are void action(pmt_t)
  • Registry has std::vector of actions to be taken upon a specific key

Implementation so far

basic_block::register_msg_action(key,conv,action) method (or rather four methods, including three convenience wrappers):

  • register_msg_action (pmt_t key , function<ArbitraryType(pmt_t)> converter , function<void(ArbitraryType)> action )

registers an action by generating a function chain functor, and putting that in a std::vector in a std::map.

  • basic_block::trigger_actions(key, value)

triggers all actions registered for a single key

  • basic_block::process_action_msg(pmt::pair)

takes in pairs like pmt::cons(pmt::mp("interpolation"), pmt::from_long(100))

  • the boost::bind magic that GR already uses when doing register_msg_handler gets used, so (hopefully) no new dependencies or boost strangenesses.
  • the basic_block constructor now sets up a message port to which one can send such pairs, and registers process_action_msg as handler

Use Cases

  • Intrinsic: gr::blocks::repeat_impl has a non-thread-safe set_interpolation(int) method. It wants to keep that private and expose a message action. It does
boost::function action = boost::bind(&repeat_impl::set_interpolation, this, _1);@
register_msg_action(pmt::mp("interpolation"), pmt::to_long, action);
  • Extrinsic: User/GRC knows there's a multiply_const_x::set_k(float) method, but multiply_const doesn't offer a message passing interface. Instead of despairing, we now can do
boost::function action = boost::bind(&repeat_impl::set_interpolation, this, _1);
multiply_const_0->register_msg_action(pmt::mp("factor"), pmt::to_float, action);

and send pairs (key, value) to the pmt::mp("actions") msg port of the respective block

Discussion

  • How to do getters?
  • Should GR have one central settings "bus", to which blocks' setters automatically are subscribed?

Yet to do

  • drawing pretty pictures and expanding docs beyond the doxygen method docs
  • block_gateway to enable python methods to be registered. Should be relatively simple, if it weren't for swig.
  • replacing GRC's callback mechanism by something that registers a python function as action handler
  • Will require that "Variable" GRC blocks are aware of this
  • All blocks "observing" variable get their "actions" port subscribed to the variable's message_publisher

As you can see, not nearly complete, but already useful. I'm not quite sure the naming and architecture take things in the right direction, so I RFC before I PR.