Device configuration

In the GenICam world, each device exposes its parameters in a tree-like structure called nodemap. Each node in this tree represents a camera parameter, known as a feature. The GenApi library, provided with ItalaApi, is specifically designed to manipulate these features. This allows users to read and write values to the nodemaps of Opto Engineering devices in a standardized way.

Note

Feature names and types are standardized by the SFNC (Standard Feature Naming Convention), which is part of the GenICam standard. Its goal is to improve compatibility between different devices by defining a common set of features (like ExposureTime, Width, AcquisitionMode, etc.). Opto Engineering devices are SFNC-compliant. For detailed information on standard features, please refer to the official SFNC and GenICam documentation, available from the GenICam Introduction page.

Accessing the nodemap

To configure a device, users first need to get its nodemap. This is done through the device interface or handle.

// Get the GenICam nodemap from the device object
GenApi::INodeMap& deviceNodemap = pDevice->GetNodeMap();
// Get the GenICam nodemap from the device handle
H_NODEMAP hNodeMap = NULL;
error = DEV_GetNodeMap(hDevice, &hNodeMap);
// Get the GenICam nodemap from the device object
GenApi.INodeMap deviceNodemap = device.GetNodeMap();
# Get the GenICam nodemap from the device object
device_nodemap = device.node_map

Working with features

Once users have the nodemap, they can query it for specific features by name. Features have different types (Integer, Float, Boolean, etc.), and GenApi provides specific interfaces or handles for each.

Accessing feature nodes

// Get typed pointers for different features

// "ReverseX" is a boolean feature
GenApi::CBooleanPtr pReverseX = deviceNodemap.GetNode("ReverseX");
// "Width" is a integer feature
GenApi::CIntegerPtr pWidth = deviceNodemap.GetNode("Width");
// "ExposureTime" is a float feature.
GenApi::CFloatPtr pExposureTime = deviceNodemap.GetNode("ExposureTime");
// "DeviceUserID" is a string feature.
GenApi::CStringPtr pDeviceUserID = deviceNodemap.GetNode("DeviceUserID");
// "AcquisitionMode" is a enum feature.
GenApi::CEnumerationPtr pAcquisitionMode = deviceNodemap.GetNode("AcquisitionMode");
// "DeviceReset" is a command feature
GenApi::CCommandPtr pDeviceReset = deviceNodemap.GetNode("DeviceReset");
// Get generic handles for different features
H_NODE hReverseX = NULL;
error = NODEMAP_GetNode(hNodeMap, "ReverseX", &hReverseX);
H_NODE hWidth = NULL;
error = NODEMAP_GetNode(hNodeMap, "Width", &hWidth);
// ... and so on for other features
// Get typed interfaces for different features

// "ReverseX" is a boolean feature
GenApi.IBoolean reverseX = deviceNodemap.GetNode<GenApi.IBoolean>("ReverseX");
// "Width" is a integer feature
GenApi.IInteger width = deviceNodemap.GetNode<GenApi.IInteger>("Width");
// "ExposureTime" is a float feature.
GenApi.IFloat exposureTime = deviceNodemap.GetNode<GenApi.IFloat>("ExposureTime");
// "DeviceUserID" is a string feature.
GenApi.IString deviceUserID = deviceNodemap.GetNode<GenApi.IString>("DeviceUserID");
// "AcquisitionMode" is a enum feature.
GenApi.IEnumeration acquisitionMode = deviceNodemap.GetNode<GenApi.IEnumeration>("AcquisitionMode");
// "DeviceReset" is a command feature
GenApi.ICommand deviceReset = deviceNodemap.GetNode<GenApi.ICommand>("DeviceReset");
# Access features as properties of the nodemap
reverse_x = device_nodemap.ReverseX
width = device_nodemap.Width
exposure_time = device_nodemap.ExposureTime
device_user_id = device_nodemap.DeviceUserID
acquisition_mode = device_nodemap.AcquisitionMode
device_reset = device_nodemap.DeviceReset

Boolean features

Boolean features accept true/false values.

// Flip the image horizontally
bool oldReverseX = pReverseX->GetValue();
pReverseX->SetValue(true);
// Flip the image horizontally
bool oldReverseX = false;
error = NODE_BooleanGetValue(hReverseX, &oldReverseX);
error = NODE_BooleanSetValue(hReverseX, true);
// Flip the image horizontally
bool oldReverseX = reverseX.Value;
reverseX.Value = true;
# Flip the image horizontally
old_reverse_x = reverse_x.value
reverse_x.value = True

Integer, Float, and String features

These types are used for numerical values (like width in pixels or exposure time in microseconds) and text strings.

// Set width in pixels
int64_t oldWidth = pWidth->GetValue();
pWidth->SetValue(520);

// Set exposure time in microseconds
float oldExpTime = pExposureTime->GetValue();
pExposureTime->SetValue(25700.5);

// A user-defined ID is assigned to the camera
GenICam::gcstring oldUserID = pDeviceUserID->GetValue();
pDeviceUserID->FromString("HelloCamera");

// Get min/max values
int64_t maxWidth = pWidth->GetMax();
int64_t minWidth = pWidth->GetMin();
int64_t incWidth = pWidth->GetInc();
// Set width in pixels
int64_t oldWidth = 0;
error = NODE_IntegerGetValue(hWidth, &oldWidth);
error = NODE_IntegerSetValue(hWidth, 520);

// Set exposure time in microseconds
float oldExpTime = 0;
error = NODE_FloatGetValue(hExposureTime, &oldExpTime);
error = NODE_FloatSetValue(hExposureTime, 257000.5);

// A user-defined ID is assigned to the camera
char oldUserId[255];
size_t sizeMessage = 255;
error = NODE_StringGetValue(hDeviceUserID, oldUserId, &sizeMessage);
error = NODE_StringSetValue(hDeviceUserID, "HelloCamera");

// Get min/max values
int64_t maxWidth = 0;
error = NODE_IntegerGetMax(hWidth, &maxWidth);
// Set width in pixels
width.Value = 520;

// Set exposure time in microseconds
exposureTime.Value = 25700.5;

// Get min/max values
long maxWidth = width.Max;
# Set width in pixels
width.value = 520

# Set exposure time in microseconds
exposure_time.value = 25700.5

# Get min/max values
max_width = width.max

Enumeration features

Enumeration features represent a list of fixed choices (e.g., AcquisitionMode can be SingleFrame, MultiFrame, or Continuous). Users can set them using either their string representation or their underlying integer value.

// Set by string
pAcquisitionMode->FromString("Continuous");

// Set by integer value
pAcquisitionMode->SetIntValue(3); // "Continuous" corresponds to 3 in SFNC
// Set by string
error = NODE_FromString(hAcquisitionMode, "Continuous");

// Set by integer value
error = NODE_EnumerationSetIntValue(hAcquisitionMode, 3);
// Set by string
acquisitionMode.FromString("Continuous");

// Set by integer value
acquisitionMode.IntValue = 3;
# Set by string
acquisition_mode.from_string("Continuous")

# Set by integer value
acquisition_mode.set_int_value(3)

Command features

Command features trigger an action on the device when executed.

// Reset the device
GenApi::CCommandPtr pDeviceReset = deviceNodemap.GetNode("DeviceReset");
pDeviceReset->Execute();
// Reset the device
error = NODE_CommandExecute(hDeviceReset);
// Reset the device
GenApi.ICommand deviceReset = deviceNodemap.GetNode<GenApi.ICommand>("DeviceReset");
deviceReset.Execute();
# Reset the device
device_reset.execute()

Feature accessibility and validation

Not all features are available or writable at all times. For example, DeviceTemperature is read-only, and Width may only be writable when the camera is not acquiring images. GenApi provides functions to check the current accessibility of a feature.

if (GenApi::IsReadable(pWidth))
{
  int64_t currentWidth = pWidth->GetValue();
}

if (GenApi::IsWritable(pWidth))
{
  pWidth->SetValue(520);
}

// A node that does not exist will be a null pointer
GenApi::CIntegerPtr pInvalidNode = deviceNodemap.GetNode("InvalidName");
if (!pInvalidNode) {
  // Node does not exist
}
// Getting a node with the wrong type returns a null pointer
GenApi::CFloatPtr pWidthWrongType = deviceNodemap.GetNode("Width");
if (!pWidthWrongType)
{
  // If the camera implements the "Width" feature, it has to be an integer.
  // The condition is false.
}
bool isReadable = false;
error = IsNodeReadable(hWidth, &isReadable);
if (isReadable) { /* ... */ }

bool isWritable = false;
error = IsNodeWritable(hWidth, &isWritable);
if (isWritable) { /* ... */ }

// A handle to a node that does not exist will be NULL
H_NODE hInvalidNode = NULL;
error = NODEMAP_GetNode(hNodeMap, "InvalidName", &hInvalidNode);
if (hInvalidNode == NULL) {
  // Node does not exist
}
if (width.IsReadable)
{
  long currentWidth = width.Value;
}

if (width.IsWritable)
{
  width.Value = 520;
}

// Requesting a non-existent node returns null
var invalidNode = deviceNodemap.GetNode<GenApi.IInteger>("InvalidName");
if (!invalidNode) {
  // Node does not exist
}
// Getting a node with the wrong type throws an InvalidCastException
var wrongTypeNode = deviceNodemap.GetNode<GenApi.IFloat>("Width"); // throws InvalidCastException
if itala.is_readable(width.node):
  current_width = width.value

if itala.is_writable(width.node):
  width.value = 520

# Accessing a non-existent feature raises an AttributeError
try:
  invalid_node = device_nodemap.InvalidName
except AttributeError:
  print("Node does not exist")