Impact Acquire SDK C++
Callback.cpp

The Callback example is meant to show how to register a custom callback function to a property or feature in Impact Acquire.

Program location
The source file Callback.cpp can be found under:
%INSTALLDIR%\apps\Callback\
Note
If you have installed the package without example applications, this file will not be available. On Windows® the sample application can be installed or removed from the target system at any time by simply restarting the installation package.
Callback example:
  1. Opens a Balluff device.
  2. Shows custom callbacks.
Console Output
[0]: GX001559 (mvBlueCOUGAR-X122G, Family: mvBlueCOUGAR, interface layout: DeviceSpecific)
[1]: BF000306 (mvBlueFOX-202C, Family: mvBlueFOX, interface layout: DeviceSpecific)

Please enter the number in front of the listed device followed by [ENTER] to open it: 1
Using device number 1.
Initialising the device. This might take some time...
=== List of records BEFORE callbacks ===
This record is called 'The number of the Beast' and since creation it has been played 0 times.
This record is called 'Holy Diver' and since creation it has been played 0 times.
This record is called 'Master of Reality' and since creation it has been played 0 times.
Component 'ImageRequestTimeout_ms' did just cause a callback. It's the 1 time this function got called.
This callback carries 3 good old vinyl records with it.
  There is a record called 'The number of the Beast'
  There is a record called 'Holy Diver', which I will play now
  There is a record called 'Master of Reality'
Component 'ImageRequestTimeout_ms' did just cause a callback. It's the 2 time this function got called.
This callback carries 3 good old vinyl records with it.
  There is a record called 'The number of the Beast'
  There is a record called 'Holy Diver'
  There is a record called 'Master of Reality', which I will play now
Component 'RequestCount' did just cause a callback. It's the 3 time this function got called.
This callback carries 3 good old vinyl records with it.
  There is a record called 'The number of the Beast', which I will play now
  There is a record called 'Holy Diver'
  There is a record called 'Master of Reality'
...
How it works

After getting the device from user input the sample tries to

  1. open the device by calling
    pDev->open();
  2. Attach a custom callback to some driver properties that get called whenever a property is modified.
  3. Modify these properties in order to cause the callbacks to be called.

But now step by step through the source:

Any application that wants to get notified when a certain feature in the Impact Acquire property tree did change needs to derive a class from mvIMPACT::acquire::ComponentCallback and override the mvIMPACT::acquire::ComponentCallback::execute() method:

//-----------------------------------------------------------------------------
class MyCallback : public ComponentCallback
//-----------------------------------------------------------------------------
{
unsigned int hitCount_;
public:
explicit MyCallback( void* pUserData = 0 ) : ComponentCallback( pUserData ),
hitCount_( 0 ) {}
// Please carefully read the documentation of the base class (mvIMPACT::acquire::ComponentCallback) and the documentation of the
// mvIMPACT::acquire::ComponentCallback::execute function in particular to avoid unpleasant surprises!
virtual void execute( Component& c, void* pUserData )
{
// get access to the user data previously associated with the component that just executes the callback
RecordStack* pRecordStack = reinterpret_cast<RecordStack*>( pUserData );
// do some work with the user data object
const RecordStack::size_type recordCount = pRecordStack->size();
cout << "Component '" << c.name() << "' did just cause a callback. It's the " << ++hitCount_ << " time this function got called." << endl
<< "This callback carries " << recordCount << " good old vinyl records with it." << endl;
RecordStack::const_iterator it = pRecordStack->begin();
const RecordStack::const_iterator itEND = pRecordStack->end();
unsigned int i = 0;
while( it != itEND )
{
cout << " There is a record called '" << ( *it )->getAlbum() << "'";
if( hitCount_ % recordCount == i )
{
cout << ", which I will play now";
( *it )->play();
}
cout << endl;
++it;
++i;
}
}
};

In order to be able to do something useful each callback can carry a pointer to arbitrary user data that can be used to get access to any part of the application code within the callback context. This example attaches an instance of the class VinylRecord when creating the callback handler later.

Now within the actual application first of all a device handle must be obtained. In this sample the user is prompted to select the device he wants to use:

DeviceManager devMgr;
Device* pDev = getDeviceFromUserInput( devMgr );

The function getDeviceFromUserInput() is included via

#include <apps/Common/exampleHelper.h>

Afterwards some interface classes are created in order to get access to some driver properties that shall get a callback attached to.

BasicDeviceSettings bds( pDev );
SystemSettings ss( pDev );

Now some objects that will serve as dummy user data for the callback will be created:

vector<VinylRecord*> vinylRecords;
vinylRecords.push_back( new VinylRecord( "The number of the Beast" ) );
vinylRecords.push_back( new VinylRecord( "Holy Diver" ) );
vinylRecords.push_back( new VinylRecord( "Master of Reality" ) );

Now the actual callback handler will be created and 2 properties will be registered to it:

MyCallback myCallback( &vinylRecords );
// attach the callback to some features
myCallback.registerComponent( bds.imageRequestTimeout_ms );
myCallback.registerComponent( ss.requestCount );

When now modifying one of these properties the callback handler will be invoked

for( int i = 1; i < 30; i++ )
{
bds.imageRequestTimeout_ms.write( i );
ss.requestCount.write( i );
}

This can be shown by sending the user data objects to the standard output now. In this example this will increase the play counter of a record:

// now verify that the callbacks have actually been executed by displaying the times all records have
// been played within the callback handlers
cout << "=== List of records AFTER callbacks ===" << endl;
for_each( vinylRecords.begin(), vinylRecords.end(), mem_fn( &VinylRecord::display ) );
Source code
//
// @description: Example applications for Impact Acquire
// @copyright: Copyright (C) 2011 - 2023 Balluff GmbH
// @authors: APIs and drivers development team at Balluff GmbH
// @initial date: 2011-07-11
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,i
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#ifdef _MSC_VER // is Microsoft compiler?
# if _MSC_VER < 1300 // is 'old' VC 6 compiler?
# pragma warning( disable : 4786 ) // 'identifier was truncated to '255' characters in the debug information'
# endif // #if _MSC_VER < 1300
#endif // #ifdef _MSC_VER
#include <algorithm>
#include <apps/Common/exampleHelper.h>
#include <functional>
#include <mvIMPACT_CPP/mvIMPACT_acquire.h>
using namespace std;
using namespace mvIMPACT::acquire;
//-----------------------------------------------------------------------------
class VinylRecord
//-----------------------------------------------------------------------------
{
private:
std::string album_;
unsigned int timesPlayed_;
public:
explicit VinylRecord( const std::string& album ) : album_( album ), timesPlayed_( 0 ) {}
bool display( void )
{
cout << "This record is called '" << getAlbum() << "' and since creation it has been played " << getTimesPlayed() << " times." << endl; // if this function is declared 'const' or does not return a value the 'for_each' calls does not compile with VS 6...
return true;
}
const std::string& getAlbum( void ) const
{
return album_;
}
unsigned int getTimesPlayed( void ) const
{
return timesPlayed_;
}
void play( void )
{
++timesPlayed_;
}
};
typedef vector<VinylRecord*> RecordStack;
//-----------------------------------------------------------------------------
class MyCallback : public ComponentCallback
//-----------------------------------------------------------------------------
{
unsigned int hitCount_;
public:
explicit MyCallback( void* pUserData = 0 ) : ComponentCallback( pUserData ),
hitCount_( 0 ) {}
// Please carefully read the documentation of the base class (mvIMPACT::acquire::ComponentCallback) and the documentation of the
// mvIMPACT::acquire::ComponentCallback::execute function in particular to avoid unpleasant surprises!
virtual void execute( Component& c, void* pUserData )
{
// get access to the user data previously associated with the component that just executes the callback
RecordStack* pRecordStack = reinterpret_cast<RecordStack*>( pUserData );
// do some work with the user data object
const RecordStack::size_type recordCount = pRecordStack->size();
cout << "Component '" << c.name() << "' did just cause a callback. It's the " << ++hitCount_ << " time this function got called." << endl
<< "This callback carries " << recordCount << " good old vinyl records with it." << endl;
RecordStack::const_iterator it = pRecordStack->begin();
const RecordStack::const_iterator itEND = pRecordStack->end();
unsigned int i = 0;
while( it != itEND )
{
cout << " There is a record called '" << ( *it )->getAlbum() << "'";
if( ( hitCount_ % recordCount ) == i )
{
cout << ", which I will play now";
( *it )->play();
}
cout << endl;
++it;
++i;
}
}
};
//-----------------------------------------------------------------------------
int main( void )
//-----------------------------------------------------------------------------
{
DeviceManager devMgr;
Device* pDev = getDeviceFromUserInput( devMgr );
if( !pDev )
{
cout << "Unable to continue! Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
cout << "Initialising the device. This might take some time..." << endl;
try
{
pDev->open();
}
catch( const ImpactAcquireException& e )
{
// this e.g. might happen if the same device is already opened in another process...
cout << "An error occurred while opening the device(error code: " << e.getErrorCode() << ")." << endl
<< "Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
BasicDeviceSettings bds( pDev );
SystemSettings ss( pDev );
// create some user data to attach to the callback
vector<VinylRecord*> vinylRecords;
vinylRecords.push_back( new VinylRecord( "The number of the Beast" ) );
vinylRecords.push_back( new VinylRecord( "Holy Diver" ) );
vinylRecords.push_back( new VinylRecord( "Master of Reality" ) );
// create the callback with user data
MyCallback myCallback( &vinylRecords );
// attach the callback to some features
myCallback.registerComponent( bds.imageRequestTimeout_ms );
myCallback.registerComponent( ss.requestCount );
const vector<VinylRecord*>::size_type vinylRecordCnt = vinylRecords.size();
cout << "=== List of records BEFORE callbacks ===" << endl;
for( vector<VinylRecord*>::iterator it = vinylRecords.begin(); it != vinylRecords.end(); ++it )
{
( *it )->display();
}
// provoke some callbacks by modifying the properties we just registered callbacks for.
// Whenever one of this features is changed in any way the previously attached callback
// handler will be called.
for( int i = 1; i < 30; i++ )
{
bds.imageRequestTimeout_ms.write( i );
ss.requestCount.write( i );
}
// now verify that the callbacks have actually been executed by displaying the times all records have
// been played within the callback handlers
cout << "=== List of records AFTER callbacks ===" << endl;
for( vector<VinylRecord*>::iterator it = vinylRecords.begin(); it != vinylRecords.end(); ++it )
{
( *it )->display();
}
// clean up
myCallback.unregisterComponent( ss.requestCount );
myCallback.unregisterComponent( bds.imageRequestTimeout_ms );
for( vector<VinylRecord*>::size_type j = 0; j < vinylRecordCnt; j++ )
{
delete vinylRecords[j];
}
vinylRecords.clear();
cout << "Press [ENTER] to end the application" << endl;
cin.get();
return 0;
}
A base class for essential device related settings.
Definition mvIMPACT_acquire.h:12215
std::string name(void) const
Returns the name of the component referenced by this object.
Definition mvIMPACT_acquire.h:1206
A simple helper class to wrap the creation of a callback object.
Definition mvIMPACT_acquire.h:2101
A base class to implement access to internal driver components.
Definition mvIMPACT_acquire.h:1439
Grants access to devices that can be operated by this software interface.
Definition mvIMPACT_acquire.h:7171
This class and its functions represent an actual device detected by this interface in the current sys...
Definition mvIMPACT_acquire.h:6118
void open(void)
Opens a device.
Definition mvIMPACT_acquire.h:6420
A base class for exceptions generated by Impact Acquire.
Definition mvIMPACT_acquire.h:256
int getErrorCode(void) const
Returns a unique numerical representation for this error.
Definition mvIMPACT_acquire.h:275
A base class for accessing settings that control the overall behaviour of a device driver.
Definition mvIMPACT_acquire.h:14728
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition mvCommonDataTypes.h:34