Connection Monitoring

<< Click to Display Table of Contents >>

Navigation:  CVB with GenICam > SDK >

Connection Monitoring

 

With our GenICam architecture it is possible to be informed if a device disconnects or reconnects.

This is called Connection Monitoring and  is supported with GigE Vision.

 

This feature can be useful if a device temporarily loose its power and the connection needs to be re-established.

The Connection Monitoring is realized over the INotify interface with its DEVICE_DISCONNECTED and DEVICE_RECONNECT event.

 

Important Notes:

Configure the devices with a persistent IP address and do not use DHCP to be able to get reconnected events.

When the camera is reconnected the driver should be reloaded to ensure if camera and driver are in correct status again.

There is no need to reload the driver when you do not use special driver configuration (working with defaults).

Do not unload (ReleaseObject) the camera IMG inside the callback thread.

Do not call G2Freeze() and G2Grab() within the callback itself.

The callback functions should only be used to inform your acquisition state that it need to be stopped or started.

The INotify callbacks are fired from an internal thread context, thus be careful when accessing the GUI.
 

 

Sample code how to use the INotify Interface for Connection Monitoring:

 

C++ Connection Monitoring Example (CVB 2017 - 13.x.x)

 

#include <atomic>

#include <cassert>

#include <iostream>

#include <sstream>

#include <stdexcept>

#include <thread>

 

#include <iCVCImg.h>

#include <iCVCDriver.h>

#include <iDC_GenICam.h>

 

// main function is below

// vvvvvvvvvvvvvvvvvvvvvv

 

class Camera 

{

  IMG handle_; // the driver image

  std::atomic<bool> isConnected_; // the connection state

 

public:

  Camera() 

    : handle_(OpenCamera())

    , isConnected_(true)

  {

    InitCamera();

  }

 

  Camera(const Camera &) = delete; // no copy

  Camera &operator =(const Camera &) = delete; // no copy

 

  virtual ~Camera()

  {

    Unload();

  }

 

  bool IsConnected() const

  {

    return isConnected_;

  }

 

  void Reload()

  {

    // this method cannot be implemented with any exception safety:

    // to get a clean start we need to unload first

    Unload();

 

    handle_ = OpenCamera();

    InitCamera();

  }

 

private:

  // opens the first camera and returns its handle; throws on error

  static IMG OpenCamera()

  {

    if(const char *cvbDir = std::getenv("CVB"))

    {

      std::stringstream path;

      path << cvbDir << "Drivers/GenICam.vin";

      IMG handle = nullptr;

      if(LoadImageFile(path.str().c_str(), handle))

        return handle;

    }

 

    throw std::runtime_error("Error opening GenICam.vin");

  }

 

  void InitCamera()

  {

    assert(CanNotify(handle_));

    assert(IsEventAvailable(CVNO_EID_DEVICE_DISCONNECTED));

    assert(IsEventAvailable(CVNO_EID_DEVICE_RECONNECT));

 

    RegisterEvent(CVNO_EID_DEVICE_DISCONNECTED, &Camera::OnDisconnectedDispatcher);

    RegisterEvent(CVNO_EID_DEVICE_RECONNECT, &Camera::OnReconnectDispatcher);

  }

 

  bool IsEventAvailable(CVNotifyEvent_t id) const

  {

    cvbint64_t status = 0;

    if(cvbres_t error = NOGetStatus(handle_, id, CVNO_INFO_IS_AVAILABLE, status))

      throw std::runtime_error("Error getting INotify event availability");

 

    return status != 0;

  }

 

  void RegisterEvent(CVNotifyEvent_t id, CVBDRIVER_NOTIFY_CB callback)

  {

    intptr_t ignored = 0; // we do not want to unregister the event

    if(cvbres_t error = NORegister(handle_, id, callback, this, ignored))

      throw std::runtime_error("Error registering INotify event");      

  }

 

  static void __stdcall OnDisconnectedDispatcher(CVNotifyEvent_t /*id*/, void * /*buffer*/, size_t /*bufferSize*/, CVNotifyDatatype_t /*bufferDataType*/, void *pThis)

  {

    // called from non-main thread context

    reinterpret_cast<Camera *>(pThis)->OnDisconnected();

  }

 

  void OnDisconnected()

  {

    isConnected_ = false;

  }

 

  static void __stdcall OnReconnectDispatcher(CVNotifyEvent_t /*id*/, void * /*buffer*/, size_t /*bufferSize*/, CVNotifyDatatype_t /*bufferDataType*/, void *pThis)

  {

    // called from non-main thread context

    reinterpret_cast<Camera *>(pThis)->OnReconnect();

  }

 

  void OnReconnect()

  {

    isConnected_ = true;

  }

 

  void Unload()

  {

    ReleaseObject(handle_);

    assert(handle_ == nullptr);

  }

};

 

 

int main()

{

  try

  {

    Camera camera;

 

    std::cout << "Opened first GenICam camera (connected)...\n";

 

    bool connected = true;

    while(true)

    {

      if(connected != camera.IsConnected())

      {

        connected = !connected; // toggle local state

 

        if(!connected)

        {

          std::cout << "Disconnected! Waiting for reconnect...\n";

        }

        else

        {

          std::cout << "Reconnected! Reloading...";

          camera.Reload();

          std::cout << " done.\n";

        }

      }

 

      std::this_thread::sleep_for(std::chrono::milliseconds(100));

    }

  }

  catch(std::exception &ex)

  {

    std::cerr << ex.what() << "\n";

  }

 

  return 0;

}

 

 

 

C# Connection Monitoring Example (CVB 2017 - 13.x.x)

 

{{{
using System;
using System.Threading.Tasks;
using System.Diagnostics;
using static Cvb.Image;
using static Cvb.Driver.INotify;
namespace ConnectionMonitoringExample
{
  class Program
  {
    static void Main(string[] args)
    {
      try
      {
        Camera camera = new Camera();
        Console.WriteLine("Loaded first connected GenICam camera.");
        bool connected = true;
        while (true)
        {
          if (connected != Camera.IsConnected)
          {
            connected = !connected; // toggle local state
            if (!connected)
            {
              Console.WriteLine("Camera disconnected, waiting for  reconnected event!");
            }
            else
            {
              Console.WriteLine("Camera reconnected, reloading...");
              camera.Reload();
              Console.WriteLine("Camera is up and ready");
              connected = true;
            }
          }
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }
    class Camera : IDisposable
    {
      // The delegates MUST be stored as they are given to native code  which is not visible
      // for the garbage collector
      private static NONOTIFYCALLBACK disconnectedEvent;
      private static NONOTIFYCALLBACK reconnectedEvent;
      private IMG _handle; // handle of the driver
      public Camera()
      {
        _handle = OpenCamera();
        InitCamera();
      }
      private static IMG OpenCamera()
      {
        IMG camera;
        string driverString = Environment.ExpandEnvironmentVariables("%CVB%" + @"\Drivers\GenICam.vin");
        bool success = LoadImageFile(driverString, out camera);
        if (!success)
          throw new Exception("Camera could not be loaded");
        return camera;
      }
      #region Finalizer / IDisposable
      ~Camera()
      {
        Dispose(false);
      }
      public void Dispose()
      {
        Dispose(true);
        GC.SuppressFinalize(this);
      }
      protected virtual void Dispose(bool disposing)
      {
        if (!IsDisposed)
        {
          ReleaseObj(_handle);
          _handle = IntPtr.Zero;
        }
      }
      public bool IsDisposed
      {
        get
        {
          return _handle != IntPtr.Zero;
        }
      }
      #endregion
      public static bool IsConnected { getprivate set; } = true;
      void InitCamera()
      {
        Debug.Assert(CanNotify(_handle)); Debug.Assert(IsEventAvailable(CVNotifyEventID.DEVICE_DISCONNECTED));
        Debug.Assert(IsEventAvailable(CVNotifyEventID.DEVICE_RECONNECT));
        disconnectedEvent = DeviceDisconnectedEvent;
        reconnectedEvent = DeviceReconnectedEvent;
        RegisterEvent(CVNotifyEventID.DEVICE_DISCONNECTED,disconnectedEvent);
        RegisterEvent(CVNotifyEventID.DEVICE_RECONNECT, reconnectedEvent);
        Debug.WriteLine("Camera initialized");
      }
      private bool IsEventAvailable(CVNotifyEventID id)
      {
        long status = 0;
        if (NOGetStatus(_handle, id, CVNotifyInfoCmd.IS_AVAILABLE, out status) < 0)
          throw new NotSupportedException("Error getting INotify event  availability");
        return status != 0;
      }
      private void RegisterEvent(CVNotifyEventID id, NONOTIFYCALLBACK callback)
      {
        IntPtr cookie;
        long info;
        info = NORegister(_handle, id, callback, IntPtr.Zero, out cookie);
        if (info < 0)
          Console.WriteLine("Registering INotifyEvent failed!");
        Debug.WriteLine("Event" + id.ToString() + "initialized!");
      }
      private static void DeviceDisconnectedEvent(CVNotifyEventID eventID, IntPtr buffer, int Size, CVNotifyDataType DataType, IntPtr UserData)
      {
        // event is fired from a driver thread that is not the UI thread!
        IsConnected = false;
        Task.Run(() =>
        {
          Debug.WriteLine("Disconnected event triggered successfully!");
        });
      }
      private static void DeviceReconnectedEvent(CVNotifyEventID eventID, IntPtr buffer, int Size, CVNotifyDataType DataType, IntPtr UserData)
      {
        // event is fired from a driver thread that is not the UI thread!
        Task.Run(() =>
        {
          IsConnected = true;
          Debug.WriteLine("Reconnected event triggered successfully!");
        });
      }
      public void Reload()
      {
        Unload();
        _handle = OpenCamera();
        InitCamera();
        Debug.WriteLine("Camera reloaded!");
      }
      void Unload()
      {
        ReleaseObj(_handle);
        Debug.Assert(_handle == IntPtr.Zero);
      }
    }
  }
}
}}}