Skip to content
Rich edited this page Apr 8, 2017 · 1 revision

Player is normally launched with a configuration file that describes which drivers to be loaded, and provides driver-specific configuration options. Before Player 3.0 there was no way to change any of these values at run-time: when these driver-specific configuration options needed to be changed, the user was forced to shut down the Player server, edit the file, and re-launch the Player. Player now has the ability to change some of these options on the fly from client libraries using driver properties.

Table of Contents

Using Properties in Drivers

Drivers that support properties contain a lot of extra code, such as handling what to do when a property changes, doing bounds-checking on requested property changes, etc. Because of this, many of the older drivers in Player do not yet support driver properties. Even in drivers that do support properties, some of the configuration file options may not be implemented as properties depending on whether that value is even able to be changed at run-time. To implement properties in your driver, you first must decide which configuration options are most useful to be adjusted at runtime, and determine whether or not you will actually be able to change them without shutting the driver down.

There are four kinds of properties that can be used in Player drivers:

  • IntProperty
  • DoubleProperty
  • BoolProperty
  • StringProperty
To use one of these property types, the value should be declared as a member of the Driver's class, like so:
class ExampleDriver : public ThreadedDriver
{
  public:

    // Constructor; need that
    ExampleDriver(ConfigFile* cf, int section);

    // This method will be invoked on each incoming message
    virtual int ProcessMessage(QueuePointer &resp_queue,
                               player_msghdr * hdr,
                               void * data);

  private:

    // Main function for device thread.
    virtual void Main();
    virtual int MainSetup();
    virtual void MainQuit();

    // Driver Properties
    BoolProperty foo;
    IntProperty  bar;
}

This particular driver now has two properties: foo (a boolean), and bar (an int). Before these properties can be used by the driver, they need to be initialized and registered. This is handled in the driver's constructor, like so:

ExampleDriver::ExampleDriver(ConfigFile* cf, int section)
    : ThreadedDriver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_POSITION2D_CODE),
      foo("foo", DEFAULT_FOO, false),
      bar("bar", DEFAULT_BAR, false)
{
  // Register the properties and link them to the configuration file options
  RegisterProperty ("foo", &foo, cf, section);
  RegisterProperty ("bar", &bar, cf, section);

  return;
}

The above code initiailzes both properties to pre-defined default values, which are declared somewhere else in the code. These defaults should correspond to the default values desired should the option be absent form the configuration file. The last boolean in the initialization is a "readonly" flag. If this is set to true, the property cannot be changed during runtime, but its value can be queried by client libraries. The RegisterProperty function will read the config file value described by the first argument into the property passed as the second argument.

Now that the driver is using properties foo and bar, it should be able to handle requests from clients to change the values of foo and bar. Player handles requests to get and set the properties transparently, and will update non readonly properties accordingly when a property change request comes to the driver. However, there may be cases when you'd like to do something special when a property change comes in, such as restart a serial port. In these cases, you may add your own property handlers to the driver's ProcessMessage function, like so:

int ExampleDriver::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr, void * data)
{
    if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, PLAYER_SET_INTPROP_REQ, this->device_addr))
    {
        player_intprop_req_t *req = reinterpret_cast<player_intprop_req_t*> (data);
        // Property "foo" needs to be changed
        if (strncmp (req->key, "foo", 3) == 0)
        {
            // Handle a change in "foo"
        }
    }
    // Other message handlers...
}

Any property requests that aren't handled explicitly by your driver will fall through to Player's default property handling routines.

Using Properties in Client programs

playerprop utility

Player comes with a command-line utility called playerprop, with the following usage:

Usage: playerprop -d <device> [-i <index> -h <host> -p <port>] <command> <args>

Commands:
getbool <prop name>         Get a boolean property
getint <prop name>          Get an interger property
getdbl <prop name>          Get a double property
getstr <prop name>          Get a string property
setbool <prop name> <value> Set a boolean property
setint <prop name> <value>  Set an interger property
setdbl <prop name> <value>  Set a double property
setstr <prop name> <value>  Set a string property

This utility can be used to query and set properties manually from the command line

Getting property values

The client libraries all have functionality to read property values from individual drivers. Below are some examples of how to do so from different client libraries.

libplayerc++

The libplayerc++ ClientProxy class contains the methods GetBoolProp, GetDblProp, GetIntProp, and GetStrProp to query each of the four types of property values. Each of these functions will return 0 on success, and non-zero if the specified property was unable to be read.

#include <iostream>
include <libplayerc++/playerc++.h>
int main(int argc, char *argv[])
{
  using namespace PlayerCc;
 
  PlayerClient    robot("localhost");
  Position2dProxy pp(&robot,0);
 
  bool fooval; 
  if(pp.GetBoolProp("foo", &fooval) == 0)
    std::cout << "Property foo has a value of: " << fooval << std::endl;
}

Setting new property values

The client libraries all have functionality to write new property values to drivers. Below are some examples of how to do so.

libplayerc++

The libplayerc++ ClientProxy class contains the methods SetBoolProp, SetDblProp, SetIntProp, and SetStrProp to query each of the four types of property values. Each of these functions will return 0 on success, and non-zero if the specified property was unable to be written.

#include <iostream>
include <libplayerc++/playerc++.h>
int main(int argc, char *argv[])
{
  using namespace PlayerCc;
 
  PlayerClient    robot("localhost");
  Position2dProxy pp(&robot,0);
 
  if(pp.SetIntProp("bar", 10) == 0)
    std::cout << "Property bar set to 10" << std::endl;
}