Difference between revisions of "Breaking the Ice"

From MyLabWiki
Jump to: navigation, search
(Reading values.)
(Write values)
 
(One intermediate revision by the same user not shown)
Line 155: Line 155:
 
       ::GNURadio::KnobPtr max;
 
       ::GNURadio::KnobPtr max;
 
       ::GNURadio::KnobPtr defaultvalue;
 
       ::GNURadio::KnobPtr defaultvalue;
 
 
 
       ...
 
       ...
 
   };
 
   };
Line 161: Line 160:
 
plus a bunch of relational operators and __read() / __write() methods that AFAIK we are not supposed to use.
 
plus a bunch of relational operators and __read() / __write() methods that AFAIK we are not supposed to use.
  
The properties contain static information only and not the actual value of a knob. To read and write values we must retrieve the KnobMap cast individual knobs to a typed knob and use the value field. In the following example we assume that there is a knob of integer type and a knob of type double:
+
The properties contain only static information and not the actual value of a knob.  
 +
 
 +
== Read and write values ==
 +
 
 +
To read and write values we must retrieve the KnobMap and then cast the individual knobs to a typed knob and use the value field. In the following example we assume that there is a knob of integer type and a knob of type double:
  
 
   ...
 
   ...
Line 168: Line 171:
 
   GNURadio::KnobIPtr    knobi;
 
   GNURadio::KnobIPtr    knobi;
 
   GNURadio::KnobDPtr    knobd;
 
   GNURadio::KnobDPtr    knobd;
 
+
 
 
   knob_map = ctrlport->get(empty_list);
 
   knob_map = ctrlport->get(empty_list);
 
+
 
 
   // get integer value
 
   // get integer value
 
   knob = knob["key_to_int"];
 
   knob = knob["key_to_int"];
 
   knobi = static_cast<KnobIPtr>(knob);
 
   knobi = static_cast<KnobIPtr>(knob);
 
   std::cout << "Int value: " << knobi->value << std::endl;
 
   std::cout << "Int value: " << knobi->value << std::endl;
 
+
 
 
   // get double value
 
   // get double value
 
   knob = knob["key_to_double"];
 
   knob = knob["key_to_double"];
 
   knobd = static_cast<KnobDPtr>(knob);
 
   knobd = static_cast<KnobDPtr>(knob);
 
   std::cout << "Double value: " << knobd->value << std::endl;
 
   std::cout << "Double value: " << knobd->value << std::endl;
 +
 +
Writing is similar to reading. Since we only used pointers above, modifying knobd->value will also modify the value stored in the knob_map:
 +
 +
  knob_map.erase("flowgraph0::max nouptut_items");  // this is read only and would give an error if we tried to write
 +
  knobd->value = 20.0;
 +
  ctrlport->set(knob_map);
  
  
 
[[Category:GNU Radio]]
 
[[Category:GNU Radio]]

Latest revision as of 21:16, 5 April 2013

My notes taken while I was creating a custom client to a gr-ctrlport enabled flow graph.

Enable gr-ctrlport

Add to ~/.gnuradio/config.conf

 [ControlPort]
 on = True
 edges_list = False
 config = /home/directory/.gnuradio/ctrlport.conf

Next, create ~/.gnuradio/ctrlport.conf (based on PREFIX/etc/gnuradio/ctrlport.conf.example):

 ControlPort.Endpoints = tcp -t 300 -h 127.0.0.1 -p 43243

Test that gr-ctrlport is working properly by running the gr-blocks/examples/ctrlport/pfb_sync_test-qt.grc application in the source tree and the PREFIX/bin/gr-ctrlport-monitor python application (started automatically by pfb_sync_test-qt).

Hello gr-ctrlport

The Ice Manual contains a Hello World application that we can use as template. Read that chapter and try the example.

Translate gnuradio-runtime/lib/gnuradio.ice to C++ code:

 $ slice2cpp gnuradio.ice

This will generate a gnuradio.h and gnuradio.cpp file.

Create a client.cpp file that can connect to gnuradio:

 #include <Ice/Ice.h>
 #include <gnuradio.h>
 
 using namespace std;
 using namespace GNURadio;
 
 int main(int argc, char* argv[])
 {
     int status = 0;
     Ice::CommunicatorPtr ic;
       
     try
     {
         ic = Ice::initialize(argc, argv);
         Ice::ObjectPrx base = ic->stringToProxy("gnuradio:tcp -h localhost -p 43243");
 
         ControlPortPrx ctrlport = ControlPortPrx::checkedCast(base);
 
         if (!ctrlport)
             throw "Invalid proxy";
 
     }
     catch (const Ice::Exception& ex)
     {
         cerr << ex << endl;
         status = 1;
     }
     catch (const char* msg)
     {
         cerr << msg << endl;
         status = 1;
     }
 
     if (ic)
         ic->destroy();
 
     return status;
 }

The above code will do nothing except establish a connection.

You can put the code below into a script for easy compilation of the client.cpp:

 c++ -fpermissive -I. -I$ICE_HOME/include -c gnuradio.cpp client.cpp
 c++ -o client gnuradio.o client.o -L$ICE_HOME/lib -lIce -lIceUtil

The -fpermissive flag is necessary because we will be casting from base classes to derived classes.

Get list of parameters (aka. knobs)

Reverse engineered from gnuradio.h

We can use ControlPortPrx::properties to get a list of knobs and their properties:

 class ControlPort : virtual public ::Ice::Object
 {
 public:
     ...
     virtual ::GNURadio::KnobPropMap properties(const ::GNURadio::KnobIDList&, const ::Ice::Current& = ::Ice::Current()) = 0;

We ignore Ice::Current for now. The other GNURadio types are defined as:

 typedef ::std::vector< ::std::string> KnobIDList;
 typedef ::std::map< ::std::string, ::GNURadio::KnobProp> KnobPropMap;

If we use an empty KnobIDList we will get a map containing all exported knobs. The following client.cpp update fetches this list and prints map key represented by the string:

 #include <Ice/Ice.h>
 #include <gnuradio.h>
 
 using namespace std;
 using namespace GNURadio;
 
 int main(int argc, char* argv[])
 {
     int status = 0;
     Ice::CommunicatorPtr ic;
 
     GNURadio::KnobIDList   empty_list;  // vector<string>
     GNURadio::KnobPropMap  knob_props;  // map<string, GNURadio::KnobProp>
       
     try
     {
         // Get proxy object
         ic = Ice::initialize(argc, argv);
         Ice::ObjectPrx base = ic->stringToProxy("gnuradio:tcp -h localhost -p 43243");
         ControlPortPrx ctrlport = ControlPortPrx::checkedCast(base);
 
         if (!ctrlport)
             throw "Invalid proxy";
 
         // Get list of knobs
         knob_props = ctrlport->properties(empty_list);
         cout << "Exported knobs: " << knob_props.size() << endl;
 
         for (KnobPropMap::iterator it = knob_props.begin(); it != knob_props.end(); ++it)
             cout << "  " << it->first << endl;
 
     }
     catch (const Ice::Exception& ex)
     {
         cerr << ex << endl;
         status = 1;
     }
     catch (const char* msg)
     {
         cerr << msg << endl;
         status = 1;
     }
 
     if (ic)
         ic->destroy();
 
     return status;
 }

Knob properties are available in GNURadio::KnobProp. This is a struct with the following fields:

 struct KnobProp
 {
     ::GNURadio::KnobType type;
     ::std::string units;
     ::std::string description;
     ::Ice::Int display;
     ::GNURadio::KnobPtr min;
     ::GNURadio::KnobPtr max;
     ::GNURadio::KnobPtr defaultvalue;
     ...
 };

plus a bunch of relational operators and __read() / __write() methods that AFAIK we are not supposed to use.

The properties contain only static information and not the actual value of a knob.

Read and write values

To read and write values we must retrieve the KnobMap and then cast the individual knobs to a typed knob and use the value field. In the following example we assume that there is a knob of integer type and a knob of type double:

 ...
 GNURadio::KnobMap      knob_map;    // map<string, GNURadio::KnobPtr>
 GNURadio::KnobPtr      knob;
 GNURadio::KnobIPtr     knobi;
 GNURadio::KnobDPtr     knobd;
 
 knob_map = ctrlport->get(empty_list);
 
 // get integer value
 knob = knob["key_to_int"];
 knobi = static_cast<KnobIPtr>(knob);
 std::cout << "Int value: " << knobi->value << std::endl;
 
 // get double value
 knob = knob["key_to_double"];
 knobd = static_cast<KnobDPtr>(knob);
 std::cout << "Double value: " << knobd->value << std::endl;

Writing is similar to reading. Since we only used pointers above, modifying knobd->value will also modify the value stored in the knob_map:

 knob_map.erase("flowgraph0::max nouptut_items");   // this is read only and would give an error if we tried to write
 knobd->value = 20.0;
 ctrlport->set(knob_map);