EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: asynDriver R4-21: a possible patch for asynRecord.c: test on GigE camera
From: "Feng, Kate" <[email protected]>
To: "[email protected]" <[email protected]>
Date: Thu, 6 Jun 2013 14:53:57 +0000
Hi,

     I got a chance to test the interactions of connect/disconnect between two
Prosilica GigE cameras within one Linux IOC. For your consideration, the attached patches
are based on areaDetectorR1-9-1, and asyn4-21.  In addition to the bug fix, which was
contributed on May 16, it fixes the following bugs:

1) Originally, only the 1st camera responded to the connect/disconnect callback function
due to one of the rules for the function PvLinkCallbackRegister(), which is 
"The same callback function with the same event may not be registered twice".
Thus, the IOC did not know the connect/disconnect of other cameras (e.g. the 2nd camera).
The prosilica.diff patch fixes this problem by registering a static cameraLinkCallback()
function only once. It handles the connect/disconnect of all the cameras in the IOC.
 
2) Originally, if more than one camera is not connected at the start of the IOC,
it would be difficult to tell which camera is reconnected because the IDs 
of the unconnected cameras might be unknown.  Thus, I added 'uniqueIP' as a private variable
in the 'C++ class prosilica' to keep track of the IP addresses of each cameras in the system
in case the unique ID is unknown. By comparing the unique ID or the IP address, one can match 
the newly connected camera with the right one in the EPICS database (i.e. PVs).

    The patch should work if there are more than two cameras. Hope that this helps.

    Cheers,
    Kate Feng

________________________________________
From: [email protected] [[email protected]] on behalf of Kate Feng [[email protected]]
Sent: Thursday, May 16, 2013 2:14 PM
To: [email protected]
Subject: asynDriver R4-21: a possible patch for asynRecord.c: test on GigE      camera

Hi,

    I am using the asynDriver R4-21 to run Mark River's areaDetectorR1-9-1
software on a Prosilica (i.e. Allied) GigE camera.  Everything works
very well
except when the camera becomes offline (e.g. the Ethernet cable for the
Prosilica GigE camera is disconnected). Thankfully, the medm screen
indicated
the "disconnect" status when the Ethernet cable for the Prosilica GE
camera is
disconnected.  However, one could still hit the 'acquire start/stop' and
other buttons
via the medm GUI and access the PVs.

   One would wish to have a more detectable effect so that one could not
access
the camera's PVs, when the camera became offline.  The attached patch
will disable
the PVs access, if the Ethernet cable for the GigE camera is
disconnected.  If
the camera becomes online via Ethernet, the PVs will be accessible again.

   The patch is tested with the  GigE camera.

   Cheers,
   Kate Feng




--- prosilicaSrc/prosilica.cpp.orig	2013-02-17 10:15:03.000000000 -0500
+++ prosilicaSrc/prosilica.cpp	2013-06-06 09:40:56.347820082 -0400
@@ -42,10 +42,7 @@
 
 #define MAX_PVAPI_FRAMES  2  /**< Number of frame buffers for PvApi */
 #define MAX_PACKET_SIZE 8228
- 
-/* Static functions to interface with PvAPI */
-static void PVDECL GlobalCameraLinkCallback(void* Context, tPvInterface Interface, 
-                                            tPvLinkEvent Event, unsigned long UniqueId);
+
                                      
 /** Driver for Prosilica GigE and CameraLink cameras using their PvApi library */
 class prosilica : public ADDriver {
@@ -66,7 +63,7 @@
     
     /* These are called from C and so must be public */
      /* This is called by the AVT driver when the connection status of a camera changes */
-    asynStatus cameraLinkCallback(tPvInterface Interface, tPvLinkEvent Event, unsigned long UniqueId);
+    static void PVDECL cameraLinkCallback(void* Context, tPvInterface Interface, tPvLinkEvent Event, unsigned long UniqueId);
     void frameCallback(tPvFrame *pFrame);
     /* Removes the PvAPI callback functions and disconnects the camera */
     static void shutdown(void *arg);
@@ -124,6 +121,7 @@
     /* These items are specific to the Prosilica driver */
     tPvHandle PvHandle;            /* GenericPointer for the Prosilica PvAPI library */
     char *cameraId;                /* This can be a uniqueID, IP name, or IP address */
+    unsigned long uniqueIP;
     unsigned long uniqueId;
     tPvCameraInfoEx PvCameraInfo;
     tPvFrame *PvFrames;
@@ -264,6 +262,10 @@
 #define PSStrobe1CtlDurationString   "PS_STROBE_1_CTL_DURATION"/* (asynInt32,    r/w) Strobe 1 controlled duration */
 #define PSStrobe1DurationString      "PS_STROBE_1_DURATION"    /* (asynFloat64,  r/w) Strobe 1 duration */
 
+#define MAX_PROSILICA_CAM 20 
+static int numOfProsilicaCam=0;
+static prosilica *pProsilicaDriver[MAX_PROSILICA_CAM];
+
 void prosilica::shutdown (void* arg) {
 
     prosilica *p = (prosilica*)arg;
@@ -275,21 +277,25 @@
 
     int status;
     static const char *functionName = "~prosilica";
+    prosilica *p = (prosilica*) this;
 
     this->lock();
     disconnectCamera();
     this->unlock();
-    status = PvLinkCallbackUnRegister(GlobalCameraLinkCallback, ePvLinkAdd);
-    if (status) {
-        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
+
+    if (p->uniqueId== pProsilicaDriver[0]->uniqueId) {
+       status = PvLinkCallbackUnRegister(p->cameraLinkCallback, ePvLinkAdd);
+       if (status) {
+          asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
             "%s:%s: error calling PvLinkCallbackUnRegister for ePvLinkAdd, status=%d\n",
             driverName, functionName, status);
-    }
-    status = PvLinkCallbackUnRegister(GlobalCameraLinkCallback, ePvLinkRemove);
-    if (status) {
-        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
+        }
+        status = PvLinkCallbackUnRegister(p->cameraLinkCallback, ePvLinkRemove);
+        if (status) {
+           asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
             "%s:%s: error calling PvLinkCallbackUnRegister for ePvLinkRemove, status=%d\n",
             driverName, functionName, status);
+        }
     }
 
     if (PvApiInitialized) {
@@ -297,50 +303,67 @@
         PvUnInitialize();
         PvApiInitialized = false;
     }
-}
-
-
-// callback function called on seperate thread when a registered camera event received
-void PVDECL GlobalCameraLinkCallback(void* Context,
-                                     tPvInterface Interface,
-                                     tPvLinkEvent Event,
-                                     unsigned long UniqueId) {
- 
-    prosilica *p = (prosilica*)Context;
-    if ( p ) p->cameraLinkCallback(Interface, Event, UniqueId);
+	
 }
 
 // Changes the connection status of the camera based on information from the AVT library
-asynStatus prosilica::cameraLinkCallback( tPvInterface Interface, tPvLinkEvent Event, unsigned long UniqueId ) {
+void PVDECL prosilica::cameraLinkCallback(void* Context, tPvInterface Interface, tPvLinkEvent Event, unsigned long UniqueId ) {
 
     asynStatus status = asynSuccess;
+    int i, found=0;
     //static const char *functionName = "cameraLinkCallback";
-    
-    this->lock();
-    switch( Event ) {
+    unsigned long UniqueIp=0;
+
+    for (i=0; i <numOfProsilicaCam; i++) {
+        pProsilicaDriver[i]->lock();
+        switch( Event ) {
         case ePvLinkAdd: {
-            // We cannot check to see if the UniqueId matches ours, because the camera may have been
-            // specified by IP address or IP name and may never have connected yet, so we don't know its
-            // uniqueId.
-            // So instead whenever any camera comes online and we are not connected we try to connect to it, 
-            // in hopes that it is our camera.
-            if (this->PvHandle == 0) {
-                status = this->connectCamera();
+            // We need to check to see if the UniqueId matches ours. If the camera have been
+            // specified by IP address or IP name and may never have connected yet, we can find out
+            // if the IP address of this recently connected camera matches with ours.
+            if ( !pProsilicaDriver[i]->uniqueId) {
+	      if ( !UniqueIp)  { /* If we did not find out the IP address of this recently connected camera yet */
+		 tPvIpSettings ipSettings;
+
+		 PvCameraIpSettingsGet(UniqueId, &ipSettings);
+		 UniqueIp = ipSettings.CurrentIpAddress;
+              }
+	      if (UniqueIp == pProsilicaDriver[i]->uniqueIP) {
+                 status = pProsilicaDriver[i]->connectCamera();
+	       if (status) 
+                  printf("Camera uniqueIP 0x%lx connectCamera() error status %d\n",pProsilicaDriver[i]->uniqueIP, status);
+	       else
+		  found=1;
+              }
+	    }
+	    else {
+	      if ( UniqueId == pProsilicaDriver[i]->uniqueId) {
+                 status = pProsilicaDriver[i]->connectCamera();
+	         if (status) 
+                    printf("Camera uniqueId 0x%lx connectCamera() error status %d\n",pProsilicaDriver[i]->uniqueId, status);
+	         else
+		    found=1;
+              }
             }
             break;
         }
         case ePvLinkRemove: {
-            if( UniqueId == this->uniqueId ) {
+            if( UniqueId ==  pProsilicaDriver[i]->uniqueId ) {
                 // the camera has disconnected
-                status = this->disconnectCamera();
+                status = pProsilicaDriver[i]->disconnectCamera();
+		if (status) 
+		   printf("Camera uniqueId 0x%lx disconnectCamera() error status %d\n",pProsilicaDriver[i]->uniqueId, status);
+	        else
+		   found=1;
             }
             break;
         }
         default:
             break;
+        }
+        pProsilicaDriver[i]->unlock();
+	if (found) break;
     }
-    this->unlock();
-    return status;
 }
 
 
@@ -1076,7 +1099,7 @@
     /* First disconnect from the camera */
     disconnectCamera();
     
-    /* Determine if we have been passed a uniqueID (all characters in cameraId are digits), 
+    /* Determine if we have been passed an uniqueID (all characters in cameraId are digits), 
      * or an IP address (anything else) */
     isUniqueId = true;
     for (i=0; i<(int)strlen(this->cameraId); i++) {
@@ -1101,6 +1124,7 @@
                   driverName, functionName, this->cameraId);
             return asynError;
         }
+	this->uniqueIP = (unsigned long) ipAddr.s_addr;
         status = PvCameraInfoByAddrEx(ipAddr.s_addr, &this->PvCameraInfo, NULL, sizeof(this->PvCameraInfo));
         if (status) {
             asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
@@ -1582,35 +1606,46 @@
             driverName, functionName, status);
             return;
         }
+
+        tPvErr errCode;
+        prosilica *p= (prosilica*)this;
+
+        // register camera connection callback
+        if ((errCode = PvLinkCallbackRegister(p->cameraLinkCallback,ePvLinkAdd,(void*)this)) != ePvErrSuccess)
+           printf("PvLinkCallbackRegister err: %u\n", errCode);
+
+       // register camera disconnection callback
+       if((errCode = PvLinkCallbackRegister(p->cameraLinkCallback,ePvLinkRemove,(void*)this)) != ePvErrSuccess)
+           printf("PvLinkCallbackRegister err: %u\n", errCode);
+
         PvApiInitialized = 1;
     }
-    
-    tPvErr errCode;
-    // register camera connection callback
-    if((errCode = PvLinkCallbackRegister(GlobalCameraLinkCallback,ePvLinkAdd,(void*)this)) != ePvErrSuccess)
-        printf("PvLinkCallbackRegister err: %u\n", errCode);
-
-    // register camera disconnection callback
-    if((errCode = PvLinkCallbackRegister(GlobalCameraLinkCallback,ePvLinkRemove,(void*)this)) != ePvErrSuccess)
-        printf("PvLinkCallbackRegister err: %u\n", errCode);
-
-    /* Need to wait a short while for the PvAPI library to find the cameras (0.2 seconds is not long enough in 1.24) */
-    epicsThreadSleep(1.0);
-    
-    /* Try to connect to the camera.  
-     * It is not a fatal error if we cannot now, the camera may be off or owned by
-     * someone else.  It may connect later. */
-    this->lock();
-    status = connectCamera();
-    this->unlock();
-    if (status) {
-        printf("%s:%s: cannot connect to camera %s, manually connect when available.\n", 
+    if (numOfProsilicaCam < MAX_PROSILICA_CAM) {
+       /* Need to wait a short while for the PvAPI library to find the cameras (0.2 seconds is not long enough in 1.24) */
+       epicsThreadSleep(1.0);
+
+       /* Try to connect to the camera.  
+        * It is not a fatal error if we cannot now, the camera may be off or owned by
+        * someone else.  It may connect later. */
+       this->lock();
+       status = connectCamera();
+       this->unlock();
+        /* <skf> Add pointer to the prosilica driver (e,g, camera's uniqueId) for the PvLinkCallback even if it is not connected at this point */
+        pProsilicaDriver[numOfProsilicaCam++] = (prosilica*)this;
+
+	if (status) {	   
+           printf("%s:%s: cannot connect to camera %s, manually connect when available.\n", 
                driverName, functionName, cameraId);
-        return;
+      
+	   return;
+        }
+        /* Register the shutdown function for epicsAtExit */
+        epicsAtExit(shutdown, (void*)this);
+    }
+    else {
+      printf("The number of cameras configured is more than %d.\n", MAX_PROSILICA_CAM); 
+      exit(0);
     }
-    
-    /* Register the shutdown function for epicsAtExit */
-    epicsAtExit(shutdown, (void*)this);
 }
 
 /* Code for iocsh registration */
--- asynRecord/asynRecord.c.orig	2012-12-21 17:34:45.000000000 -0500
+++ asynRecord/asynRecord.c	2013-06-05 14:20:31.000000000 -0400
@@ -874,12 +874,33 @@
     asynPrint(pasynUser, ASYN_TRACE_FLOW,
               "%s: exception %d\n",
               pasynRec->name, (int) exception);
-    if(callLock)
-        dbScanLock((dbCommon *) pasynRec);
+
+    switch(exception) {
+    case asynExceptionConnect:
+         if (((pasynRec->udf) && callLock) || ((pasynRec->cnct) && callLock))
+            dbScanLock((dbCommon *) pasynRec); 
+         break;
+    default:   
+         if (callLock) dbScanLock((dbCommon *) pasynRec);
+         break;
+    }
     /* There has been a change in connect or enable status */
     monitorStatus(pasynRec);
-    if(callLock)
-        dbScanUnlock((dbCommon *) pasynRec);
+
+    switch(exception) {
+    case asynExceptionConnect:
+         if ((pasynRec->cnct) && callLock) {
+	    dbScanUnlock((dbCommon *) pasynRec);
+	    if (pasynRec->udf) pasynRec->udf=0;
+	    printf("Asyn record %s is reconnected\n", pasynRec->name);
+         }
+         else
+            printf("Asyn record %s is disconnected\n", pasynRec->name);
+         break;
+     default: 
+         if (callLock) dbScanUnlock((dbCommon *) pasynRec);
+         break;
+    }        
 }
 
 static void queueTimeoutCallbackProcess(asynUser * pasynUser)
@@ -1246,6 +1267,7 @@
                 "queueRequest failed\n");
             pasynManager->memFree(pmsg, sizeof(*pmsg));
             pasynManager->freeAsynUser(pasynUserEos);
+	    pasynRec->udf=1;
         }
     }
     pasynRec->pcnct = 1; 

Replies:
RE: asynDriver R4-21: a possible patch for asynRecord.c: test on GigE camera Mark Rivers
References:
asynDriver R4-21: a possible patch for asynRecord.c: test on GigE camera Kate Feng

Navigate by Date:
Prev: max length char for an ENUM Touchard Dominique
Next: Re: medm/motif compilation on Fedora 16+ Andrew Johnson
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: asynDriver R4-21: a possible patch for asynRecord.c: test on GigE camera Kate Feng
Next: RE: asynDriver R4-21: a possible patch for asynRecord.c: test on GigE camera Mark Rivers
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  <20132014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 20 Apr 2015 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·