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.
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.
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:
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
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
function isAcquisitionNotComplete()
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 function isSendFrame()
.
This is how the toolbox implements the FrameGrabInterval
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
object makeFrame()
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
object setImage()
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
function setTime()
. Device SDKs sometimes provide
access to time stamp information, but you can also use the adaptor
kit getCurrentTime()
function.
Send the packaged frame to the
engine, using the IEngine
member function receiveFrame()
.
Increment the frame count using the IAdaptor
member
function incrementFrameCount()
. 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
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 Docs.
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; }