-
Notifications
You must be signed in to change notification settings - Fork 32
Driver Properties
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.
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
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.
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
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.
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;
}
The client libraries all have functionality to write new property values to drivers. Below are some examples of how to do so.
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;
}