IDS peak genericC++  v1.4.2
Mainpage

Introduction

The IDS peak API is a library that unites GenTL and GenApi. In some places, it also introduces some extra functionality. The purpose of this extra functionality is to increase the usability and comfort of the standard GenAPI.

GenAPI & GenTL Wrapper

The classes in the core namespace are mostly a tight wrapper around the GenAPI and GenTL. It provides some convenience by automatic resource cleanup (RAII), but mostly it reflects the hierarchical structure of the GenTL:

  • Each ProducerLibrary represents one *.cti and contains exactly one System (not part of GenTL).
  • Each System contains 0 or more Interfaces.
  • Each Interface represents one physical interface in the system (i.e. one network interface card) and contains 0 or more Devices.
  • Each Device represents the GenTL Producers’ proxy for one physical RemoteDevice (i.e. a camera) and contains 0 or more DataStreams.
  • Each DataStream represents a single (image) data stream. 0 or more Buffers can be assigned to each DataStream.
  • Each Buffer represents a single, separate memory buffer from the DataStream.

Each module can list the Descriptors of its child modules, which can open the corresponding child module.

Each module needs its parent module to function properly. Therefore, you need to keep the parent modules around until you are done with the child module. When using the DeviceManager, it keeps the ProducerLibrary, System, and Interface modules open until program termination (or until calling DeviceManager::Reset()).

Convenience Layer

The main peak namespace contains global library functions as well as convenience functionality, which don't exist in GenAPI/GenTL. The convenience functionality simplifies the standard usage of the API, without sacrificing access to the more complex API in the core namespace.

Usage

Initialize / Close Library

Before doing anything else, call Library::Initialize(). This will initialize any needed resources. Calling any other function before calling Library::Initialize() will result in a NotInitializedException.

After you are done using the library, call Library::Close() before unloading the library. This will clean up any internal resources and stop any running threads.

Note
Calling Library::Close() is of particular importance on MS Windows platforms, when using "Run-Time Dynamic Linking", especially when unloading the DLL with FreeLibrary(). Otherwise it is very likely to run into the "Loader-Lock Deadlock Problem" during DLL unloading.

Hierarchical access

A common way to start programming with the IDS peak API is to enumerate the GenTL producer libraries found in the current environment. This is achieved by calling EnvironmentInspector::CollectCTIPaths(). Once you have chosen a producer library, you pass its path to the static method ProducerLibrary::Open(). From there, you can follow the hierarchical structure of the modules: ProducerLibrary -> System -> Interface -> Device -> DataStream. Each Module can list and open its child-modules.

DeviceManager

If you don't need tight control over when modules are opened and closed, you can also use the DeviceManager. It provides much more convenience by enabling you to enumerate all modules of the available producer libraries with a single function call (DeviceManager::Update()):

auto& deviceManager = peak::DeviceManager::Instance();
deviceManager.Update();
devices = deviceManager.Devices();

To enumerate the Devices, the underlying modules (i.e. ProducerLibraries, Systems, and Interfaces) need to be opened. Since the DeviceManager is a singleton, these modules stay open until program termination or until DeviceManager::Reset() is called.

GenTL Compatibility

*.ctis using GenTL v1.1 or higher are supported. When accessing features the *.cti doesn't support, there will be a "not implemented" error. E.g. chunks exist since GenTL v1.3, so trying to access chunks with a GenTL v1.2 *.cti will result in a exception. GenTL v1.0 *.ctis are not supported.

Core-Principles

C-API with C++ Wrapper

The IDS peak API exists as a plain C-API, so it can be integrated in any programming environment. As a wrapper around the the C-API, there is also a more convenient C++ API. These C++ wrapper classes are implemented as header-only, so there are no compiler incompatibilities.

Descriptors

This API uses the concept of descriptors acting as delegates for all openable modules. A descriptor holds information about its module and can open its module.

Automatic resource release (RAII)

This API uses smart pointers to automatically release unused resources. This makes the interaction with the API very intuitive. As an example the descriptors' open functions return a smart pointer holding the opened module. If the user releases the last smart pointer referencing the opened module, the module automatically gets closed and destroyed. The same applies to the event controller returned by EventSupportingModule::EnableEvents(). After releasing the last smart pointer referencing the event controller, the corresponding event type is disabled automatically and the event controller itself is destroyed.

Static or Dynamic Loading

By default, this library is linked into the user program, therefore is loaded statically at program start. Instead, it can also be loaded dynamically, when the first library function is called. To use this feature, enable the CMake option PEAK_DYNAMIC_LOADING or set the #define PEAK_DYNAMIC_LOADING before including any of the libraries files.

C# / .NET

For Windows, there is also a .NET version of the library.

To use it in a C# project, add a reference to the ids_peak_dotnet.dll to the project.

Before starting your application, make sure that the DLL-Loader can find all required libraries. This means that ids_peak_dotnet.dll, ids_peak_dotnet_interface.dll, ids_peak.dll and all GenICam libraries required by ids_peak.dll are located next to your application binary or that the directory where they are located is added to the DLL-Loader's search directories. To add their directory to the DLL-Loader's search directories, you could simply append their directory to the environment variable 'Path':

PowerShell:

1. $env:Path="$env:Path;<Installation-Directory-Of-ids_peak.dll>"
2. $env:Path="$env:Path;<Installation-Directory-Of-ids_peak_dotnet.dll>"
3. Start your application

CMD:

1. set Path=%Path%;<Installation-Directory-Of-ids_peak.dll>
2. set Path=%Path%;<Installation-Directory-Of-ids_peak_dotnet.dll>
3. Start your application

The .NET API works much like the C++ API. The same principles, class and method names apply. For example, listing all available devices:

using peak;
try
{
Library.Initialize();
var deviceManager = DeviceManager.Instance();
deviceManager.Update();
var deviceDescriptors = deviceManager.Devices();
foreach (var deviceDescriptor in deviceDescriptors)
{
Console.WriteLine(deviceDescriptor.DisplayName());
}
}
catch (System.ApplicationException e)
{
Console.WriteLine("Exception: " + e.Message);
}

There are a few differences between the C++ API and the .NET API. The most important ones are listed here:

C++C# / .NET

Deterministic Memory Management

To close a module (e.g. the Device), you have to release its shared_ptr (out-of-scope, call reset(), set to nullptr), then the module closes immediately.

{
auto device = deviceDescriptors[0].OpenDevice(DeviceAccessType.Control);
// ...
} // Device closes here

Garbage Collection

When an object is relased in C#, it won't be closed and deleted immediately. Instead, it will be deleted at some point in the future, when the garbage collection deems it necessary. Often, that's no problem. But if it is, there are 2 options:

  • Call Dispose() explicitly:
    var device = deviceDescriptors[0].OpenDevice(DeviceAccessType.Control);
    device.Dispose(); // Device closes here
  • Use using-block:
    using (var device = deviceDescriptors[0].OpenDevice(DeviceAccessType.Control))
    {
    // ...
    } // Device closes here
Callbacks
device_manager.RegisterDeviceFoundCallback(
[](const std::shared_ptr<peak::core::DeviceDescriptor>& newDev)
{ std::cout << "Device found: " << newDev->DisplayName() << '\n'; });
Events + Delegates
deviceManager.DeviceFoundEvent += (object o, DeviceDescriptor newDev)
=> Console.WriteLine("Device found: {0}", newDev.DisplayName());
Method Default Parameters
DataStream::StartAcquisition(
AcquisitionStartMode mode=AcquisitionStartMode::Default,
uint64_t numToAcquire=INFINITE_NUMBER);
Method Overloads
DataStream.StartAcquisition(peak.core.AcquisitionStartMode mode, ulong numToAcquire)
DataStream.StartAcquisition(peak.core.AcquisitionStartMode mode) // with numToAcquire=INFINITE_NUMBER
DataStream.StartAcquisition() // with mode=Default and numToAcquire=INFINITE_NUMBER
Function templates
nodeMapRemoteDevice->FindNode<peak::core::nodes::StringNode>("DeviceModelName")->Value()

Generic method wrappers

C# also supports function templates (i.e. generic methods), which can be used as follows:

nodeMapRemoteDevice.FindNode<peak.core.nodes.StringNode>("DeviceModelName").Value());

However, some IDE's and/or .NET implementations might not support such generic methods (e.g. NI Labview). Therefore all template specifications have been made available separately:

nodeMapRemoteDevice.FindNodeString("DeviceModelName").Value());

Python

To use IDS peak API in Python, there is a separate Python wheel for each supported Python version and CPU architecture. A Python wheel is a package file (with .whl file ending) which can be installed via 'pip', Python's package manager. Just call 'pip install <Path-To-Python-Wheel>' to install your chosen Python wheel.

To finally use IDS peak API in your Python script, just add 'import ids_peak.ids_peak' or 'import ids_peak.ids_peak as some_alias' at the top of your Python script. The latter should be preferred.

The Python API works much like the C++ API. Nearly the same principles, class and method names apply. For example, listing all available devices:

import ids_peak.ids_peak as some_alias
try:
some_alias.Library.Initialize()
device_manager = some_alias.DeviceManager.Instance()
device_manager.Update()
device_descriptors = device_manager.Devices()
for device_descriptor in device_descriptors:
print(device_descriptor.DisplayName())
except ids_peak_alias.Exception as ex:
print("Exception: " + str(ex))
finally:
some_alias.Library.Close()

There are only a few differences between the C++ API and the Python API. The most important ones are listed here:

C++Python

Deterministic Memory Management

To close a module (e.g. the Device), you have to release its shared_ptr (out-of-scope, call reset(), set to nullptr), then the module closes immediately.

{
auto device = deviceDescriptors[0].OpenDevice(DeviceAccessType.Control);
// ...
} // Device gets closed here

Garbage Collection

When an object is relased in Python, it won't be closed and deleted immediately. Instead, it will be deleted at some point in the future, when the garbage collection deems it necessary. Often, that's no problem. But if it is, you could do the following:

device = deviceDescriptors[0].OpenDevice(some_alias.DeviceAccessType_Control)
del device # Device gets closed here
Enums
const auto deviceAccessType = DeviceAccessType::Control;
std::cout << ToString(deviceAccessType) << '\n';
Enums
device_access_type = some_alias.DeviceAccessType_Control
print(some_alias.DeviceAccessTypeEnumEntryToString(device_access_type))
Callbacks
const auto deviceFoundCallbackHandle = deviceManager.RegisterDeviceFoundCallback(
[](const std::shared_ptr<peak::core::DeviceDescriptor>& newDev)
{ std::cout << "Device found: " << newDev->DisplayName() << '\n'; });
deviceManager.Update()
deviceManager.UnregisterDeviceFoundCallback(deviceFoundCallbackHandle);
Callbacks
device_found_callback = device_manager.DeviceFoundCallback(
lambda new_dev: print("Device found: {}", new_dev.DisplayName()))
device_found_callback_handle = device_manager.RegisterDeviceFoundCallback(device_found_callback)
device_manager.Update()
device_manager.UnregisterDeviceFoundCallback(device_found_callback_handle)