Experimental Physics and
| |||||||||||||||
|
hellow
i modified the pilatus src like this For changing the last made filename... ------------------------------------------------------------------------ /* pilatusDetector.cpp * * This is a driver for a Pilatus pixel array detector. * * Author: Mark Rivers * University of Chicago * * Created: June 11, 2008 * */ #include <stddef.h> #include <stdlib.h> #include <stdarg.h> #include <math.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <ctype.h> #include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #include <cbf_ad.h> #include <tiffio.h> #include <epicsTime.h> #include <epicsThread.h> #include <epicsEvent.h> #include <epicsMutex.h> #include <epicsString.h> #include <epicsStdio.h> #include <epicsMutex.h> #include <cantProceed.h> #include <iocsh.h> #include <epicsExport.h> #include <asynOctetSyncIO.h> #include "ADDriver.h" /** Messages to/from camserver */ #define MAX_MESSAGE_SIZE 256 #define MAX_FILENAME_LEN 256 #define FILEPATH_INDEX 8 #define MAX_BAD_PIXELS 100 /** Time to poll when reading from camserver */ #define ASYN_POLL_TIME .01 /**#define CAMSERVER_DEFAULT_TIMEOUT 1**/ #define CAMSERVER_DEFAULT_TIMEOUT 1 /** Time between checking to see if image file is complete */ #define FILE_READ_DELAY .01 /** Trigger modes */ typedef enum { TMInternal, TMExternalEnable, TMExternalTrigger, TMMultipleExternalTrigger, TMAlignment } PilatusTriggerMode; /** Bad pixel structure for Pilatus detector */ typedef struct { int badIndex; int replaceIndex; } badPixel; static const char *gainStrings[] = {"lowG", "midG", "highG", "uhighG"}; static const char *driverName = "pilatusDetector"; #define PilatusDelayTimeString "DELAY_TIME" #define PilatusThresholdString "THRESHOLD" #define PilatusThresholdApplyString "THRESHOLD_APPLY" #define PilatusThresholdAutoApplyString "THRESHOLD_AUTO_APPLY" #define PilatusArmedString "ARMED" #define PilatusImageFileTmotString "IMAGE_FILE_TMOT" #define PilatusBadPixelFileString "BAD_PIXEL_FILE" #define PilatusNumBadPixelsString "NUM_BAD_PIXELS" #define PilatusFlatFieldFileString "FLAT_FIELD_FILE" #define PilatusMinFlatFieldString "MIN_FLAT_FIELD" #define PilatusFlatFieldValidString "FLAT_FIELD_VALID" #define PilatusGapFillString "GAP_FILL" #define PilatusWavelengthString "WAVELENGTH" #define PilatusEnergyLowString "ENERGY_LOW" #define PilatusEnergyHighString "ENERGY_HIGH" #define PilatusDetDistString "DET_DIST" #define PilatusDetVOffsetString "DET_VOFFSET" #define PilatusBeamXString "BEAM_X" #define PilatusBeamYString "BEAM_Y" #define PilatusFluxString "FLUX" #define PilatusFilterTransmString "FILTER_TRANSM" #define PilatusStartAngleString "START_ANGLE" #define PilatusAngleIncrString "ANGLE_INCR" #define PilatusDet2thetaString "DET_2THETA" #define PilatusPolarizationString "POLARIZATION" #define PilatusAlphaString "ALPHA" #define PilatusKappaString "KAPPA" #define PilatusPhiString "PHI" #define PilatusChiString "CHI" #define PilatusOscillAxisString "OSCILL_AXIS" #define PilatusNumOscillString "NUM_OSCILL" /** Driver for Dectris Pilatus pixel array detectors using their camserver server over TCP/IP socket */ class pilatusDetector : public ADDriver { public: pilatusDetector(const char *portName, const char *camserverPort, int maxSizeX, int maxSizeY, int maxBuffers, size_t maxMemory, int priority, int stackSize); /* These are the methods that we override from ADDriver */ virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual); void report(FILE *fp, int details); void pilatusTask(); /* This should be private but is called from C so must be public */ protected: int PilatusDelayTime; #define FIRST_PILATUS_PARAM PilatusDelayTime int PilatusThreshold; int PilatusThresholdApply; int PilatusThresholdAutoApply; int PilatusArmed; int PilatusImageFileTmot; int PilatusBadPixelFile; int PilatusNumBadPixels; int PilatusFlatFieldFile; int PilatusMinFlatField; int PilatusFlatFieldValid; int PilatusGapFill; int PilatusWavelength; int PilatusEnergyLow; int PilatusEnergyHigh; int PilatusDetDist; int PilatusDetVOffset; int PilatusBeamX; int PilatusBeamY; int PilatusFlux; int PilatusFilterTransm; int PilatusStartAngle; int PilatusAngleIncr; int PilatusDet2theta; int PilatusPolarization; int PilatusAlpha; int PilatusKappa; int PilatusPhi; int PilatusChi; int PilatusOscillAxis; int PilatusNumOscill; #define LAST_PILATUS_PARAM PilatusNumOscill private: /* These are the methods that are new to this class */ void abortAcquisition(); void makeMultipleFileFormat(const char *baseFileName); asynStatus waitForFileToExist(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage); void correctBadPixels(NDArray *pImage); int stringEndsWith(const char *aString, const char *aSubstring, int shouldIgnoreCase); asynStatus readImageFile(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage); asynStatus readCbf(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage); asynStatus readTiff(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage); asynStatus writeCamserver(double timeout); asynStatus readCamserver(double timeout); asynStatus writeReadCamserver(double timeout); asynStatus setAcquireParams(); asynStatus setThreshold(); void readBadPixelFile(const char *badPixelFile); void readFlatFieldFile(const char *flatFieldFile); /* Our data */ int imagesRemaining; epicsEventId startEventId; epicsEventId stopEventId; char toCamserver[MAX_MESSAGE_SIZE]; char fromCamserver[MAX_MESSAGE_SIZE]; NDArray *pFlatField; char multipleFileFormat[MAX_FILENAME_LEN]; int multipleFileNumber; int multipleFileNumber2; asynUser *pasynUserCamserver; badPixel badPixelMap[MAX_BAD_PIXELS]; double averageFlatField; }; #define NUM_PILATUS_PARAMS (&LAST_PILATUS_PARAM - &FIRST_PILATUS_PARAM + 1) void pilatusDetector::readBadPixelFile(const char *badPixelFile) { int i; int xbad, ybad, xgood, ygood; int n; FILE *file; int nx, ny; const char *functionName = "readBadPixelFile"; int numBadPixels=0; getIntegerParam(NDArraySizeX, &nx); getIntegerParam(NDArraySizeY, &ny); setIntegerParam(PilatusNumBadPixels, numBadPixels); if (strlen(badPixelFile) == 0) return; file = fopen(badPixelFile, "r"); if (file == NULL) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, cannot open file %s\n", driverName, functionName, badPixelFile); return; } for (i=0; i<MAX_BAD_PIXELS; i++) { n = fscanf(file, " %d,%d %d,%d", &xbad, &ybad, &xgood, &ygood); if (n == EOF) break; if (n != 4) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, too few items =%d, should be 4\n", driverName, functionName, n); return; } this->badPixelMap[i].badIndex = ybad*nx + xbad; this->badPixelMap[i].replaceIndex = ygood*ny + xgood; numBadPixels++; } setIntegerParam(PilatusNumBadPixels, numBadPixels); } void pilatusDetector::readFlatFieldFile(const char *flatFieldFile) { int i; int status; int ngood; int minFlatField; epicsInt32 *pData; const char *functionName = "readFlatFieldFile"; NDArrayInfo arrayInfo; setIntegerParam(PilatusFlatFieldValid, 0); this->pFlatField->getInfo(&arrayInfo); getIntegerParam(PilatusMinFlatField, &minFlatField); if (strlen(flatFieldFile) == 0) return; status = readImageFile(flatFieldFile, NULL, 0., this->pFlatField); if (status) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, error reading flat field file %s\n", driverName, functionName, flatFieldFile); return; } /* Compute the average counts in the flat field */ this->averageFlatField = 0.; ngood = 0; for (i=0, pData = (epicsInt32 *)this->pFlatField->pData; i<arrayInfo.nElements; i++, pData++) { if (*pData < minFlatField) continue; ngood++; averageFlatField += *pData; } averageFlatField = averageFlatField/ngood; for (i=0, pData = (epicsInt32 *)this->pFlatField->pData; i<arrayInfo.nElements; i++, pData++) { if (*pData < minFlatField) *pData = (epicsInt32)averageFlatField; } /* 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(); doCallbacksGenericPointer(this->pFlatField, NDArrayData, 0); this->lock(); setIntegerParam(PilatusFlatFieldValid, 1); } void pilatusDetector::makeMultipleFileFormat(const char *baseFileName) { /* This function uses the code from camserver */ char *p, *q; int fmt; char mfTempFormat[MAX_FILENAME_LEN]; char mfExtension[10]; int numImages; /* baseFilename has been built by the caller. * Copy to temp */ strncpy(mfTempFormat, baseFileName, sizeof(mfTempFormat)); getIntegerParam(ADNumImages, &numImages); p = mfTempFormat + strlen(mfTempFormat) - 5; /* look for extension */ if ( (q=strrchr(p, '.')) ) { strcpy(mfExtension, q); *q = '\0'; } else { strcpy(mfExtension, ""); /* default is raw image */ } multipleFileNumber=0; /* start number */ fmt=5; /* format length */ if ( !(p=strrchr(mfTempFormat, '/')) ) { p=mfTempFormat; } if ( (q=strrchr(p, '_')) ) { q++; if (isdigit(*q) && isdigit(*(q+1)) && isdigit(*(q+2))) { multipleFileNumber=atoi(q); fmt=0; p=q; while(isdigit(*q)) { fmt++; q++; } *p='\0'; if (((fmt<3) || ((fmt==3) && (numImages>999))) || ((fmt==4) && (numImages>9999))) { fmt=5; } } else if (*q) { strcat(p, "_"); /* force '_' ending */ } } else { strcat(p, "_"); /* force '_' ending */ } /* Build the final format string */ epicsSnprintf(this->multipleFileFormat, sizeof(this->multipleFileFormat), "%s%%.%dd%s", mfTempFormat, fmt, mfExtension); } /** This function waits for the specified file to exist. It checks to make sure that * the creation time of the file is after a start time passed to it, to force it to wait * for a new file to be created. */ asynStatus pilatusDetector::waitForFileToExist(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage) { int fd=-1; int fileExists=0; struct stat statBuff; epicsTimeStamp tStart, tCheck; time_t acqStartTime; double deltaTime=0.; int status=-1; const char *functionName = "waitForFileToExist"; FILE *fp; if (pStartTime) epicsTimeToTime_t(&acqStartTime, pStartTime); epicsTimeGetCurrent(&tStart); while (deltaTime <= timeout) { fd = open(fileName, O_RDONLY, 0); if ((fd >= 0) && (timeout != 0.)) { fileExists = 1; status = fstat(fd, &statBuff); if (status){ asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s error calling fstat, errno=%d %s\n", driverName, functionName, errno, fileName); close(fd); return(asynError); } if (difftime(statBuff.st_mtime, acqStartTime) > -1) break; close(fd); fd = -1; } /* Sleep, but check for stop event, which can be used to abort a long acquisition */ status = epicsEventWaitWithTimeout(this->stopEventId, FILE_READ_DELAY); if (status == epicsEventWaitOK) { setStringParam(ADStatusMessage, "Acquisition aborted"); return(asynError); } epicsTimeGetCurrent(&tCheck); deltaTime = epicsTimeDiffInSeconds(&tCheck, &tStart); } /* if (fd < 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s timeout waiting for file to be created %s\n", driverName, functionName, fileName); if (fileExists) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, " file exists but is more than 10 seconds old, possible clock synchronization problem\n"); setStringParam(ADStatusMessage, "Image file is more than 10 seconds old"); } else setStringParam(ADStatusMessage, "Timeout waiting for file to be created"); return(asynError); } close(fd); */ return(asynSuccess); } /** This function replaces bad pixels in the specified image with their replacements * according to the bad pixel map. */ void pilatusDetector::correctBadPixels(NDArray *pImage) { int i; int numBadPixels; getIntegerParam(PilatusNumBadPixels, &numBadPixels); for (i=0; i<numBadPixels; i++) { ((epicsInt32 *)pImage->pData)[this->badPixelMap[i].badIndex] = ((epicsInt32 *)pImage->pData)[this->badPixelMap[i].replaceIndex]; } } int pilatusDetector::stringEndsWith(const char *aString, const char *aSubstring, int shouldIgnoreCase) { int i, j; i = strlen(aString) - 1; j = strlen(aSubstring) - 1; while (i >= 0 && j >= 0) { if (shouldIgnoreCase) { if (tolower(aString[i]) != tolower(aSubstring[j])) return 0; } else { if (aString[i] != aSubstring[j]) return 0; } i--; j--; } return j < 0; } /** This function reads TIFF or CBF image files. It is not intended to be general, it * is intended to read the TIFF or CBF files that camserver creates. It checks to make * sure that the creation time of the file is after a start time passed to it, to force * it to wait for a new file to be created. */ asynStatus pilatusDetector::readImageFile(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage) { const char *functionName = "readImageFile"; if (stringEndsWith(fileName, ".tif", 1) || stringEndsWith(fileName, ".tiff", 1)) { return readTiff(fileName, pStartTime, timeout, pImage); } else if (stringEndsWith(fileName, ".cbf", 1)) { return readCbf(fileName, pStartTime, timeout, pImage); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, unsupported image file name extension, expected .tif or .cbf, fileName=%s\n", driverName, functionName, fileName); setStringParam(ADStatusMessage, "Unsupported file extension, expected .tif or .cbf"); return(asynError); } } /** This function reads CBF files using CBFlib. It is not intended to be general, it is / * intended to read the CBF files that camserver creates. It checks to make sure that * the creation time of the file is after a start time passed to it, to force it to wait * for a new file to be created. */ asynStatus pilatusDetector::readCbf(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage) { epicsTimeStamp tStart, tCheck; double deltaTime; int status=-1; const char *functionName = "readCbf"; cbf_handle cbf; FILE *file=NULL; unsigned int cbfCompression; int cbfBinaryId; size_t cbfElSize; int cbfElSigned; int cbfElUnsigned; size_t cbfElements; int cbfMinElement; int cbfMaxElement; const char *cbfByteOrder; size_t cbfDimFast; size_t cbfDimMid; size_t cbfDimSlow; size_t cbfPadding; size_t cbfElementsRead; deltaTime = 0.; epicsTimeGetCurrent(&tStart); status = waitForFileToExist(fileName, pStartTime, timeout, pImage); if (status != asynSuccess) { return((asynStatus)status); } cbf_set_warning_messages_enabled(0); cbf_set_error_messages_enabled(0); printf("%s \n", fileName); while (deltaTime <= timeout) { /* At this point we know the file exists, but it may not be completely * written yet. If we get errors then try again. */ status = cbf_make_handle(&cbf); if (status != 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, failed to make CBF handle, error code %#x\n", driverName, functionName, status); return(asynError); } status = cbf_set_cbf_logfile(cbf, NULL); if (status != 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, failed to disable CBF logging, error code %#x\n", driverName, functionName, status); return(asynError); } file = fopen(fileName, "rb"); if (file == NULL) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, failed to open CBF file \"%s\" for reading: %s\n", driverName, functionName, fileName, strerror(errno)); cbf_free_handle(cbf); return(asynError); } status = cbf_read_widefile(cbf, file, MSG_DIGESTNOW); if (status != 0) goto retry; status = cbf_find_tag(cbf, "_array_data.data"); if (status != 0) goto retry; /* Do some basic checking that the image size is what we expect */ status = cbf_get_integerarrayparameters_wdims_fs(cbf, &cbfCompression, &cbfBinaryId, &cbfElSize, &cbfElSigned, &cbfElUnsigned, &cbfElements, &cbfMinElement, &cbfMaxElement, &cbfByteOrder, &cbfDimFast, &cbfDimMid, &cbfDimSlow, &cbfPadding); if (status != 0) goto retry; if (cbfDimFast != (size_t)pImage->dims[0].size) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, image width incorrect =%zd, should be %d\n", driverName, functionName, cbfDimFast, pImage->dims[0].size); cbf_free_handle(cbf); return(asynError); } if (cbfDimMid != (size_t)pImage->dims[1].size) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, image height incorrect =%zd, should be %d\n", driverName, functionName, cbfDimMid, pImage->dims[1].size); cbf_free_handle(cbf); return(asynError); } /* Read the image */ status = cbf_get_integerarray(cbf, &cbfBinaryId, pImage->pData, sizeof(epicsInt32), 1, cbfElements, &cbfElementsRead); if (status != 0) goto retry; if (cbfElements != cbfElementsRead) goto retry; /* Sucesss! */ status = cbf_free_handle(cbf); if (status != 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, failed to free CBF handle, error code %#x\n", driverName, functionName, status); return(asynError); } break; retry: status = cbf_free_handle(cbf); if (status != 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, failed to free CBF handle, error code %#x\n", driverName, functionName, status); return(asynError); } /* Sleep, but check for stop event, which can be used to abort a long * acquisition */ status = epicsEventWaitWithTimeout(this->stopEventId, FILE_READ_DELAY); if (status == epicsEventWaitOK) { return(asynError); } epicsTimeGetCurrent(&tCheck); deltaTime = epicsTimeDiffInSeconds(&tCheck, &tStart); } correctBadPixels(pImage); return(asynSuccess); } /** This function reads TIFF files using libTiff. It is not intended to be general, * it is intended to read the TIFF files that camserver creates. It checks to make sure * that the creation time of the file is after a start time passed to it, to force it to * wait for a new file to be created. */ asynStatus pilatusDetector::readTiff(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage) { epicsTimeStamp tStart, tCheck; double deltaTime; int status=-1; const char *functionName = "readTiff"; int size, totalSize; int numStrips, strip; char *buffer; TIFF *tiff=NULL; epicsUInt32 uval; deltaTime = 0.; epicsTimeGetCurrent(&tStart); /* Suppress error messages from the TIFF library */ TIFFSetErrorHandler(NULL); TIFFSetWarningHandler(NULL); status = waitForFileToExist(fileName, pStartTime, timeout, pImage); if (status != asynSuccess) { return((asynStatus)status); } while (deltaTime <= timeout) { /* At this point we know the file exists, but it may not be completely written yet. * If we get errors then try again */ tiff = TIFFOpen(fileName, "rc"); if (tiff == NULL) { status = asynError; goto retry; } /* Do some basic checking that the image size is what we expect */ status = TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &uval); if (uval != (epicsUInt32)pImage->dims[0].size) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, image width incorrect =%u, should be %d\n", driverName, functionName, uval, pImage->dims[0].size); goto retry; } status = TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &uval); if (uval != (epicsUInt32)pImage->dims[1].size) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, image length incorrect =%u, should be %d\n", driverName, functionName, uval, pImage->dims[1].size); goto retry; } numStrips= TIFFNumberOfStrips(tiff); buffer = (char *)pImage->pData; totalSize = 0; for (strip=0; (strip < numStrips) && (totalSize < pImage->dataSize); strip++) { size = TIFFReadEncodedStrip(tiff, 0, buffer, pImage->dataSize-totalSize); if (size == -1) { /* There was an error reading the file. Most commonly this is because the file * was not yet completely written. Try again. */ asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s::%s, error reading TIFF file %s\n", driverName, functionName, fileName); goto retry; } buffer += size; totalSize += size; } if (totalSize != pImage->dataSize) { status = asynError; asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, file size incorrect =%d, should be %d\n", driverName, functionName, totalSize, pImage->dataSize); goto retry; } /* Sucesss! */ break; retry: if (tiff != NULL) TIFFClose(tiff); tiff = NULL; /* Sleep, but check for stop event, which can be used to abort a long acquisition */ status = epicsEventWaitWithTimeout(this->stopEventId, FILE_READ_DELAY); if (status == epicsEventWaitOK) { return(asynError); } epicsTimeGetCurrent(&tCheck); deltaTime = epicsTimeDiffInSeconds(&tCheck, &tStart); } if (tiff != NULL) TIFFClose(tiff); correctBadPixels(pImage); return(asynSuccess); } asynStatus pilatusDetector::setAcquireParams() { int ival; double dval; int triggerMode; asynStatus status; status = getIntegerParam(ADTriggerMode, &triggerMode); if (status != asynSuccess) triggerMode = TMInternal; /* When we change modes download all exposure parameters, since some modes * replace values with new parameters */ if (triggerMode == TMAlignment) { setIntegerParam(ADNumImages, 1); } /* nexpf > 1 is only supported in External Enable mode */ if (triggerMode != TMExternalEnable) { setIntegerParam(ADNumExposures, 1); } status = getIntegerParam(ADNumImages, &ival); if ((status != asynSuccess) || (ival < 1)) { ival = 1; setIntegerParam(ADNumImages, ival); } epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "nimages %d", ival); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); status = getIntegerParam(ADNumExposures, &ival); if ((status != asynSuccess) || (ival < 1)) { ival = 1; setIntegerParam(ADNumExposures, ival); } epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "nexpframe %d", ival); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); status = getDoubleParam(ADAcquireTime, &dval); if ((status != asynSuccess) || (dval < 0.)) { dval = 1.; setDoubleParam(ADAcquireTime, dval); } epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "exptime %f", dval); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); status = getDoubleParam(ADAcquirePeriod, &dval); if ((status != asynSuccess) || (dval < 0.)) { dval = 2.; setDoubleParam(ADAcquirePeriod, dval); } epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "expperiod %f", dval); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); status = getDoubleParam(PilatusDelayTime, &dval); if ((status != asynSuccess) || (dval < 0.)) { dval = 0.; setDoubleParam(PilatusDelayTime, dval); } epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "delay %f", dval); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); status = getIntegerParam(PilatusGapFill, &ival); if ((status != asynSuccess) || (ival < -2) || (ival > 0)) { ival = -2; setIntegerParam(PilatusGapFill, ival); } /* -2 is used to indicate that GapFill is not supported because it is a single element detector */ if (ival != -2) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "gapfill %d", ival); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } return(asynSuccess); } asynStatus pilatusDetector::setThreshold() { int igain, status; double threshold, dgain; getDoubleParam(ADGain, &dgain); igain = (int)(dgain + 0.5); if (igain < 0) igain = 0; if (igain > 3) igain = 3; getDoubleParam(PilatusThreshold, &threshold); epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "SetThreshold %s %f", gainStrings[igain], threshold*1000.); /* Set the status to waiting so we can be notified when it has finished */ setIntegerParam(ADStatus, ADStatusWaiting); setStringParam(ADStatusMessage, "Setting threshold"); callParamCallbacks(); status=writeReadCamserver(90.0); /* This command can take 78 seconds on a 6M */ if (status) setIntegerParam(ADStatus, ADStatusError); else setIntegerParam(ADStatus, ADStatusIdle); setIntegerParam(PilatusThresholdApply, 0); callParamCallbacks(); /* The SetThreshold command resets numimages to 1 and gapfill to 0, so re-send current * acquisition parameters */ setAcquireParams(); return(asynSuccess); } asynStatus pilatusDetector::writeCamserver(double timeout) { size_t nwrite; asynStatus status; const char *functionName="writeCamserver"; /* Flush any stale input, since the next operation is likely to be a read */ status = pasynOctetSyncIO->flush(this->pasynUserCamserver); status = pasynOctetSyncIO->write(this->pasynUserCamserver, this->toCamserver, strlen(this->toCamserver), timeout, &nwrite); if (status) asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s, status=%d, sent\n%s\n", driverName, functionName, status, this->toCamserver); /* Set output string so it can get back to EPICS */ setStringParam(ADStringToServer, this->toCamserver); return(status); } asynStatus pilatusDetector::readCamserver(double timeout) { size_t nread; asynStatus status=asynSuccess; int eventStatus; asynUser *pasynUser = this->pasynUserCamserver; int eomReason; epicsTimeStamp tStart, tCheck; double deltaTime; const char *functionName="readCamserver"; /* We implement the timeout with a loop so that the port does not * block during the entire read. If we don't do this then it is not possible * to abort a long exposure */ deltaTime = 0; epicsTimeGetCurrent(&tStart); while (deltaTime <= timeout) { status = pasynOctetSyncIO->read(pasynUser, this->fromCamserver, sizeof(this->fromCamserver), ASYN_POLL_TIME, &nread, &eomReason); if (status != asynTimeout) break; /* Sleep, but check for stop event, which can be used to abort a long acquisition */ eventStatus = epicsEventWaitWithTimeout(this->stopEventId, ASYN_POLL_TIME); if (eventStatus == epicsEventWaitOK) { setStringParam(ADStatusMessage, "Acquisition aborted"); return(asynError); } epicsTimeGetCurrent(&tCheck); deltaTime = epicsTimeDiffInSeconds(&tCheck, &tStart); } // If we got asynTimeout, and timeout=0 then this is not an error, it is a poll checking for possible reply and we are done if ((status == asynTimeout) && (timeout == 0)) return(asynSuccess); if (status != asynSuccess) asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:%s, timeout=%f, status=%d received %d bytes\n%s\n", driverName, functionName, timeout, status, nread, this->fromCamserver); else { /* Look for the string OK in the response */ if (!strstr(this->fromCamserver, "OK")) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:%s unexpected response from camserver, no OK, response=%s\n", driverName, functionName, this->fromCamserver); setStringParam(ADStatusMessage, "Error from camserver"); status = asynError; } else setStringParam(ADStatusMessage, "Camserver returned OK"); } /* Set output string so it can get back to EPICS */ setStringParam(ADStringFromServer, this->fromCamserver); return(status); } asynStatus pilatusDetector::writeReadCamserver(double timeout) { asynStatus status; status = writeCamserver(timeout); if (status) return status; status = readCamserver(timeout); return status; } static void pilatusTaskC(void *drvPvt) { pilatusDetector *pPvt = (pilatusDetector *)drvPvt; pPvt->pilatusTask(); } /** This thread controls acquisition, reads image files to get the image data, and * does the callbacks to send it to higher layers */ void pilatusDetector::pilatusTask() { int status = asynSuccess; int imageCounter; int numImages; int multipleFileNextImage=0; /* This is the next image number, starting at 0 */ int acquire; ADStatus_t acquiring; double startAngle; NDArray *pImage; double acquireTime, acquirePeriod; double readImageFileTimeout, timeout; int triggerMode; epicsTimeStamp startTime; const char *functionName = "pilatusTask"; char fullFileName[MAX_FILENAME_LEN], fullFileNameTmp[MAX_FILENAME_LEN], fullFileNameConvert[MAX_FILENAME_LEN]; char filePath[MAX_FILENAME_LEN]; char statusMessage[MAX_MESSAGE_SIZE]; int dims[2]; int arrayCallbacks; int flatFieldValid; this->lock(); /* Loop forever */ while (1) { /* Is acquisition active? */ getIntegerParam(ADAcquire, &acquire); /* If we are not acquiring then wait for a semaphore that is given when acquisition is started */ if (!acquire) { /* Only set the status message if we didn't encounter any errors last time, so we don't overwrite the error message */ if (!status) setStringParam(ADStatusMessage, "Waiting for acquire command"); callParamCallbacks(); /* Release the lock while we wait for an event that says acquire has started, then lock again */ this->unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: waiting for acquire to start\n", driverName, functionName); status = epicsEventWait(this->startEventId); this->lock(); getIntegerParam(ADAcquire, &acquire); } /* We are acquiring. */ /* Get the current time */ epicsTimeGetCurrent(&startTime); /* Get the exposure parameters */ getDoubleParam(ADAcquireTime, &acquireTime); getDoubleParam(ADAcquirePeriod, &acquirePeriod); getDoubleParam(PilatusImageFileTmot, &readImageFileTimeout); /* Get the acquisition parameters */ getIntegerParam(ADTriggerMode, &triggerMode); getIntegerParam(ADNumImages, &numImages); acquiring = ADStatusAcquire; setIntegerParam(ADStatus, acquiring); /* Reset the MX settings start angle */ getDoubleParam(PilatusStartAngle, &startAngle); epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Start_angle %f", startAngle); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); /* Create the full filename */ createFileName(sizeof(fullFileName), fullFileName); if (numImages > 1) { int length = strlen(fullFileName); if (length > 0) { strcpy(fullFileNameTmp, &fullFileName[8]); if (fullFileName[0] == '/') { strcpy(fullFileNameConvert, "/data"); } else { strcpy(fullFileNameConvert, "/data/"); } strcat(fullFileNameConvert, fullFileNameTmp); } } switch (triggerMode) { case TMInternal: epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "Exposure %s", fullFileName); break; case TMExternalEnable: epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "ExtEnable %s", fullFileName); break; case TMExternalTrigger: epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "ExtTrigger %s", fullFileName); break; case TMMultipleExternalTrigger: epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "ExtMTrigger %s", fullFileName); break; case TMAlignment: getStringParam(NDFilePath, sizeof(filePath), filePath); epicsSnprintf(fullFileName, sizeof(fullFileName), "%salignment.tif", filePath); epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "Exposure %s", fullFileName); break; } setStringParam(ADStatusMessage, "Starting exposure"); /* Send the acquire command to camserver and wait for the 15OK response */ writeReadCamserver(2.0); /* Do another read in case there is an ERR string at the end of the input buffer */ status=readCamserver(0.0); /* If the status wasn't asynSuccess or asynTimeout, report the error */ if (status>1) { acquire = 0; } else { /* Set status back to asynSuccess as the timeout was expected */ status = asynSuccess; /* Open the shutter */ setShutter(1); /* Set the armed flag */ setIntegerParam(PilatusArmed, 1); /* Create the format string for constructing file names for multi-image collection */ makeMultipleFileFormat(fullFileName); makeMultipleFileFormat(fullFileNameConvert); multipleFileNextImage = 0; /* Call the callbacks to update any changes */ // setStringParam(NDFullFileName, fullFileName); setStringParam(NDFullFileName, fullFileNameConvert); callParamCallbacks(); } while (acquire) { if (numImages == 1) { /* For single frame or alignment mode need to wait for 7OK response from camserver * saying acquisition is complete before trying to read file, else we get a * recent but stale file. */ setStringParam(ADStatusMessage, "Waiting for 7OK response"); callParamCallbacks(); /* We release the mutex when waiting for 7OK because this takes a long time and * we need to allow abort operations to get through */ this->unlock(); status = readCamserver(acquireTime + readImageFileTimeout); this->lock(); /* If there was an error jump to bottom of loop */ if (status) { acquire = 0; if(status==asynTimeout) setStringParam(ADStatusMessage, "Timeout waiting for camserver response"); continue; } } else { /* If this is a multi-file acquisition the file name is built differently */ epicsSnprintf(fullFileName, sizeof(fullFileName), multipleFileFormat, multipleFileNumber); epicsSnprintf(fullFileNameConvert, sizeof(fullFileNameConvert), multipleFileFormat, multipleFileNumber); setStringParam(NDFullFileName, fullFileNameConvert); } getIntegerParam(NDArrayCallbacks, &arrayCallbacks); if (arrayCallbacks) { getIntegerParam(NDArrayCounter, &imageCounter); imageCounter++; setIntegerParam(NDArrayCounter, imageCounter); /* Call the callbacks to update any changes */ callParamCallbacks(); /* Get an image buffer from the pool */ getIntegerParam(ADMaxSizeX, &dims[0]); getIntegerParam(ADMaxSizeY, &dims[1]); pImage = this->pNDArrayPool->alloc(2, dims, NDInt32, 0, NULL); epicsSnprintf(statusMessage, sizeof(statusMessage), "Reading image file %s", fullFileNameConvert); setStringParam(ADStatusMessage, statusMessage); callParamCallbacks(); /* We release the mutex when calling readImageFile, because this takes a long time and * we need to allow abort operations to get through */ this->unlock(); status = readImageFile(fullFileNameConvert, &startTime, acquireTime + readImageFileTimeout, pImage); this->lock(); /* If there was an error jump to bottom of loop */ if (status) { acquire = 0; pImage->release(); continue; } getIntegerParam(PilatusFlatFieldValid, &flatFieldValid); if (flatFieldValid) { epicsInt32 *pData, *pFlat, i; for (i=0, pData = (epicsInt32 *)pImage->pData, pFlat = (epicsInt32 *)this->pFlatField->pData; i<dims[0]*dims[1]; i++, pData++, pFlat++) { *pData = (epicsInt32)((this->averageFlatField * *pData) / *pFlat); } } /* Put the frame number and time stamp into the buffer */ pImage->uniqueId = imageCounter; pImage->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9; /* Get any attributes that have been defined for this driver */ this->getAttributes(pImage->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:%s: calling NDArray callback\n", driverName, functionName); doCallbacksGenericPointer(pImage, NDArrayData, 0); this->lock(); /* Free the image buffer */ pImage->release(); } if (numImages == 1) { if (triggerMode == TMAlignment) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "Exposure %s", fullFileName); /* Send the acquire command to camserver and wait for the 15OK response */ writeReadCamserver(2.0); } else { acquire = 0; } } else if (numImages > 1) { multipleFileNextImage++; multipleFileNumber++; multipleFileNumber2++; if (multipleFileNextImage == numImages) acquire = 0; } } /* We are done acquiring */ /* Wait for the 7OK response from camserver in the case of multiple images */ if ((numImages > 1) && (status == asynSuccess)) { /* If arrayCallbacks is 0we will have gone through the above loop without waiting * for each image file to be written. Thus, we may need to wait a long time for * the 7OK response. * If arrayCallbacks is 1 then the response should arrive fairly soon. */ if (arrayCallbacks) timeout = readImageFileTimeout; else timeout = numImages * acquireTime + readImageFileTimeout; setStringParam(ADStatusMessage, "Waiting for 7OK response"); callParamCallbacks(); /* We release the mutex because we may wait a long time and need to allow abort * operations to get through */ this->unlock(); readCamserver(timeout); this->lock(); } setShutter(0); setIntegerParam(ADAcquire, 0); setIntegerParam(PilatusArmed, 0); /* If everything was ok, set the status back to idle */ if (!status) setIntegerParam(ADStatus, ADStatusIdle); else setIntegerParam(ADStatus, ADStatusError); /* Call the callbacks to update any changes */ callParamCallbacks(); } } /** Called when asyn clients call pasynInt32->write(). * This function performs actions for some parameters, including ADAcquire, ADTriggerMode, etc. * For all parameters it sets the value in the parameter library and calls any registered callbacks.. * \param[in] pasynUser pasynUser structure that encodes the reason and address. * \param[in] value Value to write. */ asynStatus pilatusDetector::writeInt32(asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; int adstatus; asynStatus status = asynSuccess; const char *functionName = "writeInt32"; status = setIntegerParam(function, value); if (function == ADAcquire) { getIntegerParam(ADStatus, &adstatus); if (value && (adstatus == ADStatusIdle || adstatus == ADStatusError)) { /* Send an event to wake up the Pilatus task. */ epicsEventSignal(this->startEventId); } if (!value && (adstatus == ADStatusAcquire)) { /* This was a command to stop acquisition */ epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "Stop"); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "K"); writeCamserver(CAMSERVER_DEFAULT_TIMEOUT); epicsEventSignal(this->stopEventId); } } else if ((function == ADTriggerMode) || (function == ADNumImages) || (function == ADNumExposures) || (function == PilatusGapFill)) { setAcquireParams(); } else if (function == PilatusThresholdApply) { setThreshold(); } else if (function == PilatusNumOscill) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings N_oscillations %d", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else { /* If this parameter belongs to a base class call its method */ if (function < FIRST_PILATUS_PARAM) status = ADDriver::writeInt32(pasynUser, value); } /* Do callbacks so higher layers see any changes */ callParamCallbacks(); if (status) asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:%s: error, status=%d function=%d, value=%d\n", driverName, functionName, status, function, value); else asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d, value=%d\n", driverName, functionName, function, value); return status; } /** Called when asyn clients call pasynFloat64->write(). * This function performs actions for some parameters, including ADAcquireTime, ADGain, etc. * For all parameters it sets the value in the parameter library and calls any registered callbacks.. * \param[in] pasynUser pasynUser structure that encodes the reason and address. * \param[in] value Value to write. */ asynStatus pilatusDetector::writeFloat64(asynUser *pasynUser, epicsFloat64 value) { int function = pasynUser->reason; asynStatus status = asynSuccess; double energyLow, energyHigh; double beamX, beamY; int thresholdAutoApply; const char *functionName = "writeFloat64"; /* 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); /* Changing any of the following parameters requires recomputing the base image */ if ((function == ADGain) || (function == PilatusThreshold)) { getIntegerParam(PilatusThresholdAutoApply, &thresholdAutoApply); if (thresholdAutoApply) setThreshold(); } else if ((function == ADAcquireTime) || (function == ADAcquirePeriod) || (function == PilatusDelayTime)) { setAcquireParams(); } else if (function == PilatusWavelength) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Wavelength %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if ((function == PilatusEnergyLow) || (function == PilatusEnergyHigh)) { getDoubleParam(PilatusEnergyLow, &energyLow); getDoubleParam(PilatusEnergyHigh, &energyHigh); epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Energy_range %f,%f", energyLow, energyHigh); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusDetDist) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Detector_distance %f", value / 1000.0); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusDetVOffset) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Detector_Voffset %f", value / 1000.0); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if ((function == PilatusBeamX) || (function == PilatusBeamY)) { getDoubleParam(PilatusBeamX, &beamX); getDoubleParam(PilatusBeamY, &beamY); epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Beam_xy %f,%f", beamX, beamY); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusFlux) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Flux %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusFilterTransm) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Filter_transmission %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusStartAngle) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Start_angle %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusAngleIncr) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Angle_increment %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusDet2theta) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Detector_2theta %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusPolarization) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Polarization %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusAlpha) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Alpha %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusKappa) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Kappa %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusPhi) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Phi %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else if (function == PilatusChi) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Chi %f", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else { /* If this parameter belongs to a base class call its method */ if (function < FIRST_PILATUS_PARAM) status = ADDriver::writeFloat64(pasynUser, value); } /* Do callbacks so higher layers see any changes */ 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; } /** Called when asyn clients call pasynOctet->write(). * This function performs actions for some parameters, including PilatusBadPixelFile, ADFilePath, etc. * For all parameters it sets the value in the parameter library and calls any registered callbacks.. * \param[in] pasynUser pasynUser structure that encodes the reason and address. * \param[in] value Address of the string to write. * \param[in] nChars Number of characters to write. * \param[out] nActual Number of characters actually written. */ asynStatus pilatusDetector::writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual) { int function = pasynUser->reason; asynStatus status = asynSuccess; const char *functionName = "writeOctet"; /* Set the parameter in the parameter library. */ status = (asynStatus)setStringParam(function, (char *)value); if (function == PilatusBadPixelFile) { this->readBadPixelFile(value); } else if (function == PilatusFlatFieldFile) { this->readFlatFieldFile(value); } else if (function == NDFilePath) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "imgpath %s", value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); this->checkPath(); } else if (function == PilatusOscillAxis) { epicsSnprintf(this->toCamserver, sizeof(this->toCamserver), "mxsettings Oscillation_axis %s", strlen(value) == 0 ? "(nil)" : value); writeReadCamserver(CAMSERVER_DEFAULT_TIMEOUT); } else { /* If this parameter belongs to a base class call its method */ if (function < FIRST_PILATUS_PARAM) status = ADDriver::writeOctet(pasynUser, value, nChars, nActual); } /* Do callbacks so higher layers see any changes */ status = (asynStatus)callParamCallbacks(); if (status) epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s:%s: status=%d, function=%d, value=%s", driverName, functionName, status, function, value); else asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d, value=%s\n", driverName, functionName, function, value); *nActual = nChars; return status; } /** Report status of the driver. * Prints details about the driver if details>0. * It then calls the ADDriver::report() method. * \param[in] fp File pointed passed by caller where the output is written to. * \param[in] details If >0 then driver details are printed. */ void pilatusDetector::report(FILE *fp, int details) { fprintf(fp, "Pilatus detector %s\n", this->portName); if (details > 0) { int nx, ny, dataType; getIntegerParam(ADSizeX, &nx); getIntegerParam(ADSizeY, &ny); getIntegerParam(NDDataType, &dataType); fprintf(fp, " NX, NY: %d %d\n", nx, ny); fprintf(fp, " Data type: %d\n", dataType); } /* Invoke the base class method */ ADDriver::report(fp, details); } extern "C" int pilatusDetectorConfig(const char *portName, const char *camserverPort, int maxSizeX, int maxSizeY, int maxBuffers, size_t maxMemory, int priority, int stackSize) { new pilatusDetector(portName, camserverPort, maxSizeX, maxSizeY, maxBuffers, maxMemory, priority, stackSize); return(asynSuccess); } /** Constructor for Pilatus driver; most parameters are simply passed to ADDriver::ADDriver. * After calling the base class constructor this method creates a thread to collect the detector data, * and sets reasonable default values for the parameters defined in this class, asynNDArrayDriver, and ADDriver. * \param[in] portName The name of the asyn port driver to be created. * \param[in] camserverPort The name of the asyn port previously created with drvAsynIPPortConfigure to * communicate with camserver. * \param[in] maxSizeX The size of the Pilatus detector in the X direction. * \param[in] maxSizeY The size of the Pilatus detector in the Y direction. * \param[in] portName The name of the asyn port driver to be created. * \param[in] maxBuffers The maximum number of NDArray buffers that the NDArrayPool for this driver is * allowed to allocate. Set this to -1 to allow an unlimited number of buffers. * \param[in] maxMemory The maximum amount of memory that the NDArrayPool for this driver is * allowed to allocate. Set this to -1 to allow an unlimited amount of memory. * \param[in] priority The thread priority for the asyn port driver thread if ASYN_CANBLOCK is set in asynFlags. * \param[in] stackSize The stack size for the asyn port driver thread if ASYN_CANBLOCK is set in asynFlags. */ pilatusDetector::pilatusDetector(const char *portName, const char *camserverPort, int maxSizeX, int maxSizeY, int maxBuffers, size_t maxMemory, int priority, int stackSize) : ADDriver(portName, 1, NUM_PILATUS_PARAMS, maxBuffers, maxMemory, 0, 0, /* No interfaces beyond those set in ADDriver.cpp */ ASYN_CANBLOCK, 1, /* ASYN_CANBLOCK=1, ASYN_MULTIDEVICE=0, autoConnect=1 */ priority, stackSize), imagesRemaining(0) { int status = asynSuccess; const char *functionName = "pilatusDetector"; int dims[2]; /* Create the epicsEvents for signaling to the pilatus task when acquisition starts and stops */ this->startEventId = epicsEventCreate(epicsEventEmpty); if (!this->startEventId) { printf("%s:%s epicsEventCreate failure for start event\n", driverName, functionName); return; } this->stopEventId = epicsEventCreate(epicsEventEmpty); if (!this->stopEventId) { printf("%s:%s epicsEventCreate failure for stop event\n", driverName, functionName); return; } /* Allocate the raw buffer we use to read image files. Only do this once */ dims[0] = maxSizeX; dims[1] = maxSizeY; /* Allocate the raw buffer we use for flat fields. */ this->pFlatField = this->pNDArrayPool->alloc(2, dims, NDUInt32, 0, NULL); /* Connect to camserver */ status = pasynOctetSyncIO->connect(camserverPort, 0, &this->pasynUserCamserver, NULL); createParam(PilatusDelayTimeString, asynParamFloat64, &PilatusDelayTime); createParam(PilatusThresholdString, asynParamFloat64, &PilatusThreshold); createParam(PilatusThresholdApplyString, asynParamInt32, &PilatusThresholdApply); createParam(PilatusThresholdAutoApplyString, asynParamInt32, &PilatusThresholdAutoApply); createParam(PilatusArmedString, asynParamInt32, &PilatusArmed); createParam(PilatusImageFileTmotString, asynParamFloat64, &PilatusImageFileTmot); createParam(PilatusBadPixelFileString, asynParamOctet, &PilatusBadPixelFile); createParam(PilatusNumBadPixelsString, asynParamInt32, &PilatusNumBadPixels); createParam(PilatusFlatFieldFileString, asynParamOctet, &PilatusFlatFieldFile); createParam(PilatusMinFlatFieldString, asynParamInt32, &PilatusMinFlatField); createParam(PilatusFlatFieldValidString, asynParamInt32, &PilatusFlatFieldValid); createParam(PilatusGapFillString, asynParamInt32, &PilatusGapFill); createParam(PilatusWavelengthString, asynParamFloat64, &PilatusWavelength); createParam(PilatusEnergyLowString, asynParamFloat64, &PilatusEnergyLow); createParam(PilatusEnergyHighString, asynParamFloat64, &PilatusEnergyHigh); createParam(PilatusDetDistString, asynParamFloat64, &PilatusDetDist); createParam(PilatusDetVOffsetString, asynParamFloat64, &PilatusDetVOffset); createParam(PilatusBeamXString, asynParamFloat64, &PilatusBeamX); createParam(PilatusBeamYString, asynParamFloat64, &PilatusBeamY); createParam(PilatusFluxString, asynParamFloat64, &PilatusFlux); createParam(PilatusFilterTransmString, asynParamFloat64, &PilatusFilterTransm); createParam(PilatusStartAngleString, asynParamFloat64, &PilatusStartAngle); createParam(PilatusAngleIncrString, asynParamFloat64, &PilatusAngleIncr); createParam(PilatusDet2thetaString, asynParamFloat64, &PilatusDet2theta); createParam(PilatusPolarizationString, asynParamFloat64, &PilatusPolarization); createParam(PilatusAlphaString, asynParamFloat64, &PilatusAlpha); createParam(PilatusKappaString, asynParamFloat64, &PilatusKappa); createParam(PilatusPhiString, asynParamFloat64, &PilatusPhi); createParam(PilatusChiString, asynParamFloat64, &PilatusChi); createParam(PilatusOscillAxisString, asynParamOctet, &PilatusOscillAxis); createParam(PilatusNumOscillString, asynParamInt32, &PilatusNumOscill); /* Set some default values for parameters */ status = setStringParam (ADManufacturer, "Dectris"); status |= setStringParam (ADModel, "Pilatus"); status |= setIntegerParam(ADMaxSizeX, maxSizeX); status |= setIntegerParam(ADMaxSizeY, maxSizeY); status |= setIntegerParam(ADSizeX, maxSizeX); status |= setIntegerParam(ADSizeX, maxSizeX); status |= setIntegerParam(ADSizeY, maxSizeY); status |= setIntegerParam(NDArraySizeX, maxSizeX); status |= setIntegerParam(NDArraySizeY, maxSizeY); status |= setIntegerParam(NDArraySize, 0); status |= setIntegerParam(NDDataType, NDUInt32); status |= setIntegerParam(ADImageMode, ADImageContinuous); status |= setIntegerParam(ADTriggerMode, TMInternal); status |= setIntegerParam(PilatusArmed, 0); status |= setStringParam (PilatusBadPixelFile, ""); status |= setIntegerParam(PilatusNumBadPixels, 0); status |= setStringParam (PilatusFlatFieldFile, ""); status |= setIntegerParam(PilatusFlatFieldValid, 0); if (status) { printf("%s: unable to set camera parameters\n", functionName); return; } /* Create the thread that updates the images */ status = (epicsThreadCreate("PilatusDetTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)pilatusTaskC, this) == NULL); if (status) { printf("%s:%s epicsThreadCreate failure for image task\n", driverName, functionName); return; } } /* Code for iocsh registration */ static const iocshArg pilatusDetectorConfigArg0 = {"Port name", iocshArgString}; static const iocshArg pilatusDetectorConfigArg1 = {"camserver port name", iocshArgString}; static const iocshArg pilatusDetectorConfigArg2 = {"maxSizeX", iocshArgInt}; static const iocshArg pilatusDetectorConfigArg3 = {"maxSizeY", iocshArgInt}; static const iocshArg pilatusDetectorConfigArg4 = {"maxBuffers", iocshArgInt}; static const iocshArg pilatusDetectorConfigArg5 = {"maxMemory", iocshArgInt}; static const iocshArg pilatusDetectorConfigArg6 = {"priority", iocshArgInt}; static const iocshArg pilatusDetectorConfigArg7 = {"stackSize", iocshArgInt}; static const iocshArg * const pilatusDetectorConfigArgs[] = {&pilatusDetectorConfigArg0, &pilatusDetectorConfigArg1, &pilatusDetectorConfigArg2, &pilatusDetectorConfigArg3, &pilatusDetectorConfigArg4, &pilatusDetectorConfigArg5, &pilatusDetectorConfigArg6, &pilatusDetectorConfigArg7}; static const iocshFuncDef configPilatusDetector = {"pilatusDetectorConfig", 8, pilatusDetectorConfigArgs}; static void configPilatusDetectorCallFunc(const iocshArgBuf *args) { pilatusDetectorConfig(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival, args[6].ival, args[7].ival); } static void pilatusDetectorRegister(void) { iocshRegister(&configPilatusDetector, configPilatusDetectorCallFunc); } extern "C" { epicsExportRegistrar(pilatusDetectorRegister); } ------------------------------------------------------------------------------------------------------------- this is error message in pilatus ioc ----------------------------------------------------------------------------------- CAS: Client accept error was "Too many open files" CAS: Client accept error was "Too many open files" CAS: Client accept error was "Too many open files" CAS: Client accept error was "Too many open files" CAS: Client accept error was "Too many open files" CAS: Client accept error was "Too many open files" CAS: Client accept error was "Too many open files" /data/users/kha/BL5C-2016MAR29/230C_2_00001.cbf 2016/03/29 15:02:40.457 pilatusDetector::readCbf, failed to open CBF file "/data/users/kha/BL5C-2016MAR29/230C_2_00001.cbf" for reading: Too many open files 2016/03/29 15:45:22.164 pilatusDetector:readCamserver, timeout=1.000000, status=1 received 0 bytes ---------------------------------------------------------------------------------------------------------- When the first operation some time while the file is Not recently been updated. How can i slove this problem? thank for Reading Best Regards mujin
| ||||||||||||||
ANJ, 15 Jul 2016 |
·
Home
·
News
·
About
·
Base
·
Modules
·
Extensions
·
Distributions
·
Download
·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing · |