Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 65 additions & 17 deletions aravisApp/src/ADAravis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class ADAravis : public ADGenICam, epicsThreadRunable {
/* Constructor */
ADAravis(const char *portName, const char *cameraName, int enableCaching,
size_t maxMemory, int priority, int stackSize);
~ADAravis();

/* These are the methods that we override from ADDriver */
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
Expand All @@ -155,6 +156,7 @@ class ADAravis : public ADGenICam, epicsThreadRunable {
std::string const & featureName, GCFeatureType_t featureType);
virtual asynStatus startCapture();
virtual asynStatus stopCapture();
virtual void shutdownPortDriver();
void report(FILE *fp, int details);

/* This is the method we override from epicsThreadRunable */
Expand All @@ -164,9 +166,6 @@ class ADAravis : public ADGenICam, epicsThreadRunable {
epicsMessageQueueId msgQId;
void newBufferCallback(ArvStream *stream);

/** Used by epicsAtExit */
ArvCamera *camera;

/** Used by connection lost callback */
int connectionValid;

Expand Down Expand Up @@ -196,6 +195,7 @@ class ADAravis : public ADGenICam, epicsThreadRunable {
asynStatus makeCameraObject();
asynStatus makeStreamObject();

ArvCamera *camera;
ArvStream *stream;
ArvDevice *device;
ArvGc *genicam;
Expand All @@ -206,6 +206,7 @@ class ADAravis : public ADGenICam, epicsThreadRunable {
int nConsecutiveBadFrames;
int nBadFramesPrior;
epicsThread pollingLoop;
bool exiting;
std::vector<arvFeature*> featureList;
};

Expand All @@ -217,19 +218,13 @@ GenICamFeature *ADAravis::createFeature(GenICamFeatureSet *set,
return pFeature;
}

/** Called by epicsAtExit to shutdown camera */
#ifndef ASYN_DESTRUCTIBLE
/** On old asyn versions, called by epicsAtExit to shutdown camera */
static void aravisShutdown(void* arg) {
ADAravis *pPvt = (ADAravis *) arg;
GErrorHelper err;
ArvCamera *cam = pPvt->camera;
printf("ADAravis: Stopping %s... ", pPvt->portName);
arv_camera_stop_acquisition(cam, err.get());
pPvt->connectionValid = 0;
epicsThreadSleep(0.1);
pPvt->camera = NULL;
g_object_unref(cam);
printf("ADAravis: OK\n");
pPvt->shutdownPortDriver();
}
#endif

/** Called by aravis when destroying a buffer with an NDArray wrapper */
static void destroyBuffer(gpointer data){
Expand Down Expand Up @@ -311,9 +306,15 @@ static void setIocRunningFlag(initHookState state) {
ADAravis::ADAravis(const char *portName, const char *cameraName, int enableCaching,
size_t maxMemory, int priority, int stackSize)

: ADGenICam(portName, maxMemory, priority, stackSize),
camera(NULL),
: ADGenICam(portName, maxMemory, priority, stackSize,
#ifdef ASYN_DESTRUCTIBLE
ASYN_DESTRUCTIBLE
#else
0
#endif
),
connectionValid(0),
camera(NULL),
stream(NULL),
device(NULL),
genicam(NULL),
Expand All @@ -324,7 +325,8 @@ ADAravis::ADAravis(const char *portName, const char *cameraName, int enableCachi
pollingLoop(*this,
"aravisPoll",
stackSize>0 ? stackSize : epicsThreadGetStackSize(epicsThreadStackMedium),
epicsThreadPriorityHigh)
epicsThreadPriorityHigh),
exiting(false)
{
const char *functionName = "ADAravis";
char tempString[256];
Expand Down Expand Up @@ -385,14 +387,53 @@ ADAravis::ADAravis(const char *portName, const char *cameraName, int enableCachi
this->featureIndex = 0;
this->connectToCamera();

#ifndef ASYN_DESTRUCTIBLE
/* Register the shutdown function for epicsAtExit */
epicsAtExit(aravisShutdown, (void*)this);
#endif

/* Register the pollingLoop to start after iocInit */
initHookRegister(setIocRunningFlag);
this->pollingLoop.start();
}

void ADAravis::shutdownPortDriver() {
asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s shutting down\n", driverName);

lock();
GErrorHelper err;
arv_camera_stop_acquisition(camera, err.get());
connectionValid = 0;
exiting = true;
unlock();
pollingLoop.exitWait();

ADGenICam::shutdownPortDriver();

// This would normally go in the destructor. But on old versions of asyn,
// the driver is not deleted after shutdown completes, and the following
// steps are needed to disconnect the camera.
arv_stream_set_emit_signals(stream, false);
g_object_unref(stream);
g_object_unref(camera);

// This makes it easier to find use-after-free.
stream = NULL;
genicam = NULL;
device = NULL;
camera = NULL;
}

ADAravis::~ADAravis() {
// If the driver subclass is not destructible, or asyn is old, or we are not
// in an IOC (e.g. unit tests), we need to call shutdown ourselves.
// On newer versions of asyn, we could check with needsShutdown() to see if
// shutdown has already been done, be we don't want to rely on that.
if (!exiting) {
shutdownPortDriver();
}
}

asynStatus ADAravis::makeCameraObject() {
const char *functionName = "makeCameraObject";

Expand Down Expand Up @@ -683,11 +724,18 @@ void ADAravis::run() {
epicsThreadSleep(0.1);
}

/* Loop forever */
/* Loop until driver shutdown */
epicsTimeGetCurrent(&lastFeatureGet);
while (1) {
/* Wait 5ms for an array to arrive from the queue */
if (epicsMessageQueueReceiveWithTimeout(this->msgQId, &buffer, sizeof(&buffer), 0.005) == -1) {
lock();
/* We could use needsShutdown() here, but it requires a recent asyn. */
bool e = exiting;
unlock();
if (e) {
break;
}
} else {
/* Got a buffer, so lock up and process it */
this->lock();
Expand Down