mvIMPACT Acquire SDK C++
SingleCaptureMasterSlave.legacy.cpp

The SingleCaptureMasterSlave.legacy program is a legacy version of the SingleCaptureMasterSlave.cpp example.

Note
This is a legacy version of SingleCaptureMasterSlave.cpp only needed when working on a system with a non C++11 capable compiler (e.g. Visual Studio smaller then version 2013 or gcc smaller than version 4.8). For a detailed description please have a look on the modern version of this example. Even though the used C++ code is slightly different the general idea of the example is the same!
Source code
#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 <conio.h>
#include <windows.h>
#include <process.h>
#include <iostream>
#include <apps/Common/exampleHelper.h>
#include <mvIMPACT_CPP/mvIMPACT_acquire.h>
#include <mvDisplay/Include/mvIMPACT_acquire_display.h>
using namespace std;
using namespace mvIMPACT::acquire;
//-----------------------------------------------------------------------------
/// to get thread safe access to the std out and the display module
class CriticalSection
//-----------------------------------------------------------------------------
{
CRITICAL_SECTION m_criticalSection;
public:
CriticalSection()
{
InitializeCriticalSection( &m_criticalSection );
}
~CriticalSection()
{
DeleteCriticalSection( &m_criticalSection );
}
void lock( void )
{
EnterCriticalSection( &m_criticalSection );
}
void unlock( void )
{
LeaveCriticalSection( &m_criticalSection );
}
} g_critSect;
//-----------------------------------------------------------------------------
class LockedScope
//-----------------------------------------------------------------------------
{
CriticalSection c_;
public:
explicit LockedScope( CriticalSection& c ) : c_( c )
{
c_.lock();
}
~LockedScope()
{
c_.unlock();
}
};
//-----------------------------------------------------------------------------
class ThreadData
//-----------------------------------------------------------------------------
{
volatile bool boTerminateThread_;
public:
explicit ThreadData() : boTerminateThread_( false ) {}
virtual ~ThreadData() {}
bool terminated( void ) const
{
return boTerminateThread_;
}
void terminateThread( void )
{
boTerminateThread_ = true;
}
};
//-----------------------------------------------------------------------------
class DeviceData : public ThreadData
//-----------------------------------------------------------------------------
{
Device* pDev_;
IOSubSystem* pIOSS_;
Statistics* pSS_;
ImageDisplayWindow* pDisplayWindow_;
int lastRequestNr_;
public:
explicit DeviceData( Device* p ) : ThreadData(), pDev_( p ), pFI_( 0 ), pIOSS_( 0 ), pSS_( 0 ), pDisplayWindow_( 0 ), lastRequestNr_( INVALID_ID ) {}
~DeviceData()
{
if( pFI_->isRequestNrValid( lastRequestNr_ ) )
{
pFI_->imageRequestUnlock( lastRequestNr_ );
lastRequestNr_ = INVALID_ID;
}
delete pFI_;
delete pSS_;
delete pIOSS_;
delete pDisplayWindow_;
}
void init( const std::string& windowName )
{
pDev_->open();
pFI_ = new FunctionInterface( pDev_ );
pSS_ = new Statistics( pDev_ );
pIOSS_ = new IOSubSystem( pDev_ );
{
LockedScope lockedScope( g_critSect );
cout << "Please note that there will be just one refresh for the display window, so if it is" << endl
<< "hidden under another window the result will not be visible." << endl;
}
pDisplayWindow_ = new ImageDisplayWindow( windowName );
}
Device* device( void ) const
{
return pDev_;
}
FunctionInterface* functionInterface( void ) const
{
return pFI_;
}
IOSubSystem* IOSS( void ) const
{
return pIOSS_;
}
Statistics* statistics( void ) const
{
return pSS_;
}
ImageDisplayWindow* pDisp( void )
{
return pDisplayWindow_;
}
};
//-----------------------------------------------------------------------------
class TriggerSignal : public ThreadData
//-----------------------------------------------------------------------------
{
DigitalOutput* pTriggerOutput_;
unsigned int frequency_Hz_;
public:
explicit TriggerSignal( DigitalOutput* pTriggerOutput, unsigned int frequency_Hz ) : ThreadData(), pTriggerOutput_( pTriggerOutput ), frequency_Hz_( frequency_Hz ) {}
DigitalOutput* triggerOutput( void ) const
{
return pTriggerOutput_;
}
unsigned int frequency_Hz( void ) const
{
return frequency_Hz_;
}
};
//-----------------------------------------------------------------------------
unsigned int __stdcall liveThread( void* pData )
//-----------------------------------------------------------------------------
{
DeviceData* pThreadParameter = reinterpret_cast<DeviceData*>( pData );
unsigned int cnt = 0;
ImageDisplay& display = pThreadParameter->pDisp()->GetImageDisplay();
// establish access to the statistic properties
Statistics* pSS = pThreadParameter->statistics();
// create an interface to the device found
FunctionInterface* pFI = pThreadParameter->functionInterface();
// Send all requests to the capture queue. There can be more than 1 queue for some devices, but for this sample
// we will work with the default capture queue. If a device supports more than one capture or result
// queue, this will be stated in the manual. If nothing is mentioned about it, the device supports one
// queue only. This loop will send all requests currently available to the driver. To modify the number of requests
// use the property mvIMPACT::acquire::SystemSettings::requestCount at runtime or the property
// mvIMPACT::acquire::Device::defaultRequestCount BEFORE opening the device.
while( ( result = static_cast<TDMR_ERROR>( pFI->imageRequestSingle() ) ) == DMR_NO_ERROR ) {};
if( result != DEV_NO_FREE_REQUEST_AVAILABLE )
{
LockedScope lockedScope( g_critSect );
cout << "'FunctionInterface.imageRequestSingle' returned with an unexpected result: " << result
<< "(" << ImpactAcquireException::getErrorCodeAsString( result ) << ")" << endl;
}
manuallyStartAcquisitionIfNeeded( pThreadParameter->device(), *pFI );
// run thread loop
const Request* pRequest = 0;
const unsigned int timeout_ms = 200;
int requestNr = INVALID_ID;
// we always have to keep at least 2 images as the display module might want to repaint the image, thus we
// can't free it unless we have a assigned the display to a new buffer.
int lastRequestNr = INVALID_ID;
while( !pThreadParameter->terminated() )
{
// wait for results from the default capture queue
requestNr = pFI->imageRequestWaitFor( timeout_ms );
if( pFI->isRequestNrValid( requestNr ) )
{
pRequest = pFI->getRequest( requestNr );
if( pRequest->isOK() )
{
++cnt;
// here we can display some statistical information every 100th image
if( cnt % 100 == 0 )
{
LockedScope lockedScope( g_critSect );
cout << "Info from " << pThreadParameter->device()->serial.read()
<< ": " << pSS->framesPerSecond.name() << ": " << pSS->framesPerSecond.readS()
<< ", " << pSS->errorCount.name() << ": " << pSS->errorCount.readS()
<< ", " << pRequest->infoFrameNr
<< ", " << pRequest->infoFrameID
<< ", " << pSS->frameCount << endl;
}
display.SetImage( pRequest );
display.Update();
}
else
{
LockedScope lockedScope( g_critSect );
cout << "Error: " << pRequest->requestResult.readS() << endl;
}
if( pFI->isRequestNrValid( lastRequestNr ) )
{
// this image has been displayed thus the buffer is no longer needed...
pFI->imageRequestUnlock( lastRequestNr );
}
lastRequestNr = requestNr;
// send a new image request into the capture queue
}
else
{
//LockedScope lockedScope( g_critSect );
//// If the error code is -2119(DEV_WAIT_FOR_REQUEST_FAILED), the documentation will provide
//// additional information under TDMR_ERROR in the interface reference (
//cout << "imageRequestWaitFor failed (" << requestNr << ", " << ImpactAcquireException::getErrorCodeAsString( requestNr ) << ", device " << pThreadParameter->device()->serial.read() << ")"
// << ", timeout value too small?" << endl;
}
}
{
LockedScope lockedScope( g_critSect );
cout << "Overall good frames captured from device " << pThreadParameter->device()->serial.read() << ": " << cnt << endl;
}
manuallyStopAcquisitionIfNeeded( pThreadParameter->device(), *pFI );
// stop the display from showing freed memory
display.RemoveImage();
// In this sample all the next lines are redundant as the device driver will be
// closed now, but in a real world application a thread like this might be started
// several times an then it becomes crucial to clean up correctly.
// free the last potentially locked request
if( pFI->isRequestNrValid( requestNr ) )
{
pFI->imageRequestUnlock( requestNr );
}
// clear all queues
pFI->imageRequestReset( 0, 0 );
return 0;
}
//-----------------------------------------------------------------------------
unsigned int __stdcall triggerThread( void* pData )
//-----------------------------------------------------------------------------
{
TriggerSignal* pSignal = reinterpret_cast<TriggerSignal*>( pData );
unsigned int cnt = 0;
const unsigned int sleepPeriod_ms = 1000 / ( pSignal->frequency_Hz() * 2 );
while( !pSignal->terminated() )
{
// generate a trigger signal
Sleep( sleepPeriod_ms );
pSignal->triggerOutput()->flip();
Sleep( sleepPeriod_ms );
pSignal->triggerOutput()->flip();
++cnt;
if( cnt % 100 == 0 )
{
LockedScope lockedScope( g_critSect );
cout << "Trigger signals generated: " << cnt << endl;
}
}
LockedScope lockedScope( g_critSect );
cout << "Overall trigger signals generated: " << cnt << endl;
return 0;
}
//-----------------------------------------------------------------------------
unsigned int getNumberFromUser( void )
//-----------------------------------------------------------------------------
{
unsigned int nr = 0;
std::cin >> nr;
// remove the '\n' from the stream
std::cin.get();
return nr;
}
//-----------------------------------------------------------------------------
bool isDeviceSupportedBySample( const Device* const pDev )
//-----------------------------------------------------------------------------
{
return match( pDev->product.read(), string( "mvBlueCOUGAR-X*" ), '*' ) == 0;
}
//-----------------------------------------------------------------------------
void setupTriggerInput( DeviceData* pDevData )
//-----------------------------------------------------------------------------
{
cout << "Select the digital INPUT of device(" << pDevData->device()->serial.read() << ")(as a string) that shall serve as a trigger input:" << endl;
CameraSettingsBlueCOUGAR cs( pDevData->device() );
DisplayPropertyDictionary<mvIMPACT::acquire::PropertyI>( cs.triggerSource );
modifyPropertyValue( cs.triggerSource );
cs.triggerMode.write( ctmOnRisingEdge );
// infinite trigger timeout
cs.imageRequestTimeout_ms.write( 0 );
}
//-----------------------------------------------------------------------------
int main( void )
//-----------------------------------------------------------------------------
{
cout << "This sample is meant for mvBlueCOUGAR-X devices only. Other devices might be installed" << endl
<< "but won't be recognized by the application." << endl
<< endl;
DeviceManager devMgr;
std::vector<mvIMPACT::acquire::Device*> validDevices;
if( getValidDevices( devMgr, validDevices, isDeviceSupportedBySample ) < 2 )
{
cout << "This sample needs at least 2 valid devices(one master and one slave). " << validDevices.size() << " device(s) has/have been detected." << endl
<< "Unable to continue! Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
cout << "Please select the MASTER device(the one that will create the trigger for all devices).\n\n";
Device* pMaster = getDeviceFromUserInput( devMgr, isDeviceSupportedBySample, true );
if( !pMaster )
{
cout << "Master device has not been properly selected. Unable to continue!\n"
<< "Press [ENTER] to end the application\n";
cin.get();
return 1;
}
set<Device*> setOfSlaves;
do
{
cout << "\nPlease select a SLAVE device(this one will be triggered by the master).\n\n";
Device* p = getDeviceFromUserInput( devMgr, isDeviceSupportedBySample, true );
if( p == pMaster )
{
cout << "Master and slave must be different. Skipped!" << endl;
}
else if( p )
{
if( setOfSlaves.find( p ) == setOfSlaves.end() )
{
setOfSlaves.insert( p );
}
else
{
cout << "ALL slaves must be different. This one has already been selected. Skipped!" << endl;
}
}
cout << "\nAdd another slave device('y')? ";
}
while( _getch() == 'y' );
cout << endl;
vector<DeviceData*> devices;
devices.push_back( new DeviceData( pMaster ) );
set<Device*>::const_iterator it = setOfSlaves.begin();
set<Device*>::const_iterator itEND = setOfSlaves.end();
while( it != itEND )
{
devices.push_back( new DeviceData( *it ) );
++it;
}
const vector<DeviceData*>::size_type DEV_COUNT = devices.size();
DigitalOutput* pTriggerOutput = 0;
try
{
for( vector<DeviceData*>::size_type i = 0; i < DEV_COUNT; i++ )
{
cout << "Initialising device " << devices[i]->device()->serial.read() << "..." << endl;
devices[i]->init( ( ( i == 0 ) ? string( "Master " ) : string( "Slave " ) ) + devices[i]->device()->serial.read() );
cout << endl
<< "Setup the " << ( ( i == 0 ) ? "MASTER" : "SLAVE" ) << " device:" << endl
<< "===========================" << endl
<< endl;
if( i == 0 )
{
const unsigned int digoutCount = devices[i]->IOSS()->getOutputCount();
for( unsigned int digOut = 0; digOut < digoutCount; digOut++ )
{
cout << " [" << digOut << "]: " << devices[i]->IOSS()->output( digOut )->getDescription() << endl;
}
cout << endl
<< "Select the digital OUTPUT of the MASTER device(" << devices[i]->device()->serial.read() << ") where the trigger pulse shall be generated on: ";
pTriggerOutput = devices[i]->IOSS()->output( getNumberFromUser() );
cout << endl;
}
setupTriggerInput( devices[i] );
}
}
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 devices(error code: " << e.getErrorCodeAsString() << ")." << endl
<< "Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
try
{
// get trigger frequency from user
unsigned int triggerFrequency_Hz = 0;
bool boRun = true;
while( boRun )
{
cout << "Please enter the approx. desired trigger frequency in Hz: ";
triggerFrequency_Hz = getNumberFromUser();
if( ( triggerFrequency_Hz >= 1 ) && ( triggerFrequency_Hz <= 100 ) )
{
boRun = false;
continue;
}
cout << "Invalid Selection. This sample will accept values from 1 - 100." << endl;
}
TriggerSignal triggerSignal( pTriggerOutput, triggerFrequency_Hz );
HANDLE* pHandles = new HANDLE[DEV_COUNT];
// start live threads
for( unsigned int j = 0; j < DEV_COUNT; j++ )
{
unsigned int dwThreadID;
pHandles[j] = ( HANDLE )_beginthreadex( 0, 0, liveThread, ( LPVOID )devices[j], 0, &dwThreadID );
}
// now all capture threads will start running...
// before starting the trigger thread wait a little bit to allow the camera threads to set up completely
Sleep( 1000 );
HANDLE hTriggerThread;
unsigned int dwTriggerThreadID;
hTriggerThread = ( HANDLE )_beginthreadex( 0, 0, triggerThread, ( LPVOID )&triggerSignal, 0, &dwTriggerThreadID );
{
LockedScope lockedScope( g_critSect );
cout << "Press [ENTER] to end the acquisition" << endl;
}
if( _getch() == EOF )
{
printf( "Calling '_getch()' did return EOF...\n" );
}
// stop all threads again
{
LockedScope lockedScope( g_critSect );
cout << "Terminating threads..." << endl;
}
for( unsigned int k = 0; k < DEV_COUNT; k++ )
{
devices[k]->terminateThread();
}
triggerSignal.terminateThread();
// wait until each live thread has terminated...
WaitForMultipleObjects( static_cast<DWORD>( DEV_COUNT ), pHandles, true, INFINITE );
for( unsigned int l = 0; l < DEV_COUNT; l++ )
{
CloseHandle( pHandles[l] );
}
// ... and then for the trigger thread to terminate
WaitForSingleObject( hTriggerThread, INFINITE );
CloseHandle( hTriggerThread );
hTriggerThread = 0;
delete [] pHandles;
}
catch( const ImpactAcquireException& e )
{
cout << "An error occurred(error code: " << e.getErrorCodeAsString() << ")." << endl;
cout << "Press [ENTER] to end the application" << endl;
cin.get();
return 1;
}
cout << "Press [ENTER] to end the application" << endl;
cin.get();
return 0;
}
mvBlueCOUGAR related camera settings (Device specific interface layout only).
Definition: mvIMPACT_acquire.h:19748
std::string name(void) const
Returns the name of the component referenced by this object.
Definition: mvIMPACT_acquire.h:1089
Grants access to devices that can be operated by this software interface.
Definition: mvIMPACT_acquire.h:6960
This class and its functions represent an actual device detected by this interface in the current sys...
Definition: mvIMPACT_acquire.h:5944
PropertyS product
A string property (read-only) containing the product name of this device.
Definition: mvIMPACT_acquire.h:6338
void open(void)
Opens a device.
Definition: mvIMPACT_acquire.h:6234
A class to represent a digital output pin(Device specific interface layout only).
Definition: mvIMPACT_acquire.h:15147
std::string getDescription(void) const
Returns a description for this digital output.
Definition: mvIMPACT_acquire.h:15210
The function interface to devices supported by this interface.
Definition: mvIMPACT_acquire.h:10439
int imageRequestWaitFor(int timeout_ms, int queueNr=0) const
Waits for a request object to become ready.
Definition: mvIMPACT_acquire.h:11331
int imageRequestUnlock(int nr) const
Unlocks the request for the driver again.
Definition: mvIMPACT_acquire.h:11299
int imageRequestSingle(ImageRequestControl *pImageRequestControl=0, int *pRequestUsed=0) const
Sends an image request to the mvIMPACT::acquire::Device driver.
Definition: mvIMPACT_acquire.h:11218
bool isRequestNrValid(int nr) const
Check if nr specifies a valid mvIMPACT::acquire::Request.
Definition: mvIMPACT_acquire.h:11466
int imageRequestReset(int requestCtrlNr, int mode) const
Deletes all requests currently queued for the specified mvIMPACT::acquire::ImageRequestControl.
Definition: mvIMPACT_acquire.h:11165
Request * getRequest(int nr) const
Returns a pointer to the desired mvIMPACT::acquire::Request.
Definition: mvIMPACT_acquire.h:10904
A base class to handle digital inputs and outputs(Device specific interface layout only).
Definition: mvIMPACT_acquire.h:15978
A base class for exceptions generated by mvIMPACT Acquire.
Definition: mvIMPACT_acquire.h:248
std::string getErrorCodeAsString(void) const
Returns a string representation of the error associated with the exception.
Definition: mvIMPACT_acquire.h:280
std::string read(int index=0) const
Reads a value from a property.
Definition: mvIMPACT_acquire.h:5159
std::string readS(int index=0, const std::string &format="") const
Reads data from this property as a string.
Definition: mvIMPACT_acquire.h:3213
Contains information about a captured buffer.
Definition: mvIMPACT_acquire.h:8404
PropertyI64 infoFrameID
A 64 bit integer property (read-only) containing a frame identifier.
Definition: mvIMPACT_acquire.h:9538
bool isOK(void) const
Convenience function to check if a request has been processed successfully.
Definition: mvIMPACT_acquire.h:9193
PropertyIRequestResult requestResult
An enumerated integer property (read-only) defining the result of this request.
Definition: mvIMPACT_acquire.h:9496
PropertyI64 infoFrameNr
A 64 bit integer property (read-only, zero-based) containing the number of image requests processed s...
Definition: mvIMPACT_acquire.h:9545
Contains basic statistical information.
Definition: mvIMPACT_acquire.h:14155
PropertyF framesPerSecond
A float property (read-only) containing the current number of frames captured per second.
Definition: mvIMPACT_acquire.h:14222
PropertyI errorCount
An integer property (read-only) containing the overall count of image requests which returned with an...
Definition: mvIMPACT_acquire.h:14214
PropertyI frameCount
An integer property (read-only) containing the overall count of images captured since the mvIMPACT::a...
Definition: mvIMPACT_acquire.h:14228
A class that can be used to display images in a window.
Definition: mvIMPACT_acquire_display.h:582
A class that can be used for displaying images within existing windows or GUI elements that can provi...
Definition: mvIMPACT_acquire_display.h:172
void RemoveImage(void)
Removes the current image from the display.
Definition: mvIMPACT_acquire_display.h:371
void SetImage(const void *pData, int width, int height, int bitsPerPixel, int pitch)
Sets the next image to display.
Definition: mvIMPACT_acquire_display.h:292
void Update(void) const
Immediately redraws the current image.
Definition: mvIMPACT_acquire_display.h:381
TDMR_ERROR
Errors reported by the device manager.
Definition: mvDriverBaseEnums.h:2260
const int INVALID_ID
A constant to check for an invalid ID returned from the property handling module.
Definition: mvPropHandlingDatatypes.h:67
@ DMR_NO_ERROR
The function call was executed successfully.
Definition: mvDriverBaseEnums.h:2265
This namespace contains classes and functions that can be used to display images.
This namespace contains classes and functions belonging to the image acquisition module of this SDK.
Definition: mvImageBuffer.h:42