Impact Acquire SDK C++
GenICamI2cUsage.cpp

The GenICamI2cUsage program is a short example which does not include any image acquisition. It will try to open the selected device and will try to obtain access to the cameras I2C bus and show some data received from the device's temperature sensor.

Since
2.27.0
Note
  • A C++11 compliant compiler is needed to build this example.
  • Not every device supports the customer usage of the I2C interface. The following I2C addresses are locked and therefore not usable: 0x00, 0x20, 0x34, 0x36, 0x3E, 0x48, 0x60, 0x62, 0x64, 0x66, 0x6E, 0x90, 0x92, 0xA0, 0xA2, 0xA4, 0xA6, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE, 0xF8.
  • On Linux systems this sample is shipped without makefiles. The recommended way to build this sample is by using CMake (Building And Linking Using CMake).
GenICamI2cUsage example:
  1. Opens a device
  2. Checks if the opened device supports I2C access
  3. Obtains access to one of the temperature sensors
  4. Prints the values read from the temperature sensor to stdout
Note
This example only shows how to read out the temperature sensor using I2C. To read out the temperature later in the final application in a more convenient way, use the corresponding property (mvIMPACT::acquire::GenICam::DeviceControl::deviceTemperature).
How it works

In the first step it is verified if the device is allows access to its I2C bus. Once the device allows access to the I2C bus, it will be configured.

Note
Do not write to other temperature sensor registers than the one used in this example, otherwise the sensor may not work properly afterwards.
// Note: The following I2C addresses are locked and therefore not usable by the I2C Interface:
// 0x00, 0x20, 0x34, 0x36, 0x3E, 0x48, 0x60, 0x62, 0x64, 0x66, 0x6E, 0x90, 0x92, 0xA0, 0xA2, 0xA4, 0xA6, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE, 0xF8
// I2C address 0x30 and 0x32 are reserved for temperature sensors but are accessible for this i2c example
// Do not write to other temperature sensor registers than the one used in this example, otherwise the sensor may not work properly afterwards
const int i2cDeviceAddress = pDev->manufacturerSpecificInformation.read().find( ";SF3" ) != std::string::npos || pDev->manufacturerSpecificInformation.read().find( "-3M" ) != std::string::npos ? 0x32 : 0x30;
unique_ptr<GenICam::mvI2cInterfaceControl> pI2C;
try
{
// instantiate access to the I2C Interface control
pI2C = unique_ptr<GenICam::mvI2cInterfaceControl>( new GenICam::mvI2cInterfaceControl( pDev ) );
// first enable I2C Interface
pI2C->mvI2cInterfaceEnable.write( bTrue );
// set I2C speed to 400kBaud
pI2C->mvI2cInterfaceSpeed.writeS( "kHz_400" );
// set I2C device address to temperature sensor
pI2C->mvI2cInterfaceDeviceAddress.write( i2cDeviceAddress );
// set I2C sub-address to resolution register 8
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x08 );
// write I2C sub-address 8 to sensor and look whether it is accessible
pI2C->mvI2cInterfaceWrite.call();
// set temperature resolution register 8 to 1 (resolution 0.25 degrees Celsius)
// set sub-address to 8
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x08 );
// write value 1 (resolution 0.25 degrees Celsius) to buffer
const char writeBuf[1] = { 1 };
pI2C->mvI2cInterfaceBinaryBuffer.writeBinary( string( writeBuf, sizeof( writeBuf ) / sizeof( writeBuf[0] ) ) );
// send one byte from mvI2cInterfaceBinaryBuffer
pI2C->mvI2cInterfaceBytesToWrite.write( 1 );
// write data to i2c device (sum 3 Byte)
pI2C->mvI2cInterfaceWrite.call();
// do same as above but faster
// set mvI2cInterfaceDeviceSubAddress to 8 and use reminder SubAddress Byte to write value 1 (resolution 0.25 degrees Celsius) to sub-address 8 (0x1xxxx means 16-bit sub-address)
//pI2C->mvI2cInterfaceDeviceSubAddress.write(0x10800); // write value 0 (resolution 0.5 degrees Celsius)
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x10801 ); // write value 1 (resolution 0.25 degrees Celsius)
//pI2C->mvI2cInterfaceDeviceSubAddress.write(0x10802); // write value 2 (resolution 0.125 degrees Celsius)
//pI2C->mvI2cInterfaceDeviceSubAddress.write(0x10803); // write value 3 (resolution 0.0625 degrees Celsius)
// do not use mvI2cInterfaceBinaryBuffer
pI2C->mvI2cInterfaceBytesToWrite.write( 0 );
// write data to i2c device (sum 3 Byte)
pI2C->mvI2cInterfaceWrite.call();
}
catch( const ImpactAcquireException& e )
{
cout << "ERROR! I2C properties which are essential to run this sample are not available for the selected device (error code: " << e.getErrorCode() << "(" << e.getErrorCodeAsString() << ")), press [ENTER] to end the application..." << endl;
return 1;
}

Finally the measurement value of the temperature sensor is read out in a loop and printed to stdout.

// start temperature read loop
double lastTemperatureDisplayed = {0.};
// start temperature read loop
while( !s_boTerminated )
{
// read temperature register from temperature sensor
// set i2c sub-address to temperature register 5
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x05 );
// set i2c read counter to 2 bytes
pI2C->mvI2cInterfaceBytesToRead.write( 0x02 );
// read temperature from sensor
pI2C->mvI2cInterfaceRead.call();
// read temperature data from camera
const string i2cReadBinaryData = pI2C->mvI2cInterfaceBinaryBuffer.readBinary();
// calculate temperature
const int temp = ( i2cReadBinaryData[0] * 256 ) + i2cReadBinaryData[1];
const double currentTemperature = static_cast<double>( ( ( temp << 3 ) & 0xffff ) ) / 128.;
// print temperature if changed
if( currentTemperature != lastTemperatureDisplayed )
{
cout << "Mainboard Temperature: " << currentTemperature << "\370C" << endl;
lastTemperatureDisplayed = currentTemperature;
}
this_thread::sleep_for( chrono::milliseconds( 1000 ) );
}
Source code
//
// @description: Example applications for Impact Acquire
// @copyright: Copyright (C) 2019 - 2024 Balluff GmbH
// @authors: APIs and drivers development team at Balluff GmbH
// @initial date: 2019-07-09
//
// 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.
//
#include <algorithm>
#include <apps/Common/exampleHelper.h>
#include <functional>
#include <memory>
#include <mvIMPACT_CPP/mvIMPACT_acquire_GenICam.h>
#include <thread>
using namespace std;
using namespace mvIMPACT::acquire;
static bool s_boTerminated = false;
//-----------------------------------------------------------------------------
int threadFn( Device* pDev )
//-----------------------------------------------------------------------------
{
// Note: The following I2C addresses are locked and therefore not usable by the I2C Interface:
// 0x00, 0x20, 0x34, 0x36, 0x3E, 0x48, 0x60, 0x62, 0x64, 0x66, 0x6E, 0x90, 0x92, 0xA0, 0xA2, 0xA4, 0xA6, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE, 0xF8
// I2C address 0x30 and 0x32 are reserved for temperature sensors but are accessible for this i2c example
// Do not write to other temperature sensor registers than the one used in this example, otherwise the sensor may not work properly afterwards
const int i2cDeviceAddress = pDev->manufacturerSpecificInformation.read().find( ";SF3" ) != std::string::npos || pDev->manufacturerSpecificInformation.read().find( "-3M" ) != std::string::npos ? 0x32 : 0x30;
unique_ptr<GenICam::mvI2cInterfaceControl> pI2C;
try
{
// instantiate access to the I2C Interface control
pI2C = unique_ptr<GenICam::mvI2cInterfaceControl>( new GenICam::mvI2cInterfaceControl( pDev ) );
// first enable I2C Interface
pI2C->mvI2cInterfaceEnable.write( bTrue );
// set I2C speed to 400kBaud
pI2C->mvI2cInterfaceSpeed.writeS( "kHz_400" );
// set I2C device address to temperature sensor
pI2C->mvI2cInterfaceDeviceAddress.write( i2cDeviceAddress );
// set I2C sub-address to resolution register 8
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x08 );
// write I2C sub-address 8 to sensor and look whether it is accessible
pI2C->mvI2cInterfaceWrite.call();
// set temperature resolution register 8 to 1 (resolution 0.25 degrees Celsius)
// set sub-address to 8
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x08 );
// write value 1 (resolution 0.25 degrees Celsius) to buffer
const char writeBuf[1] = { 1 };
pI2C->mvI2cInterfaceBinaryBuffer.writeBinary( string( writeBuf, sizeof( writeBuf ) / sizeof( writeBuf[0] ) ) );
// send one byte from mvI2cInterfaceBinaryBuffer
pI2C->mvI2cInterfaceBytesToWrite.write( 1 );
// write data to i2c device (sum 3 Byte)
pI2C->mvI2cInterfaceWrite.call();
// do same as above but faster
// set mvI2cInterfaceDeviceSubAddress to 8 and use reminder SubAddress Byte to write value 1 (resolution 0.25 degrees Celsius) to sub-address 8 (0x1xxxx means 16-bit sub-address)
//pI2C->mvI2cInterfaceDeviceSubAddress.write(0x10800); // write value 0 (resolution 0.5 degrees Celsius)
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x10801 ); // write value 1 (resolution 0.25 degrees Celsius)
//pI2C->mvI2cInterfaceDeviceSubAddress.write(0x10802); // write value 2 (resolution 0.125 degrees Celsius)
//pI2C->mvI2cInterfaceDeviceSubAddress.write(0x10803); // write value 3 (resolution 0.0625 degrees Celsius)
// do not use mvI2cInterfaceBinaryBuffer
pI2C->mvI2cInterfaceBytesToWrite.write( 0 );
// write data to i2c device (sum 3 Byte)
pI2C->mvI2cInterfaceWrite.call();
}
catch( const ImpactAcquireException& e )
{
cout << "ERROR! I2C properties which are essential to run this sample are not available for the selected device (error code: " << e.getErrorCode() << "(" << e.getErrorCodeAsString() << ")), press [ENTER] to end the application..." << endl;
return 1;
}
double lastTemperatureDisplayed = {0.};
// start temperature read loop
while( !s_boTerminated )
{
// read temperature register from temperature sensor
// set i2c sub-address to temperature register 5
pI2C->mvI2cInterfaceDeviceSubAddress.write( 0x05 );
// set i2c read counter to 2 bytes
pI2C->mvI2cInterfaceBytesToRead.write( 0x02 );
// read temperature from sensor
pI2C->mvI2cInterfaceRead.call();
// read temperature data from camera
const string i2cReadBinaryData = pI2C->mvI2cInterfaceBinaryBuffer.readBinary();
// calculate temperature
const int temp = ( i2cReadBinaryData[0] * 256 ) + i2cReadBinaryData[1];
const double currentTemperature = static_cast<double>( ( ( temp << 3 ) & 0xffff ) ) / 128.;
// print temperature if changed
if( currentTemperature != lastTemperatureDisplayed )
{
cout << "Mainboard Temperature: " << currentTemperature << "\370C" << endl;
lastTemperatureDisplayed = currentTemperature;
}
this_thread::sleep_for( chrono::milliseconds( 1000 ) );
}
return 0;
}
//-----------------------------------------------------------------------------
// This function will allow to select devices that support the GenICam interface
// layout(these are devices, that claim to be compliant with the GenICam standard)
// and that are bound to drivers that support the user controlled start and stop
// of the internal acquisition engine. Other devices will not be listed for
// selection as the code of the example relies on these features in the code.
bool isDeviceSupportedBySample( const Device* const pDev )
//-----------------------------------------------------------------------------
{
if( !pDev->interfaceLayout.isValid() &&
{
return false;
}
vector<TDeviceInterfaceLayout> availableInterfaceLayouts;
pDev->interfaceLayout.getTranslationDictValues( availableInterfaceLayouts );
return find( availableInterfaceLayouts.begin(), availableInterfaceLayouts.end(), dilGenICam ) != availableInterfaceLayouts.end();
// since there is no possibility to check if the device supports the
// mvI2cInterfaceControl functionality without opening the device
// this check has to be done later on
}
//-----------------------------------------------------------------------------
int main( void )
//-----------------------------------------------------------------------------
{
DeviceManager devMgr;
Device* pDev = getDeviceFromUserInput( devMgr, isDeviceSupportedBySample );
if( pDev == nullptr )
{
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;
}
cout << "Press [ENTER] to end the application" << endl;
s_boTerminated = false;
thread myThread( threadFn, pDev );
cin.get();
s_boTerminated = true;
myThread.join();
return 0;
}
bool isValid(void) const
Checks if the internal component referenced by this object is still valid.
Definition mvIMPACT_acquire.h:1721
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
PropertyS manufacturerSpecificInformation
A string property (read-only) containing manufacturer specific information of this device.
Definition mvIMPACT_acquire.h:6822
void open(void)
Opens a device.
Definition mvIMPACT_acquire.h:6420
PropertyIDeviceInterfaceLayout interfaceLayout
An enumerated integer property which can be used to define which interface layout shall be used when ...
Definition mvIMPACT_acquire.h:6644
PropertyIAcquisitionStartStopBehaviour acquisitionStartStopBehaviour
An enumerated integer property defining the start/stop behaviour during acquisition of this driver in...
Definition mvIMPACT_acquire.h:6800
const EnumPropertyI & getTranslationDictValues(std::vector< ZYX > &sequence) const
This function queries a list of valid values for this property.
Definition mvIMPACT_acquire.h:4266
Contains features to control the I2C interface.
Definition mvIMPACT_acquire_GenICam.h:15136
A base class for exceptions generated by Impact Acquire.
Definition mvIMPACT_acquire.h:256
std::string getErrorCodeAsString(void) const
Returns a string representation of the error associated with the exception.
Definition mvIMPACT_acquire.h:288
int getErrorCode(void) const
Returns a unique numerical representation for this error.
Definition mvIMPACT_acquire.h:275
std::string read(int index=0) const
Reads a value from a property.
Definition mvIMPACT_acquire.h:5323
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition mvCommonDataTypes.h:34