Main Content

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

Flowchart that shows how the openDevice and startCapture functions interact with the thread message loop and frame acquisition loop. It also shows that the closeDevice function can be used to send a message to the thread message loop that terminates the frame acquisition loop.

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:

  1. 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.

  2. If your adaptor supports hardware triggers, you would check whether a hardware trigger is configured here — Supporting Hardware Triggers.

  3. 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.

  4. 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.

    1. 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.

    2. 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.

    3. 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.

    4. Send the packaged frame to the engine, using the IEngine member function receiveFrame().

  5. 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.

  6. 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;
}