Implementing Get and Set Support for Device-Specific Properties
After connecting to a device through your adaptor, users might want to view or modify
values of the properties of the device. For example, a user might adjust the value of
the Brightness
property or retrieve the current value of the
Temperature
property. (For information about how to define the
properties you want to expose to users, see Creating Device Properties.)
To receive notification from the engine when a user wants to view or modify a
property, associate a listener object with the property. The
toolbox defines two types of listener classes: get listeners that
respond to get
commands and set listeners that
respond to set
commands.
To provide support for getting and setting property values, follow this procedure:
Define a listener class of the appropriate type. The toolbox defines two abstract classes, one for get listeners and one for set listeners, from which you derive your class.
Implement the virtual function required by the class.
Associate an instance of your listener class with the property.
The following sections describe how to set up get listeners and set listeners and in your adaptor.
Setting Up Get Listeners in Your Adaptor
To receive notification from the engine when a user requests the current value of
a property using the get
command:
Define a get listener class, deriving it from the
IPropCustomGetFcn
abstract class—see Defining a Get Listener Class.Implement the
getValue()
virtual function in your listener class—see Creating the getValue() Function for Your Class.Associate an instance of your listener class with a property—see Associating Get Listeners with Properties.
Defining a Get Listener Class
Create a get listener class, deriving it from the abstract class
IPropCustomGetFcn
, as shown in the following
example.
In this example, the constructor accepts a handle to an
IAdaptor
object. Because the toolbox establishes
listeners on a per-instance basis, passing this handle can be helpful, but it is
not a requirement.
The IPropCustomGetFcn
class defines one virtual function:
the getValue()
member function. In this function, you define
how your adaptor responds when a user requests the current value of a property.
For more information about the getValue()
function, see Creating the getValue() Function for Your Class.
#include "mwadaptorimaq.h" #include "MyDeviceImaq.h" // For this example class MyDevicePropGetListener : public IPropCustomGetFcn { public: // Constructor/Destructor MyDevicePropGetListener(MyDeviceAdaptor* parent): _parent(parent) {} virtual ~MyDevicePropGetListener() {}; virtual void getValue(imaqkit::IPropInfo* propertyInfo, void* value); private: // Declare handle to parent as member data. MyDeviceAdaptor* _parent; };
Creating the getValue() Function for Your Class
When a user requests the current value of a property, the engine calls the
getValue()
function of the get listener class associated
with the property.
Your getValue()
function must accept two parameters:
void getValue(IPropInfo* propertyInfo, void* value)
propertyInfo
is a handle to anIPropInfo
object.—TheIPropInfo
class is the interface that lets you get information about the property. For example, usingIPropInfo
functions you can retrieve the property name, its storage type and its default value. This information is useful if you have a generic listener class that handles multiple properties.value
is a pointer to the location in memory where your adaptor stores the requested property value.—The engine passes this value as avoid*
. YourgetValue()
function must cast the value to the appropriate C++ data type. The following table tells which C++ data type to cast to for all property types supported by the adaptor kit.imaqkit::PropertyTypes
C++ Data Type
CHARACTER_VECTOR
char**
DOUBLE
double*
INT
int*
DOUBLE_ARRAY
imaqkit::PropertyTypes::NDoubles*
INT_ARRAY
imaqkit::PropertyTypes::NInts*
For nonscalar data types, character vectors, double arrays, and integer arrays, your listener class must allocate sufficient memory for the current property value using the
new[]
operator. The engine deletes this memory, callingdelete[]
. An example using a character vector property is:char** returnStr = reinterpret_cast<char**>(value); *returnStr = imaqkit::imaqmalloc(sizeof(char) * (stringLength)); strcpy(*returnStr, currentPropertyValueString);
Suggested Algorithm for a getValue() Function. The design of the getValue()
function varies with the
needs of your device and the facilities offered by its SDK. For example, you
could create one get listener class that handles value queries for all
properties in a particular property container (general or device-specific).
In this case, the getValue()
function includes a switch
statement with cases that handle each individual property.
Alternatively, define a separate get listener class for each property or each property storage type. Then, the engine calls the specific listener for the property specified.
You also can define get listener classes that fit the way the device SDK organizes property configuration. For example, if an SDK provides one function to configure all device properties, you can define a get listener class for these properties.
Example. This example shows an implementation of a getValue()
function for integer types:
void MyDevicePropGetListener::getValue(IPropInfo* propertyInfo, void* value) { // Get property name from the IPropInfo object. const char* propname = propertyInfo->getPropertyName(); // Get the value using whatever facility your device's SDK provides. *reinterpret_cast<const int*>(value) = sdk_function_get(); // For debug purposes only. imaqkit::adaptorWarn("In listener. Property name is %s\n",propname); }
Associating Get Listeners with Properties
To set up a listener for a property, you associate the listener object with the property in the property container. The following example shows how to add get listeners for all device-specific properties in the adaptor property container. Adaptor writers typically set up property listeners in their adaptor class constructor—see Implementing Your Adaptor Class Constructor.
Get a handle to the appropriate property container object.
The
IEngine
object has two member functions that return handles to property containers (IPropContainer
objects). The example calls theIEngine
classgetAdaptorPropContainer()
member function to get the device-specific property container:imaqkit::IPropContainer* adaptorPropContainer = getEngine()->getAdaptorPropContainer();
Add a get listener to a property in the container, using the
IPropContainer
objectsetCustomGetFcn()
function. As arguments, specify the property name and a handle to the listener object.Note
Because the toolbox deletes each instance of a listener object when a user deletes the video input object, associate a new instance of a listener object with each property.
The following example iterates through all properties in the adaptor property container, associating a get listener object with each one.
void MyDeviceAdaptor::MyDeviceAdaptor() { // get a handle to the property container IPropContainer* propContainer = getEngine()->getAdaptorPropContainer(); // Determine the number of properties in the container. int numDeviceProps = propContainer->getNumberProps(); // Retrieve the names of all the properties in the container const char **devicePropNames = new const char*[numDeviceProps]; propContainer->getPropNames(devicePropNames); // Create a variable to point to a property get listener object. MyDevicePropGetListener* getListener; // For each property in the container... for (int i = 0; i < numDeviceProps; i++){ // Create a get listener object... getListener = new MyDevicePropGetListener(this); // and associate it with a specific property. propContainer->setCustomGetFcn(devicePropNames[i], getListener); } // clean up the array of property names. delete [] devicePropNames; }
Setting Up Set Listeners in Your Adaptor
To receive notification from the engine when a user changes the value of a
property using the set
command:
Define a set listener class, deriving it from the
IPropPostSetListener
abstract class—see Defining a Set Listener Class.Implement the
notify()
virtual function in your set listener class—see Creating the notify() Function for Your Class.Associate an instance of your set listener class with the property—see Associating Set Listeners with Properties.
Defining a Set Listener Class
Create a set listener class, deriving it from the abstract class
IPropPostSetListener
, as shown in the following example.
(The name of the class includes the word Post
because the
toolbox notifies listeners after it updates the property value stored in the
container.)
In this example, the constructor accepts a handle to an
IAdaptor
object. Because the toolbox establishes
listeners on a per-instance basis, passing this handle can be helpful, but it is
not a requirement.
The IPropPostSetListener
class defines one virtual
function: the notify()
member function. In this function, you
define how your adaptor responds when a user changes the value of a property.
For more information, see Creating the notify() Function for Your Class.
#include "mwadaptorimaq.h" #include "MyDeviceImaq.h" // For this example class MyDevicePropSetListener : public IPropPostSetListener { public: // Constructor/Destructor MyDevicePropSetListener(MyDeviceAdaptor* parent): _parent(parent) {} virtual ~MyDevicePropSetListener() {}; virtual void notify(imaqkit::IEnginePropInfo* propertyInfo, void* newValue); private: // Declare handle to parent as member data MyDeviceAdaptor* _parent; // Property Information object. imaqkit::IPropInfo* _propInfo; // The new value for integer properties. int _lastIntValue; // The new value for double properties. double _lastDoubleValue; // The new value for character vector properties. char* _lastStrValue; };
Creating the notify() Function for Your Class
When a user calls the set
command to change the value of a
property, the engine calls the notify()
function of the set
listener class associated with the property.
A set listener class notify()
function must accept two
parameters:
void notify(IPropInfo* propertyInfo, void* newValue)
propertyInfo
is a handle to anIPropInfo
object—TheIPropInfo
class is the interface that lets you get information about the property. For example, usingIPropInfo
functions you can get the property name, its storage type, and its default value.newValue
is a pointer to the new property value—This engine passes this value as avoid*
. Yournotify()
function must cast the value to the appropriate C++ data type. The following table tells which C++ data type to cast to for all property types supported by the adaptor kit.imaqkit::PropertyTypes
C++ Data Type
CHARACTER_VECTOR
char*
DOUBLE
double*
INT
int*
DOUBLE_ARRAY
imaqkit::PropertyTypes::NDoubles*
INT_ARRAY
imaqkit::PropertyTypes::NInts*
Suggested Algorithm for notify() Function. The design of the notify()
function varies with the
needs of your device and the facilities offered by its SDK. For example, you
can create one set listener class that handles all value changes for all
properties in a particular property container (general or device-specific).
In this case, the notify()
function includes a switch
statement with cases that handle each individual property.
Alternatively, you could define a separate set listener class for each property or each property storage type. Then, the engine calls the specific listener for the property specified.
You also can define set listener classes that fit the way the SDK organizes property configuration. For example, if an SDK provides one function to configure all device properties, you can define a set listener class for these properties.
Example. This example shows an implementation of a notify()
function for integer types:
void MyDevicePropSetListener::notify(IPropInfo* propertyInfo, void* newValue) { // Get property name from the IPropInfo object. const char* propname = propertyInfo->getPropertyName(); // Cast newValue to the proper type newVal = *reinterpret_cast<const int*>(newValue); // ***************************************************** // Insert calls to device SDK to apply value to hardware. // ***************************************************** // For debug purposes only. imaqkit::adaptorWarn("In listener. Property name is %s\n",propname); }
Associating Set Listeners with Properties
To set up a listener for a property, you associate the listener object with the property in the property container. The following example shows how to add set listeners for all the device-specific properties in the adaptor property container. Adaptor writers typically set up property listeners in their adaptor class constructor—see Implementing Your Adaptor Class Constructor.
Get a handle to the appropriate property container object.
The
IEngine
object has two member functions that return handles to property containers (IPropContainer
objects). The example calls theIEngine
classgetAdaptorPropContainer()
member function to get the device-specific property container:imaqkit::IPropContainer* adaptorPropContainer = getEngine()->getAdaptorPropContainer();
Add a set listener to a property in the container, using the
IPropContainer
object'saddListener()
function. As arguments, specify the property name and a handle to the listener object.Note
Because the toolbox deletes each instance of a listener object when a user deletes the video input object, associate a new instance of a listener object with each property.
The following example iterates through all properties in the adaptor property container, associating a set listener object with each property:
void MyDeviceAdaptor::MyDeviceAdaptor() { // get a handle to the property container IPropContainer* propContainer = getEngine()->getAdaptorPropContainer(); // Determine the number of properties in the container. int numDeviceProps = propContainer->getNumberProps(); // Retrieve the names of all the properties in the container const char **devicePropNames = new const char*[numDeviceProps]; propContainer->getPropNames(devicePropNames); // Create a variable to point to a property listener object. MyDevicePropSetListener* setListener; // For each property in the container... for (int i = 0; i < numDeviceProps; i++){ // Create a set listener object... setListener = new MyDevicePropSetListener(this); // and associate it with a specific property. propContainer->addListener(devicePropNames[i], setListener); } // clean up the array of property names. delete [] devicePropNames; }