Impact Acquire SDK .NET
Callback.cs

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.cs can be found under:
%INSTALLDIR%\apps\CSharp\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 mv.impact.acquire.ComponentCallback and override the mv.impact.acquire.ComponentCallback.execute() method:

//-----------------------------------------------------------------------------
public class MyCallback : ComponentCallback
//-----------------------------------------------------------------------------
{
private uint executeHitCount_;
private Object pMyUserData_;
private string name_;
public MyCallback(string name, Object pUserData)
: base(pUserData)
{
pMyUserData_ = pUserData;
name_ = name;
}
// Please carefully read the documentation of the base class (mv.impact.acquire.ComponentCallback) and the documentation of the
// mv.impact.acquire.ComponentCallback.execute function in particular to avoid unpleasant surprises!
public override void execute(Component c, Object pUserData)
{
List<VinylRecord> RecordStack = new List<VinylRecord>();
// get access to the user data previously associated with the component that just executes the callback
RecordStack = (List<VinylRecord>)pUserData;
// do some work with the user data object
int recordCount = RecordStack.Count;
Console.WriteLine("Component '{0}' did just cause a callback. This function has been called {1} times.", c.name, ++executeHitCount_);
Console.WriteLine("This callback carries {0} good old vinyl records with it.", recordCount);
int i = 0;
foreach (VinylRecord Record in RecordStack)
{
Console.Write(" There is a record called '{0}'", Record.album);
if (executeHitCount_ % recordCount == i)
{
Console.Write(", which I will play now");
Record.play();
}
Console.WriteLine();
++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:

mv.impact.acquire.LibraryPath.init(); // this will add the folders containing unmanaged libraries to the PATH variable.
Device pDev = DeviceAccess.getDeviceFromUserInput();
if (pDev == null)
{
Console.WriteLine("Unable to continue! Press any key to end the program.");
Console.Read();
Environment.Exit(1);
}
Console.WriteLine("Initialising the device. This might take some time...");
try
{
pDev.open();
}
catch (ImpactAcquireException e)
{
// this e.g. might happen if the same device is already opened in another process...
Console.WriteLine("An error occurred while opening the device " + pDev.serial +
"(error code: " + e.Message + "). Press any key to end the application...");
Console.ReadLine();
Environment.Exit(1);
}
A small helper class to administer various library search path related variables and paths.
Definition LibraryPath.cs:14
static void init()
Calling this method will add the folders containing unmanaged libraries to the systems library search...
Definition LibraryPath.cs:251
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition Enumerations.cs:2
Definition Enumerations.cs:2
Definition Enumerations.cs:2

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

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

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

List<VinylRecord> vinylRecords = new List<VinylRecord>();
vinylRecords.Add(new VinylRecord("The number of the Beast"));
vinylRecords.Add(new VinylRecord("Holy Diver"));
vinylRecords.Add(new VinylRecord("Master of Reality"));

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

MyCallback myCallback = new 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
Console.WriteLine("=== List of records AFTER callbacks ===");
foreach (VinylRecord record in vinylRecords)
{
record.display();
}
Source code
using mv.impact.acquire.examples.helper;
using System;
using System.Collections.Generic;
namespace Callback
{
public class VinylRecord
{
#region private members -----------------------------------------------
private string album_;
private uint timesPlayed_;
#endregion
#region public constructors -------------------------------------------
public VinylRecord(string album)
{
album_ = album;
timesPlayed_ = 0;
}
#endregion
#region public methods ------------------------------------------------
public bool display()
{
Console.WriteLine("This record is called '{0}' and since creation it has been played {1} times.", album, timesPlayed);
return true;
}
public void play()
{
timesPlayed_++;
}
#endregion
#region public properties ---------------------------------------------
public string album { get { return album_; } }
public uint timesPlayed { get { return timesPlayed_; } }
#endregion
}
public class MyCallback : ComponentCallback
{
#region private members -----------------------------------------------
private uint executeHitCount_;
private Object pMyUserData_;
private string name_;
#endregion
#region public constructors -------------------------------------------
public MyCallback(string name, Object pUserData)
: base(pUserData)
{
pMyUserData_ = pUserData;
name_ = name;
}
#endregion
#region public methods ------------------------------------------------
// Please carefully read the documentation of the base class (mv.impact.acquire.ComponentCallback) and the documentation of the
// mv.impact.acquire.ComponentCallback.execute function in particular to avoid unpleasant surprises!
public override void execute(Component c, Object pUserData)
{
List<VinylRecord> RecordStack = new List<VinylRecord>();
// get access to the user data previously associated with the component that just executes the callback
RecordStack = (List<VinylRecord>)pUserData;
// do some work with the user data object
int recordCount = RecordStack.Count;
Console.WriteLine("Component '{0}' did just cause a callback. This function has been called {1} times.", c.name, ++executeHitCount_);
Console.WriteLine("This callback carries {0} good old vinyl records with it.", recordCount);
int i = 0;
foreach (VinylRecord Record in RecordStack)
{
Console.Write(" There is a record called '{0}'", Record.album);
if (executeHitCount_ % recordCount == i)
{
Console.Write(", which I will play now");
Record.play();
}
Console.WriteLine();
++i;
}
}
#endregion
#region static methods ------------------------------------------------
static void Main(string[] args)
{
mv.impact.acquire.LibraryPath.init(); // this will add the folders containing unmanaged libraries to the PATH variable.
Device pDev = DeviceAccess.getDeviceFromUserInput();
if (pDev == null)
{
Console.WriteLine("Unable to continue! Press any key to end the program.");
Console.Read();
Environment.Exit(1);
}
Console.WriteLine("Initialising the device. This might take some time...");
try
{
pDev.open();
}
{
// this e.g. might happen if the same device is already opened in another process...
Console.WriteLine("An error occurred while opening the device " + pDev.serial +
"(error code: " + e.Message + "). Press any key to end the application...");
Console.ReadLine();
Environment.Exit(1);
}
// create some user data to attach to the callback
List<VinylRecord> vinylRecords = new List<VinylRecord>();
vinylRecords.Add(new VinylRecord("The number of the Beast"));
vinylRecords.Add(new VinylRecord("Holy Diver"));
vinylRecords.Add(new VinylRecord("Master of Reality"));
// create the callback with user data
MyCallback myCallback = new MyCallback("", vinylRecords);
// attach the callback to some features
myCallback.registerComponent(bds.imageRequestTimeout_ms);
myCallback.registerComponent(ss.requestCount);
int vinylRecordCnt = vinylRecords.Count;
Console.WriteLine("=== List of records BEFORE callbacks ===");
foreach (VinylRecord record in vinylRecords)
{
record.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
Console.WriteLine("=== List of records AFTER callbacks ===");
foreach (VinylRecord record in vinylRecords)
{
record.display();
}
// clean up
myCallback.unregisterComponent(ss.requestCount);
myCallback.unregisterComponent(bds.imageRequestTimeout_ms);
Console.WriteLine("Press [ENTER] to end the application");
Console.Read();
}
#endregion
}
}
A base class for essential device related settings.
Definition BasicDeviceSettings.cs:15
readonly PropertyI imageRequestTimeout_ms
An integer property defining the maximum time to wait for an image in ms.
Definition BasicDeviceSettings.cs:70
String name
Returns the name of the component referenced by this object.
Definition ComponentAccess.cs:167
A simple helper class to wrap the creation of a callback object.
Definition ComponentCallback.cs:108
A base class to implement access to internal driver components.
Definition Component.cs:133
This class and its functions represent an actual device detected by this interface in the current sys...
Definition Device.cs:91
void open()
Opens a device.
Definition Device.cs:208
readonly PropertyS serial
A string property (read-only) containing the serial number of this device.
Definition Device.cs:515
An base class for exceptions generated by Impact Acquire.
Definition Exceptions.cs:9
A class for accessing general settings that control the overall behaviour of a device driver.
Definition SystemSettings.cs:6
readonly PropertyI requestCount
An integer property defining the number of requests allocated by the driver.
Definition SystemSettings.cs:60