Implementing the Acquisition Thread Function
This section describes how to implement your adaptor's acquisition thread function. In a threaded adaptor design, the acquisition thread function performs the actual acquisition of frames from the device. When you create the thread (Opening and Closing Connection with a Device), you specify the name of this acquisition thread function as the starting address for the new thread.
User Scenario
The toolbox engine invokes the acquisition thread function indirectly when a user
calls the start
, getsnapshot
, or
preview
function. Once called, the acquisition thread
function acquires frames until the specified number of frames has been acquired or
the user calls the stop
function.
Suggested Algorithm
Note
The design of the acquisition thread function can vary significantly between various adaptors, depending on the requirements of the device's SDK. This section does not describe device-dependent implementation details but rather highlights required tasks that are common to all implementations.
At its highest level, in a threaded design, an acquisition thread function typically contains two loops:
Thread Message Loop
The thread message loop is the main processing loop in the acquisition thread
function. You create the thread in the openDevice()
function.
The acquisition thread function enters the thread message loop, waiting for the
message to start acquiring frames. Your adaptor's
startCapture()
function sends the message to the
acquisition thread, telling it to start acquiring frames. This example uses the
WM_USER
message to indicate this state. See Sending a Message to the Acquisition Thread for more information.
When it receives the appropriate message, the acquisition thread function enters the frame acquisition loop. The following figure illustrates this interaction between your adaptor functions and the acquisition thread. For information about the frame acquisition loop, see Frame Acquisition Loop.
Interaction of Adaptor Functions and Acquisition Thread
Frame Acquisition Loop
The frame acquisition loop is where your adaptor acquires frames from the device and sends them to the engine. This process involves the following steps:
Check whether the specified number of frames has been acquired. The frame acquisition loop acquires frames from the device until the specified number of frames has been acquired. Use the
IAdaptor
member functionisAcquisitionNotComplete()
to determine if more frames are needed.If your adaptor supports hardware triggers, you would check whether a hardware trigger is configured here — Supporting Hardware Triggers.
Grab a frame from the device. This code is completely dependent on your device SDK's API. With many device SDKs, you allocate a buffer and the device fills it with image data. See your device's API documentation to learn how to get frames from your device.
Check whether you need to send the acquired frame to the engine, using the
IAdaptor
member functionisSendFrame()
. This is how the toolbox implements theFrameGrabInterval
property, where users can specify that they only want to acquire every other frame, for example.If you need to send a frame to the engine, package the frame in an
IAdaptorFrame
object; otherwise, skip to step 5.Create a frame object, using the
IEngine
objectmakeFrame()
member function. You must specify the image frame dimensions and frame type when you create the frame object.Put the acquired image data into the frame object, using the
IAdaptorFrame
objectsetImage()
member function. You specify a pointer to the buffer that contains the image data, the frame width and height and any offsets from the upper left corner of the image.Note
For information about specifying frame width, height, and offset with ROIs, see Supporting ROIs.
Log the time of the acquisition in the frame object, using the
IAdaptorFrame
member functionsetTime()
. Device SDKs sometimes provide access to time stamp information, but you can also use the adaptor kitgetCurrentTime()
function.Send the packaged frame to the engine, using the
IEngine
member functionreceiveFrame()
.
Increment the frame count using the
IAdaptor
member functionincrementFrameCount()
. Whether you need to send a frame or not, you must always increment the frame count whenever you acquire a frame.Return to the top of the frame acquisition loop.
The following figure illustrates the frame acquisition loop.
A Possible Algorithm for the Frame Acquisition Loop
Example
The following is a declaration of an acquisition thread function. You can give
your acquisition thread procedure any name, such as
acquireThread()
.
DWORD WINAPI acquireThread(void* ThreadParam);
Your thread function must accept a single parameter, which is defined as a pointer
to the object itself, i.e., the this
pointer. The thread function
returns a value that indicates success or failure. For more information, see Microsoft documentation.
The following is an acquisition thread function that you can use with the example
MyDeviceAdaptor
. Replace the skeletal implementation you used
in Starting an Acquisition Thread with this
code.
DWORD WINAPI MyDeviceAdaptor::acquireThread(void* param) { MyDeviceAdaptor* adaptor = reinterpret_cast<MyDeviceAdaptor*>(param); MSG msg; while (GetMessage(&msg,NULL,0,0) > 0) { switch (msg.message) { case WM_USER: // Check if a frame needs to be acquired. while(adaptor->isAcquisitionNotComplete()) { // Insert Device-specific code here to acquire frames // into a buffer. if (adaptor->isSendFrame()) { // Get frame type & dimensions. imaqkit::frametypes::FRAMETYPE frameType = adaptor->getFrameType(); int imWidth = adaptor->getMaxWidth(); int imHeight = adaptor->getMaxHeight(); // Create a frame object. imaqkit::IAdaptorFrame* frame = adaptor->getEngine()->makeFrame(frameType, imWidth, imHeight); // Copy data from buffer into frame object. frame->setImage(imBuffer, imWidth, imHeight, 0, // X Offset from origin 0); // Y Offset from origin // Set image's timestamp. frame->setTime(imaqkit::getCurrentTime()); // Send frame object to engine. adaptor->getEngine()->receiveFrame(frame); } // if isSendFrame() // Increment the frame count. adaptor->incrementFrameCount(); } // while(isAcquisitionNotComplete() break; } //switch-case WM_USER } //while message is not WM_QUIT return 0; }