Starting and stopping acquisition in GenTL

Hello,

I have an application where I need to start and stop acquisition frequently to set parameters on the camera which can be set while the camera is acquiring. For instance, saving and loading usersets.

The code I use for starting and stopping is below, together with the code that is running in a separate thread waiting for images to be available.

I frequently end up with the using
var streamImage = _genTlStream.WaitFor(_timeout);
throwing an exception

Acquisition:Acquisition Exception System.OperationCanceledException: GEVTL.cti▸FD::MAC->00-15-17-BB-5F-15▸::ID->00-0C-DF-0A-5C-A0::192.168.3.1 acquisition error.
—> Stemmer.Cvb.CvbException (0x80000014): GEVTL.cti▸FD::MAC->00-15-17-BB-5F-15▸::ID->00-0C-DF-0A-5C-A0::192.168.3.1 acquisition error.
— End of inner exception stack trace —
at Stemmer.Cvb.Driver.CompositeStreamBase.ThrowOnNonOkWaitStatus(WaitStatus status, String debugLocator)
at Stemmer.Cvb.Driver.ImageStream.WaitFor(UsTimeSpan timeout)
at Vim.Cvb.Acquisition.Acquisition.WaitProcessor() in C:\Projects\Calibre\Libraries\Vim\Cvb\Acquisition\Acquisition.cs:line 382
Inner Exception GEVTL.cti▸FD::MAC->00-15-17-BB-5F-15▸::ID->00-0C-DF-0A-5C-A0::192.168.3.1 acquisition error.

This occurs despite the stop operation being successful and the start being OK and status being reported as started.

Once this exception is seen I have to restart the application, not just acquisition.

Can you suggest what I may be doing wrong?

public void Grab(bool live)
{
if (!MasterEnable || _device == null)
return;

    try
    {
        if (live)
        {
            if (IsAcquiring) return;
            Si.Logger.LogMessage("Go Live " + Name);

            TotalFrameCount = 0;
            if (_genTlStream != null)
                _genTlStream.Start();
            else
                _vinStream?.Start();

            IsAcquiring = true;
        }
        else
        {
            Si.Logger.LogMessage("Go Stop " + Name);
            if (_genTlStream != null)
                _genTlStream.Abort();
            else
                _vinStream?.Abort();

            if (_genTlStream != null) 
                Si.Logger.LogMessage(Name + " Acquisition State " + _genTlStream.AcquisitionState);

            IsAcquiring = false;
        }
    }
    catch (Exception e)
    {
        Trace.WriteLine(Name + ":Exception starting or stopping acquisition " + e);
    }
}

And now the Wait Processor thread…
protected override bool WaitProcessor()
{
var result = false;

    if (_device != null && MasterEnable && IsOnline && IsAcquiring)
        try
        {
            if (_genTlStream != null)
            {
                using var streamImage = _genTlStream.WaitFor(_timeout);
                CurrentImage?.Dispose();
                CurrentImage = streamImage.Copy();
                result = true; // We have a valid frame
            }
            else if (_vinStream != null)
            {
                using var streamImage = _vinStream.WaitFor(_timeout);
                CurrentImage?.Dispose();
                CurrentImage = streamImage.Copy();
                result = true; // We have a valid frame
            }
        }
        catch (TimeoutException)
        {
            // Timeout so ignore
        }
        catch (Exception e)
        {
            Trace.WriteLine("Acquisition:" + Name + " Exception " + e+"\nInner Exception "+e.InnerException?.Message );
        }
    else
        Thread.Sleep(100);

    return result;
}

Hi @BitSmith ,

I assume this might be a timing problem here.
You check for IsAcquiring in you Acquisition Thread.
IsAcquiring however is set from another Thread.
When Aborting the Stream, you might run into the case, that the following line ist still true:
if (_device != null && MasterEnable && IsOnline && IsAcquiring)
because the stream has been stopped in another thread but IsAquiring was not yet set to false.

This leaves you with a corrupt state of your application.

Instead of IsAcquiring you should check for Stream.IsRunning, this automatically changes whenever you start or stop the stream and thus should be more reliable than another field.

Cheers
Chris

Thanks Chris,

I will have a look and see if that help.

Best Regards
Steve

Hi Steve,

any updates on this?

Hi Chris,

Maybe :slight_smile: Needs more testing.

As a user I feel this API is a little fragile and not particularly intuitive when things go wrong. There are several things that I can do which result in exceptions that don’t mean anything unless you understand how this is implemented internally. Like Index out of range or dictionary exceptions if the images are not disposed of correctly. In my opinion the API should protect me (or itself) from me breaking it and at least through exceptions that are more obvious. This one is a good example.

Thanks for the support
Steve