From a546eaabb6a7f72d2a18407f7d8b4bcdaaf5d336 Mon Sep 17 00:00:00 2001 From: rivers Date: Tue, 31 Jan 2012 15:29:11 +0000 Subject: [PATCH] Support array callbacks; Removed readInt32; support TemperatureActual; many other changes git-svn-id: https://subversion.xor.aps.anl.gov/synApps/areaDetector/trunk@14390 dc6c5ff5-0b8b-c028-a01f-ffb33f00fc8b --- ADApp/andorSrc/andorCCD.cpp | 309 ++++++++++++++++++++++-------------- 1 file changed, 186 insertions(+), 123 deletions(-) diff --git a/ADApp/andorSrc/andorCCD.cpp b/ADApp/andorSrc/andorCCD.cpp index 706ed85..f8a1fea 100755 --- a/ADApp/andorSrc/andorCCD.cpp +++ b/ADApp/andorSrc/andorCCD.cpp @@ -84,6 +84,7 @@ AndorCCD::AndorCCD(const char *portName, int maxBuffers, size_t maxMemory, int status = asynSuccess; int binX=1, binY=1, minX=0, minY=0, sizeX, sizeY; + char model[256]; const char *functionName = "AndorCCD::AndorCCD"; cout << "Constructing AndorCCD driver..." << endl; @@ -134,6 +135,7 @@ AndorCCD::AndorCCD(const char *portName, int maxBuffers, size_t maxMemory, checkStatus(Initialize(mInstallPath)); setStringParam(AndorMessage, "Camera successfully initialized."); checkStatus(GetDetector(&sizeX, &sizeY)); + checkStatus(GetHeadModel(model)); checkStatus(SetReadMode(ARImage)); checkStatus(SetImage(binX, binY, minX+1, minX+sizeX, minY+1, minY+sizeY)); checkStatus(SetShutter(mShutterExTTL, mShutterMode, mShutterCloseTime, mShutterOpenTime)); @@ -142,12 +144,19 @@ AndorCCD::AndorCCD(const char *portName, int maxBuffers, size_t maxMemory, cout << e << endl; return; } + + // Read the model + /* Set some default values for parameters */ status = setStringParam(ADManufacturer, "Andor"); - status |= setStringParam(ADModel, "CCD"); + status |= setStringParam(ADModel, model); status |= setIntegerParam(ADSizeX, sizeX); status |= setIntegerParam(ADSizeY, sizeY); + status |= setIntegerParam(ADBinX, 1); + status |= setIntegerParam(ADBinY, 1); + status |= setIntegerParam(ADMinX, 0); + status |= setIntegerParam(ADMinY, 0); status |= setIntegerParam(ADMaxSizeX, sizeX); status |= setIntegerParam(ADMaxSizeY, sizeY); status |= setIntegerParam(ADImageMode, ADImageSingle); @@ -155,9 +164,12 @@ AndorCCD::AndorCCD(const char *portName, int maxBuffers, size_t maxMemory, status |= setDoubleParam (ADAcquireTime, 1.0); status |= setDoubleParam (ADAcquirePeriod, 1.0); status |= setIntegerParam(ADNumImages, 1); + status |= setIntegerParam(ADNumExposures, 1); status |= setIntegerParam(NDArraySizeX, sizeX); status |= setIntegerParam(NDArraySizeY, sizeY); - status |= setIntegerParam(NDArraySize, sizeX*sizeY*sizeof(at_32)); + status |= setIntegerParam(NDArraySize, sizeX*sizeY*sizeof(at_32)); + status |= setDoubleParam(AndorAccumulatePeriod, 2.0); + status |= setIntegerParam(AndorAdcSpeed, 0); callParamCallbacks(); @@ -244,7 +256,9 @@ static void exitHandler(void *drvPvt) void AndorCCD::report(FILE *fp, int details) { int param1; + float fParam1; int xsize, ysize; + int i; unsigned int uIntParam1; unsigned int uIntParam2; unsigned int uIntParam3; @@ -269,6 +283,12 @@ void AndorCCD::report(FILE *fp, int details) fprintf(fp, " Number of amplifier channels: %d\n", param1); checkStatus(GetNumberADChannels(¶m1)); fprintf(fp, " Number of ADC channels: %d\n", param1); + checkStatus(GetNumberPreAmpGains(¶m1)); + fprintf(fp, " Number of pre-amp gains: %d\n", param1); + for (i=0; ireason; int adstatus = 0; + epicsInt32 oldValue; asynStatus status = asynSuccess; const char *functionName = "AndorCCD::writeInt32"; + //Set in param lib so the user sees a readback straight away. Save a backup in case of errors. + getIntegerParam(function, &oldValue); + status = setIntegerParam(function, value); + if (function == ADAcquire) { getIntegerParam(ADStatus, &adstatus); if (value && (adstatus == ADStatusIdle)) { try { - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, - "%s, Acquiring data...\n", - functionName); - checkStatus(StartAcquisition()); mAcquiringData = 1; //We send an event at the bottom of this function. } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } if (!value && (adstatus != ADStatusIdle)) { @@ -318,7 +339,7 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) checkStatus(CancelWait()); } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } } @@ -326,22 +347,11 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) (function == ADImageMode) || (function == ADBinX) || (function == ADBinY) || (function == ADMinX) || (function == ADMinY) || - (function == ADSizeX) || (function == ADSizeY)) { - SetupAcquisition(); - } - else if (function == ADTriggerMode) { - try { - if (value == 0) { - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetTriggerMode(%d)\n", functionName, ATInternal); - checkStatus(SetTriggerMode(ATInternal)); - } else if (value == 1) { - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetTriggerMode(%d)\n", functionName, ATExternal); - checkStatus(SetTriggerMode(ATExternal)); - } - } catch (const std::string &e) { - cout << e << endl; - return(asynError); - } + (function == ADSizeX) || (function == ADSizeY) || + (function == ADTriggerMode) || + (function == AndorAdcSpeed)) { + status = setupAcquisition(); + if (status != asynSuccess) setIntegerParam(function, oldValue); } else if (function == AndorCoolerParam) { try { @@ -354,7 +364,7 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) } } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } else if (function == ADShutterControl) { @@ -378,7 +388,7 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) } } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } @@ -389,7 +399,7 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetShutter(%d,%d,%d,%d).\n", functionName, mShutterExTTL, mShutterMode, mShutterCloseTime, mShutterOpenTime); } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } @@ -400,29 +410,14 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetShutter(%d,%d,%d,%d).\n", functionName, mShutterExTTL, mShutterMode, mShutterCloseTime, mShutterOpenTime); } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } - else if (function == AndorAdcSpeed) { - try { - checkStatus(SetADChannel(value)); - //Set fastest HS speed. - checkStatus(SetHSSpeed(0, 0)); - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetADCChannel(%d).\n", functionName, value); - setIntegerParam(AndorAdcSpeed, value); - } catch (const std::string &e) { - cout << e << endl; - return(asynError); - } - } else { + else { status = ADDriver::writeInt32(pasynUser, value); } - //Set in param lib so the user sees a readback straight away. We might overwrite this in the - //status task, depending on the parameter. - status = setIntegerParam(function, value); - //For a successful write, clear the error message. setStringParam(AndorMessage, " "); @@ -433,6 +428,9 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) epicsEventSignal(statusEvent); if (mAcquiringData) { + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, Sending dataEvent to dataTask ...\n", + functionName); //Also signal the data readout thread epicsEventSignal(dataEvent); } @@ -448,48 +446,6 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value) return status; } -asynStatus AndorCCD::readInt32(asynUser *pasynUser, epicsInt32 *value) -{ - int function = pasynUser->reason; - asynStatus status = asynSuccess; - const char *functionName = "AndorCCD::readInt32"; - - int temp = 0; - - //Changing any of the following parameters requires recomputing the base image - if (function == AndorCoolerParam) { - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, Reading cooler status...\n", functionName); - try { - checkStatus(IsCoolerOn(&temp)); - } catch (const std::string &e) { - cout << e << endl; - return(asynError); - } - } - else { - status = ADDriver::readInt32(pasynUser, value); - } - - *value = static_cast(temp); - - status = setIntegerParam(function, *value); - - callParamCallbacks(); - if (status) - asynPrint(pasynUser, ASYN_TRACE_ERROR, - "%s:%s error, status=%d function=%d, value=%f\n", - driverName, functionName, status, function, value); - else - asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, - "%s:%s: function=%d, value=%f\n", - driverName, functionName, function, value); - - return status; -} - - - - asynStatus AndorCCD::writeFloat64(asynUser *pasynUser, epicsFloat64 value) { int function = pasynUser->reason; @@ -499,10 +455,14 @@ asynStatus AndorCCD::writeFloat64(asynUser *pasynUser, epicsFloat64 value) int minTemp = 0; int maxTemp = 0; + /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the + * status at the end, but that's OK */ + status = setDoubleParam(function, value); + if ((function == ADAcquireTime) || (function == ADAcquirePeriod) || (function == AndorAccumulatePeriod)) { - SetupAcquisition(); + status = setupAcquisition(); } else if (function == ADTemperature) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, @@ -516,11 +476,11 @@ asynStatus AndorCCD::writeFloat64(asynUser *pasynUser, epicsFloat64 value) } else { setStringParam(AndorMessage, "Temperature is out of range."); callParamCallbacks(); - return(asynError); + status = asynError; } } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } else if (function == ADShutterOpenDelay) { @@ -534,7 +494,7 @@ asynStatus AndorCCD::writeFloat64(asynUser *pasynUser, epicsFloat64 value) functionName, mShutterExTTL, mShutterMode, mShutterCloseTime, mShutterOpenTime); } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } else if (function == ADShutterCloseDelay) { @@ -548,17 +508,13 @@ asynStatus AndorCCD::writeFloat64(asynUser *pasynUser, epicsFloat64 value) functionName, mShutterExTTL, mShutterMode, mShutterCloseTime, mShutterOpenTime); } catch (const std::string &e) { cout << e << endl; - return(asynError); + status = asynError; } } else { status = ADDriver::writeFloat64(pasynUser, value); } - /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the - * status at the end, but that's OK */ - status = setDoubleParam(function, value); - //For a successful write, clear the error message. setStringParam(AndorMessage, " "); @@ -720,7 +676,7 @@ void AndorCCD::statusTask(void) //Read temperature of CCD try { checkStatus(GetTemperature(&value)); - status = setDoubleParam(ADTemperature, static_cast(value)); + status = setDoubleParam(ADTemperatureActual, static_cast(value)); } catch (const std::string &e) { cout << e << endl; setStringParam(AndorMessage, e.c_str()); @@ -769,16 +725,18 @@ void AndorCCD::statusTask(void) } -asynStatus AndorCCD::SetupAcquisition() +asynStatus AndorCCD::setupAcquisition() { int numExposures; int numImages; int imageMode; - int binX, binY, minX, minY, sizeX, sizeY; + int adcChannel; + int triggerMode; + int binX, binY, minX, minY, sizeX, sizeY, maxSizeX, maxSizeY; double acquireTime, acquirePeriod, accumulatePeriod; float acquireTimeAct, acquirePeriodAct, accumulatePeriodAct; int FKmode = 4; - static const char *functionName = "AndorCCD::SetupAcquisition"; + static const char *functionName = "AndorCCD::setupAcquisition"; getIntegerParam(ADImageMode, &imageMode); getIntegerParam(ADNumExposures, &numExposures); @@ -805,33 +763,57 @@ asynStatus AndorCCD::SetupAcquisition() getIntegerParam(ADMinY, &minY); getIntegerParam(ADSizeX, &sizeX); getIntegerParam(ADSizeY, &sizeY); + getIntegerParam(ADMaxSizeX, &maxSizeX); + getIntegerParam(ADMaxSizeY, &maxSizeY); + if (minX > (maxSizeX - 2*binX)) { + minX = maxSizeX - 2*binX; + setIntegerParam(ADMinX, minX); + } + if (minY > (maxSizeY - 2*binY)) { + minY = maxSizeY - 2*binY; + setIntegerParam(ADMinY, minY); + } + if ((minX + sizeX) > maxSizeX) { + sizeX = maxSizeX - minX; + setIntegerParam(ADSizeX, sizeX); + } + if ((minY + sizeY) > maxSizeY) { + sizeY = maxSizeY - minY; + setIntegerParam(ADSizeY, sizeY); + } getDoubleParam(ADAcquireTime, &acquireTime); getDoubleParam(ADAcquirePeriod, &acquirePeriod); getDoubleParam(AndorAccumulatePeriod, &accumulatePeriod); + getIntegerParam(ADTriggerMode, &triggerMode); + getIntegerParam(AndorAdcSpeed, &adcChannel); + + // Unfortunately there does not seem to be a way to query the Andor SDK for the actual size of the image, + // so we must compute it. + setIntegerParam(NDArraySizeX, sizeX/binX); + setIntegerParam(NDArraySizeY, sizeY/binY); + setIntegerParam(NDArraySize, sizeX/binX * sizeY/binY * sizeof(at_32)); + try { + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetTriggerMode(%d)\n", functionName, triggerMode); + checkStatus(SetTriggerMode(ATInternal)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetADChannel(%d)\n", functionName, adcChannel); + checkStatus(SetADChannel(adcChannel)); + //Set fastest HS speed. + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetHSSpeed(0, 0)\n", functionName); + checkStatus(SetHSSpeed(0, 0)); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetImage(%d,%d,%d,%d,%d,%d)\n", functionName, binX, binY, minX+1, minX+sizeX, minY+1, minY+sizeY); checkStatus(SetImage(binX, binY, minX+1, minX+sizeX, minY+1, minY+sizeY)); - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, - "%s, SetNumberAccumulations(%d)\n", - functionName, numExposures); - checkStatus(SetNumberAccumulations(numExposures)); - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetExposureTime(%f).\n", functionName, acquireTime); checkStatus(SetExposureTime((float)acquireTime)); - - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, - "%s, SetAccumulationCycleTime(%f).\n", functionName, accumulatePeriod); - checkStatus(SetAccumulationCycleTime((float)accumulatePeriod)); - - asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, - "%s, SetKineticCycleTime(%f).\n", functionName,acquirePeriod); - checkStatus(SetKineticCycleTime((float)acquirePeriod)); - + switch (imageMode) { case ADImageSingle: if (numExposures == 1) { @@ -842,22 +824,42 @@ asynStatus AndorCCD::SetupAcquisition() asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetAcquisitionMode(AAAccumulate)\n", functionName); checkStatus(SetAcquisitionMode(AAAccumulate)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetNumberAccumulations(%d)\n", + functionName, numExposures); + checkStatus(SetNumberAccumulations(numExposures)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetAccumulationCycleTime(%f).\n", functionName, accumulatePeriod); + checkStatus(SetAccumulationCycleTime((float)accumulatePeriod)); } break; case ADImageMultiple: + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetAcquisitionMode(AAKinetics)\n", functionName); + checkStatus(SetAcquisitionMode(AAKinetics)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetNumberAccumulations(%d)\n", + functionName, numExposures); + checkStatus(SetNumberAccumulations(numExposures)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetAccumulationCycleTime(%f).\n", functionName, accumulatePeriod); + checkStatus(SetAccumulationCycleTime((float)accumulatePeriod)); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetNumberKinetics(%d).\n", functionName, numImages); checkStatus(SetNumberKinetics(numImages)); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, - "%s, SetAcquisitionMode(AAKinetics)\n", functionName); - checkStatus(SetAcquisitionMode(AAKinetics)); + "%s, SetKineticCycleTime(%f).\n", functionName,acquirePeriod); + checkStatus(SetKineticCycleTime((float)acquirePeriod)); break; case ADImageContinuous: asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetAcquisitionMode(AARunTillAbort)\n", functionName); checkStatus(SetAcquisitionMode(AARunTillAbort)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, SetKineticCycleTime(%f).\n", functionName,acquirePeriod); + checkStatus(SetKineticCycleTime((float)acquirePeriod)); break; case AImageFastKinetics: @@ -867,7 +869,7 @@ asynStatus AndorCCD::SetupAcquisition() asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, SetFastKineticsEx(%d,%d,%f,%d,%d,%d,%d).\n", functionName, sizeY, numExposures, acquireTime, FKmode, binX, binY, minY); - checkStatus(SetFastKineticsEx(sizeY, numExposures, (float)acquireTime, FKmode, binX, binY, minY)); + checkStatus(SetFastKineticsEx(sizeY, numImages, (float)acquireTime, FKmode, binX, binY, minY)); break; } // Read the actual times @@ -875,6 +877,9 @@ asynStatus AndorCCD::SetupAcquisition() checkStatus(GetFKExposureTime(&acquireTimeAct)); } else { checkStatus(GetAcquisitionTimings(&acquireTimeAct, &accumulatePeriodAct, &acquirePeriodAct)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, GetAcquisitionTimings(exposure=%f, accumulate=%f, kinetic=%f\n", + functionName, acquireTimeAct, accumulatePeriodAct, acquirePeriodAct); } setDoubleParam(AndorAcquireTimeActual, acquireTimeAct); setDoubleParam(AndorAcquirePeriodActual, acquirePeriodAct); @@ -883,7 +888,7 @@ asynStatus AndorCCD::SetupAcquisition() } catch (const std::string &e) { cout << e << endl; - return(asynError); + return asynError; } return asynSuccess; } @@ -895,10 +900,21 @@ asynStatus AndorCCD::SetupAcquisition() void AndorCCD::dataTask(void) { epicsUInt32 status = 0; + int acquireStatus; char *errorString = NULL; int acquiring = 0; epicsInt32 numImages = 0; epicsInt32 numImagesCounter; + epicsInt32 numExposuresCounter; + epicsInt32 imageCounter; + epicsInt32 arrayCallbacks; + epicsInt32 sizeX, sizeY; + long firstImage, lastImage; + int dims[2]; + int nDims = 2; + NDDataType_t dataType = NDInt32; + epicsTimeStamp startTime; + NDArray *pArray; int autoSave; //long *dP = NULL; @@ -921,6 +937,8 @@ void AndorCCD::dataTask(void) //Sanity check that main thread thinks we are acquiring data if (mAcquiringData) { try { + status = setupAcquisition(); + if (status != asynSuccess) continue; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, StartAcquisition()\n", functionName); checkStatus(StartAcquisition()); @@ -929,18 +947,28 @@ void AndorCCD::dataTask(void) cout << e << endl; continue; } - //Read the number of images set + //Read some parameters getIntegerParam(ADNumImages, &numImages); getIntegerParam(NDAutoSave, &autoSave); + getIntegerParam(NDArrayCallbacks, &arrayCallbacks); + getIntegerParam(NDArraySizeX, &sizeX); + getIntegerParam(NDArraySizeY, &sizeY); + // Reset the counters setIntegerParam(ADNumImagesCounter, 0); + setIntegerParam(ADNumExposuresCounter, 0); callParamCallbacks(); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s, Data thread is running but main thread thinks we are not acquiring.\n", functionName); + acquiring = 0; } while (acquiring) { try { + checkStatus(GetStatus(&acquireStatus)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, GetStatus returned %d\n", functionName, acquireStatus); + if (acquireStatus != DRV_ACQUIRING) break; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, WaitForAcquisition().\n", functionName); this->unlock(); @@ -948,14 +976,49 @@ void AndorCCD::dataTask(void) this->lock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s, WaitForAcquisition has returned.\n", functionName); - getIntegerParam(ADNumImagesCounter, &numImagesCounter); - numImagesCounter++; - setIntegerParam(ADNumImagesCounter, numImagesCounter); + getIntegerParam(ADNumExposuresCounter, &numExposuresCounter); + numExposuresCounter++; + setIntegerParam(ADNumExposuresCounter, numExposuresCounter); callParamCallbacks(); - status = GetOldestImage(mData, mDataSize); + // Is there an image available? + status = GetNumberNewImages(&firstImage, &lastImage); if (status == DRV_SUCCESS) { - //Save data + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s, firstImage=%d, lastImage=%d\n", functionName, firstImage, lastImage); + // Update counters + getIntegerParam(NDArrayCounter, &imageCounter); + imageCounter++; + setIntegerParam(NDArrayCounter, imageCounter);; + getIntegerParam(ADNumImagesCounter, &numImagesCounter); + numImagesCounter++; + setIntegerParam(ADNumImagesCounter, numImagesCounter); + // Save data if autosave is enabled if (autoSave) this->saveDataFrame(); + // If array callbacks are enabled then read data into NDArray, do callbacks + if (arrayCallbacks) { + epicsTimeGetCurrent(&startTime); + // Allocate an NDArray + dims[0] = sizeX; + dims[1] = sizeY; + pArray = this->pNDArrayPool->alloc(nDims, dims, dataType, 0, NULL); + // Read the oldest array + status = GetOldestImage((at_32*)pArray->pData, sizeX*sizeY); + /* Put the frame number and time stamp into the buffer */ + pArray->uniqueId = imageCounter; + pArray->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9; + /* Get any attributes that have been defined for this driver */ + this->getAttributes(pArray->pAttributeList); + /* Call the NDArray callback */ + /* Must release the lock here, or we can get into a deadlock, because we can + * block on the plugin lock, and the plugin can be calling us */ + this->unlock(); + asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, + "%s:, calling array callbacks\n", functionName); + doCallbacksGenericPointer(pArray, NDArrayData, 0); + this->lock(); + pArray->release(); + } + callParamCallbacks(); } } catch (const std::string &e) { cout << e << endl;