![]() |
![]() ![]()
Experimental Physics and
| ||||||||||||||
|
Hi all,
I wrote a driver for the Teledyne Shadobox 6k flat panel detector. The API has a function called GevWaitForFrame(timeout) which must be being executed by the driver when a frame arrives from the camera or the frame will be missed. Are there any examples of a driver that has a similar API? The problem is that it creates a race condition so if I execute the code sequentially: send trigger GevWaitForFrame(1 second) It's possible for the frame to arrive before I'm "waiting" for it. Right now I have two threads that receive epicsEventSignal - one to send the trigger and one to wait. That works ok but since I can't abort the GevWaitForFrame the driver gets out of sync for longer exposures. Eg I have a 5 second exposure so I set a 7 second timeout but then abort after 1 second my wait thread is stuck for 6 seconds. I haven't had a camera API work like this before so any examples would be really helpful. Thanks, David /* shaobox.cpp * * This is a driver for the Teledyn Shadobox camera. * * Author: David Vine * Sigray * * Created: Ausgust 6 2021 * */ #include <stddef.h> #include <stdlib.h> #include <stdarg.h> #include <math.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <iostream> #include <chrono> #include <thread> #include <epicsTime.h> #include <epicsThread.h> #include <epicsEvent.h> #include <epicsMutex.h> #include <epicsString.h> #include <epicsStdio.h> #include <epicsMutex.h> #include <epicsExit.h> #include <cantProceed.h> #include <iocsh.h> #include "ADDriver.h" #include <epicsExport.h> #include "shadobox.h" static const char *driverName = "shadobox"; void shadobox::imageGrabTask() { static const char* functionName = "grabImage"; size_t dims[2]; uint16_t byteDepth; NDDataType_t dataType; NDColorMode_t colorMode; uint32_t numBytes; dataType = NDUInt16; colorMode = NDColorModeMono; int acquire; double acquireTime = 1.0; bool verbose = true; while(!exiting_){ GEV_BUFFER_OBJECT *img = NULL; GEV_STATUS status = 0; getIntegerParam(ADAcquire, &acquire); if (!acquire){ if (verbose) printf("GrabTask: Waiting for start event\n"); status = epicsEventWait(startGrabTaskEventId_); if (verbose) printf("GrabTask: Got start event\n"); acquire = 1; getDoubleParam(ADAcquireTime, &acquireTime); } int waitTimeOut = (int)(2000*acquireTime+132); if (waitTimeOut<500) waitTimeOut = 500; if (verbose) printf("Entering GevWaitForNextFrame with timeout: %d\n", waitTimeOut); status = GevWaitForNextImage(telCamHandle_, &img, waitTimeOut); if ((img != NULL) && (status == GEVLIB_OK) ){ if (img->status==0){ lock(); getIntegerParam(ADAcquire, &acquire); // If we're not acquiring don't do anything if (acquire==0) { printf("Got image but not acquiring\n"); unlock(); continue; } dims[0] = img->w; dims[1] = img->h; byteDepth = img->d; numBytes = dims[0]*dims[1]*byteDepth; setIntegerParam(ADStatus, ADStatusReadout); setIntegerParam(NDArraySizeX, dims[0]); setIntegerParam(NDArraySizeY, dims[1]); setIntegerParam(NDArraySize, numBytes); setIntegerParam(NDDataType, dataType); setIntegerParam(NDColorMode, colorMode); callParamCallbacks(); //printf("Allocating pRaw_\n"); pRaw_ = pNDArrayPool->alloc(2, dims, dataType, 0, NULL); if (!pRaw_){ setIntegerParam(ADStatus, ADStatusAborting); callParamCallbacks(); asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Unable to allocate buffer\n", driverName, functionName); setIntegerParam(ADAcquire, 0); } else { memcpy(pRaw_->pData, img->address, numBytes); } setIntegerParam(NDArrayCounter, img->id); if (pRaw_){ pRaw_->uniqueId = img->id; updateTimeStamp(&pRaw_->epicsTS); pRaw_->timeStamp = pRaw_->epicsTS.secPastEpoch+pRaw_->epicsTS.nsec/1e9; getAttributes(pRaw_->pAttributeList); pRaw_->pAttributeList->add("ColorMode", "Color Mode", NDAttrInt32, &colorMode); } callParamCallbacks(); unlock(); /* Signal main thread image has been received */ epicsEventSignal(imageReceivedId_); } } if (img != NULL){ //printf("Releasing buffer\n"); GevReleaseImage(telCamHandle_, img); } } } void shadobox::shutdown(void){ exiting_=1; disconnectCamera(); } void shadobox::reconnectCamera(void){ disconnectCamera(); connectCamera(); } asynStatus shadobox::disconnectCamera(void){ int acquiring; asynStatus status; GEV_STATUS telStatus; // Check if acuiring status = getIntegerParam(ADAcquire, &acquiring); // If necessary stop acquisitiom if (status==asynSuccess && acquiring){ telStatus = GevStopTransfer(telCamHandle_); } for (int i=0; i<numBuffers; i++){ free(bufAddress[i]); } if (telCamHandle_){ printf("Disconnecting camera... "); GevAbortTransfer(telCamHandle_); telStatus = GevFreeTransfer(telCamHandle_); GevCloseCamera(&telCamHandle_); GevApiUninitialize(); _CloseSocketAPI(); printf("done\n"); } return asynSuccess; } static void c_shutdown(void *arg) { shadobox *s = (shadobox *)arg; s->shutdown(); } static void imageGrabTaskC(void *drvPvt) { shadobox *pPvt = (shadobox *)drvPvt; pPvt->imageGrabTask(); } static void tempReadTaskC(void *drvPvt) { shadobox *pPvt = (shadobox *)drvPvt; pPvt->tempReadTask(); } static void mainDataTaskC(void *drvPvt) { shadobox *pPvt = (shadobox *)drvPvt; pPvt->mainDataTask(); } void shadobox::tempReadTask(){ int type; double temp; while(!exiting_){ GevGetFeatureValue(telCamHandle_, "DeviceTemperature", &type, sizeof(temp), &temp); lock(); setDoubleParam(ADTemperature, temp); setDoubleParam(ADTemperatureActual, temp); callParamCallbacks(); unlock(); sleep(1); // seconds } } /** This thread interacts with the camera API to start/stop acquiring. * It implements the logic for single, multiple or continuous acquisition. */ void shadobox::mainDataTask() { int status = asynSuccess; int imageCounter; int numImages, numImagesCounter; int imageMode, triggerMode; int arrayCallbacks; int acquire=0; double acquireTime; epicsTimeStamp startTime; const char *functionName = "imageGrabTask"; GEV_STATUS telStatus; epicsEventStatus eventStatus; int missedFrames = 0; int shadSynch = 0; int disconnectCycles = 0; bool verbose = true; this->lock(); /* Loop forever */ while (1) { /* If we are not acquiring then wait for a semaphore that is given when acquisition is started */ if (!acquire) { setIntegerParam(ADStatus, ADStatusIdle); callParamCallbacks(); /* Release the lock while we wait for an event that says acquire has started, then lock again */ asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: waiting for acquire to start\n", driverName, functionName); this->unlock(); if (verbose) printf("Waiting for event\n"); status = epicsEventWait(startEventId_); if (verbose) printf("Got start event\n"); this->lock(); missedFrames = 0; disconnectCycles = 0; getIntegerParam(ADNumImages, &numImages); getIntegerParam(ADImageMode, &imageMode); getIntegerParam(ADTriggerMode, &triggerMode); if (imageMode == 0){ // Single numImages = 1; } else if (imageMode==1){ // Multiple getIntegerParam(ADNumImages, &numImages); } else if (imageMode == 2){ // Continuous numImages = -1; } GevStartTransfer(telCamHandle_, numImages); acquire = 1; setIntegerParam(ADNumImagesCounter, 0); } /* We are acquiring. */ /* Get the current time */ epicsTimeGetCurrent(&startTime); setIntegerParam(ADStatus, ADStatusAcquire); getDoubleParam(ADAcquireTime, &acquireTime); /* Call the callbacks to update any changes */ callParamCallbacks(); /* If internal triggering send the trigger */ setStringParam(ADStatusMessage, "Acquiring"); if (triggerMode!=0){ setStringParam(ADStatusMessage, "Wait for trigger"); } getIntegerParam(ShadTrigMode, &shadSynch); if (shadSynch==0){ // Snapshot if (verbose) printf("Sending trigger\n"); setCameraFeature("SoftwareTrigger", 1); } callParamCallbacks(); /* Wait for signal from grabber thread that image was received */ unlock(); auto t_start = std::chrono::high_resolution_clock::now(); double waitTimeOut = 2.0*acquireTime+0.132; if (waitTimeOut<0.5) waitTimeOut = 0.5; eventStatus = epicsEventWaitWithTimeout(imageReceivedId_, waitTimeOut); auto t_end = std::chrono::high_resolution_clock::now(); double elapsed_exp = std::chrono::duration<double, std::milli>(t_end-t_start).count(); printf("Elapsed exposure time: %f ms\n", elapsed_exp); lock(); getIntegerParam(ADAcquire, &acquire); if (!acquire){ // Stop was pressed during continuous acquisition printf("Aborting\n"); GevStopTransfer(telCamHandle_); continue; } if (eventStatus == epicsEventOK){ setIntegerParam(ADStatus, ADStatusReadout); getIntegerParam(NDArrayCounter, &imageCounter); getIntegerParam(ADNumImages, &numImages); getIntegerParam(ADNumImagesCounter, &numImagesCounter); getIntegerParam(NDArrayCallbacks, &arrayCallbacks); imageCounter++; numImagesCounter++; setIntegerParam(NDArrayCounter, imageCounter); setIntegerParam(ADNumImagesCounter, numImagesCounter); /* Call the callbacks to update any changes */ callParamCallbacks(); if (arrayCallbacks) { /* Call the NDArray callback */ asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: calling imageData callback\n", driverName, functionName); doCallbacksGenericPointer(pRaw_, NDArrayData, 0); } } else if (eventStatus == epicsEventWaitTimeout){ int numShadRetries = 10; //getIntegerParam(ShadRetries, &numShadRetries); if (missedFrames<numShadRetries){ missedFrames++; printf("Missed frame from timeout\n"); char buf[50]; sprintf(buf, "Missed Frame %d, Cycle %d", missedFrames, disconnectCycles); setIntegerParam(ADStatus, ADStatusError); setStringParam(ADStatusMessage, buf); // Continue to send another trigger continue; /* } else if ((missedFrames>=numShadRetries)&&(disconnectCycles<4)){ disconnectCycles++; missedFrames = 0; setStringParam(ADStatusMessage, "Reconnecting..."); callParamCallbacks(); reconnectCamera(); setStringParam(ADStatusMessage, "Reconnecting...Done"); callParamCallbacks(); int imagesCompleted = 0; getIntegerParam(ADNumImagesCounter, &imagesCompleted); int imagesRemaining = numImages - imagesCompleted; GevStartTransfer(telCamHandle_, imagesRemaining); continue; */ } else { setStringParam(ADStatusMessage, "Aborting acquisition. Sorry."); setIntegerParam(ADStatus, ADStatusError); acquire = 0; setIntegerParam(ADAcquire, acquire); callParamCallbacks(); continue; } } /* See if acquisition is done */ if ((imageMode == ADImageSingle) || ((imageMode == ADImageMultiple) && (numImagesCounter >= numImages))) { /* First do callback on ADStatus. */ setStringParam(ADStatusMessage, "Waiting for acquisition"); setIntegerParam(ADStatus, ADStatusIdle); callParamCallbacks(); acquire = 0; setIntegerParam(ADAcquire, acquire); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: acquisition completed\n", driverName, functionName); } if (pRaw_ != NULL){ //printf("Releasing pRaw\n"); pRaw_->release(); } /* Call the callbacks to update any changes */ callParamCallbacks(); } } /** Called when asyn clients call pasynInt32->write(). * This function performs actions for some parameters, including ADAcquire, ADColorMode, 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 shadobox::writeInt32(asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; int adstatus; int acquiring; int imageMode; asynStatus status = asynSuccess; /* Ensure that ADStatus is set correctly before we set ADAcquire.*/ getIntegerParam(ADStatus, &adstatus); getIntegerParam(ADAcquire, &acquiring); getIntegerParam(ADImageMode, &imageMode); if (function == ADAcquire) { if (value && !acquiring) { setStringParam(ADStatusMessage, "Acquiring data"); } if (!value && acquiring) { setStringParam(ADStatusMessage, "Acquisition stopped"); if (imageMode == ADImageContinuous) { setIntegerParam(ADStatus, ADStatusIdle); } else { setIntegerParam(ADStatus, ADStatusAborted); } setIntegerParam(ADStatus, ADStatusAcquire); } } callParamCallbacks(); /* 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 = setIntegerParam(function, value); /* For a real detector this is where the parameter is sent to the hardware */ if (function == ADAcquire) { if (value && !acquiring) { /* Send an event to wake up the simulation task. * It won't actually start generating new images until we release the lock below */ epicsEventSignal(startEventId_); epicsEventSignal(startGrabTaskEventId_); } if (!value && acquiring) { /* This was a command to stop acquisition */ /* Send the stop event */ epicsEventSignal(stopEventId_); /* Main data task is waiting for an image so stop it*/ epicsEventSignal(imageReceivedId_); } } else if ((function == ADBinX) || (function == ADBinY)){ if (value < 1) value = 1; if (value > 2) value = 2; int binX, binY; std::string rmode; getIntegerParam(ADBinX, &binX); getIntegerParam(ADBinY, &binY); if (value!=binX){ setIntegerParam(ADBinX, value); } if (value!=binY){ setIntegerParam(ADBinY, value); } if (value==2){ rmode = "Binning"; } else { rmode = "FullResolution"; } setCameraFeature("ReadOutMode", rmode); updateSensorSize(); } else if (function == ADMinX){ if (value<0) value = 0; if (value>ADMaxSizeX-2) value = ADMaxSizeX-2; int sizeX, maxSizeX; getIntegerParam(ADSizeX, &sizeX); getIntegerParam(ADMaxSizeX, &maxSizeX); setCameraFeature("ROIStartH", value); if (value+sizeX>maxSizeX-1){ sizeX = maxSizeX-1-value; setIntegerParam(ADSizeX, sizeX); } uint16_t stopX = value+sizeX; printf("Setting startH=%d, stopH=%d\n", value, stopX); setCameraFeature("ROIStopH", stopX); } else if (function == ADMinY){ if (value<0) value = 0; if (value>ADMaxSizeY-2) value = ADMaxSizeY-2; int sizeY, maxSizeY; getIntegerParam(ADSizeY, &sizeY); getIntegerParam(ADMaxSizeY, &maxSizeY); setCameraFeature("ROIStartV", value); if (value+sizeY>maxSizeY-1){ sizeY = maxSizeY-1-value; setIntegerParam(ADSizeY, sizeY); } int stopY = value+sizeY; printf("Setting startY=%d, stopY=%d\n", value, stopY); setCameraFeature("ROIStopV", stopY); } else if (function == ADSizeX){ int maxSizeX, minX; getIntegerParam(ADMaxSizeX, &maxSizeX); getIntegerParam(ADMinX, &minX); if (value<1) value = 1; if (value>=maxSizeX-minX) value = maxSizeX-minX-1; setIntegerParam(ADSizeX, value); printf("roi stopH=%d\n", value); setCameraFeature("ROIStopH", value); } else if (function == ADSizeY){ int maxSizeY, minY; getIntegerParam(ADMaxSizeY, &maxSizeY); getIntegerParam(ADMinY, &minY); if (value<1) value = 1; if (value>=maxSizeY-minY) value = maxSizeY-minY-1; setIntegerParam(ADSizeY, value); printf("roi stopY=%d\n", value); setCameraFeature("ROIStopV", value); } else if (function == ShadReadOutMode){ // 0 = Full Resolution, 1 = Binning, 2 = ROI setCameraFeature("ReadOutMode", value); } else if (function == ShadFullWell){ setCameraFeature("FullWell", value); } else if (function == ShadTrigMode){ if (value==0){ setCameraFeature("SynchronizationMode", "Snapshot"); printf("Synch mode: Snapshot\n"); } else if (value==1){ setCameraFeature("SynchronizationMode", "FreeRunning"); printf("Synch mode: Free Running\n"); } } else if (function == ShadGain){ setCameraFeature("DigitalGain", value); } else if (function == ShadFFCEnable){ setCameraFeature("FFCEnable", value); } else if (function == ShadFFCActive){ setCameraFeature("FFCActive", value); } else if (function == ShadDPCEnable){ setCameraFeature("DPCEnable", value); } else if (function == ShadDPCActive){ setCameraFeature("DPCActive", value); } else if (function == ShadTurbo){ setCameraFeature("transferTurboMode", value); } else { /* If this parameter belongs to a base class call its method */ if (function < FIRST_SHAD_PARAM) status = ADDriver::writeInt32(pasynUser, value); } /* Do callbacks so higher layers see any changes */ callParamCallbacks(); if (status) asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:writeInt32 error, status=%d function=%d, value=%d\n", driverName, status, function, value); else asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:writeInt32: function=%d, value=%d\n", driverName, 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 shadobox::writeFloat64(asynUser *pasynUser, epicsFloat64 value) { int function = pasynUser->reason; asynStatus status = asynSuccess; /* 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 simulation parameters requires recomputing the base image */ if (function == ADAcquireTime){ if (value<10e-3) value = 10e-3; if (value>60.0) value = 60.0; setCameraFeature("FrameInterval", (int)(1e6*value)); setCameraFeature("SoftwareTrigIntTime", (int)(1e6*value)); status = setDoubleParam(ADAcquireTime, value); int type, frameInterval, trigIntTime; GevGetFeatureValue(telCamHandle_, "FrameInterval", &type, sizeof(frameInterval), &frameInterval); GevGetFeatureValue(telCamHandle_, "SoftwareTrigIntTime", &type, sizeof(trigIntTime), &trigIntTime); printf("Frame interval: %d\n", frameInterval); printf("Trig int time: %d\n", trigIntTime); } else { /* This parameter belongs to a base class call its method */ status = ADDriver::writeFloat64(pasynUser, value); } /* Do callbacks so higher layers see any changes */ callParamCallbacks(); if (status) asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:writeFloat64 error, status=%d function=%d, value=%f\n", driverName, status, function, value); else asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:writeFloat64: function=%d, value=%f\n", driverName, function, value); return status; } int shadobox::setCameraFeature(std::string feature, unsigned int value){ int rbv, type, telStatus; telStatus = GevSetFeatureValue(telCamHandle_, feature.c_str(), sizeof(value), &value); if (telStatus!=GEVLIB_OK){ printf("Coud not set %s (status=%d)\n", feature.c_str(), telStatus); } GevGetFeatureValue(telCamHandle_, feature.c_str(), &type, sizeof(rbv), &rbv); if (rbv!=value){ printf( "%s:setCameraFeature error, status=%d feature=%s value=%d rbv=%d\n", driverName, telStatus, feature.c_str(), value, rbv); return asynError; } return asynSuccess; } int shadobox::setCameraFeature(std::string feature, int value){ int rbv, type, telStatus; telStatus = GevSetFeatureValue(telCamHandle_, feature.c_str(), sizeof(value), &value); if (telStatus!=GEVLIB_OK){ printf("Coud not set %s (status=%d)\n", feature.c_str(), telStatus); } GevGetFeatureValue(telCamHandle_, feature.c_str(), &type, sizeof(rbv), &rbv); if (rbv!=value){ printf( "%s:setCameraFeature error, status=%d feature=%s value=%d rbv=%d\n", driverName, telStatus, feature.c_str(), value, rbv); return asynError; } return asynSuccess; } int shadobox::setCameraFeature(std::string feature, double value){ int type, telStatus; double rbv; telStatus = GevSetFeatureValue(telCamHandle_, feature.c_str(), sizeof(value), &value); if (telStatus!=GEVLIB_OK){ printf("Coud not set %s (status=%d)\n", feature.c_str(), telStatus); } GevGetFeatureValue(telCamHandle_, feature.c_str(), &type, sizeof(rbv), &rbv); if (std::abs(rbv-value)>1e-3){ printf("%s:setCameraFeature error, status=%d feature=%s value=%f\n", driverName, telStatus, feature.c_str(), value); return asynError; } return asynSuccess; } int shadobox::setCameraFeature(std::string feature, std::string value){ int type, telStatus; std::string rbv; telStatus = GevSetFeatureValueAsString(telCamHandle_, feature.c_str(), value.c_str()); if (telStatus!=GEVLIB_OK){ printf("Could not set %s (status=%d)\n", feature.c_str(), telStatus); } GevGetFeatureValueAsString(telCamHandle_, feature.c_str(), &type, sizeof(rbv), &rbv[0]); if (strcmp(value.c_str(), rbv.c_str())!=0){ printf("%s:setCameraFeature error, status=%d feature=%s value=%s rbv=%s\n", driverName, telStatus, feature.c_str(), value.c_str(), rbv.c_str()); return asynError; } return asynSuccess; } /** 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 shadobox::report(FILE *fp, int details) { fprintf(fp, "Simulation 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); } int shadobox::connectCamera(){ static const char* functionName = "connectCamera"; GEV_STATUS telStatus; int numCameras = 0; int type, status; unsigned int height, width, format; unsigned long int size; char synchModeStr[64] = {0}; char versionString[40] = {0}; GevGetLibraryConfigOptions(&telLibOpt_); telLibOpt_.logLevel = GEV_LOG_LEVEL_NORMAL; GevSetLibraryConfigOptions(&telLibOpt_); telStatus = GevGetCameraList(telCamInt_, MAX_CAMERAS, &numCameras); printf("%s:%s: Discovered %d cameras on the network\n", driverName, functionName, numCameras); if (numCameras==0){ std::this_thread::sleep_for(std::chrono::milliseconds(3000)); printf("%s:%s: No cameras detected on network\n", driverName, functionName); return asynError; } telStatus = GevOpenCameraBySN(serial_number, GevControlMode, &telCamHandle_); if (telStatus==0){ char xmlFileName[1024] = {0}; telStatus = GevGetGenICamXML_FileName( telCamHandle_, (int)sizeof(xmlFileName), xmlFileName); if (telStatus==GEVLIB_OK){ printf("XML stored as: %s\n", xmlFileName); } /* Set some default values for parameters */ char stringFeature[32] = {0}; GevGetFeatureValueAsString(telCamHandle_, "DeviceVendorName", &type, sizeof(stringFeature), stringFeature); status = setStringParam(ADManufacturer, stringFeature); memset(stringFeature, 0, sizeof(stringFeature)); GevGetFeatureValueAsString(telCamHandle_, "DeviceModelName", &type, sizeof(stringFeature), stringFeature); status = setStringParam(ADModel, stringFeature); setStringParam(ADSerialNumber, serial_number); memset(stringFeature, 0, sizeof(stringFeature)); GevGetFeatureValueAsString(telCamHandle_, "DeviceVersion", &type, sizeof(stringFeature), stringFeature); setStringParam(ADFirmwareVersion, stringFeature); memset(stringFeature, 0, sizeof(stringFeature)); epicsSnprintf(versionString, sizeof(versionString), "%d.%d.%d", DRIVER_VERSION, DRIVER_REVISION, DRIVER_MODIFICATION); setStringParam(NDDriverVersion, versionString); GevGetFeatureValueAsString(telCamHandle_, "HardwareRevision", &type, sizeof(stringFeature), stringFeature); setStringParam(ADSDKVersion, stringFeature); uint32_t intFeature = 0; uint32_t width, height; GevGetFeatureValue(telCamHandle_, "Width", &type, sizeof(width), &width); status |= setIntegerParam(ADMaxSizeX, width); status |= setIntegerParam(ADSizeX, width); status |= setIntegerParam(NDArraySizeX, width); GevGetFeatureValue(telCamHandle_, "Height", &type, sizeof(height), &height); status |= setIntegerParam(ADMaxSizeY, height); status |= setIntegerParam(ADSizeY, height); status |= setIntegerParam(NDArraySizeY, height); status |= setIntegerParam(ADMinX, 0); status |= setIntegerParam(ADMinY, 0); status |= setIntegerParam(ADBinX, 1); status |= setIntegerParam(ADBinY, 1); status |= setIntegerParam(ADReverseX, 0); status |= setIntegerParam(ADReverseY, 0); status |= setIntegerParam(NDArraySize, 0); status |= setIntegerParam(NDDataType, NDInt16); status |= setIntegerParam(NDColorMode, NDColorModeMono); status |= setIntegerParam(NDArraySize, 2*width*height); callParamCallbacks(); GevGetCameraInterfaceOptions(telCamHandle_, &telCamOpt_); telCamOpt_.heartbeat_timeout_ms = 5000; // Disconnect detection (5 seconds) telCamOpt_.streamFrame_timeout_ms = 1001; // Internal timeout for frame reception telCamOpt_.streamNumFramesBuffered = 1; // Buffer frames internally telCamOpt_.streamMemoryLimitMax = 64*2304*2940; // Adjust packet memory buffering limit telCamOpt_.streamPktSize = 9216; telCamOpt_.streamPktDelay = 10; int numCpus = _GetNumCpus(); if (numCpus>1){ telCamOpt_.streamThreadAffinity = numCpus-1; telCamOpt_.serverThreadAffinity = numCpus-2; } GevSetCameraInterfaceOptions(telCamHandle_, &telCamOpt_); bufSize = width*height*2; for (int i=0; i<numBuffers; i++){ bufAddress[i] = (PUINT8)malloc(bufSize); memset(bufAddress[i], 0, bufSize); } telStatus = GevInitializeTransfer(telCamHandle_, SynchronousNextEmpty, bufSize, numBuffers, bufAddress); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Could not open camera (Error: %d)\n", driverName, functionName, numCameras); this->disconnect(this->pasynUserSelf); return asynError; } callParamCallbacks(); return asynSuccess; } void shadobox::updateSensorSize(void){ int type, width, height; int status; GevGetFeatureValue(telCamHandle_, "Width", &type, sizeof(width), &width); status |= setIntegerParam(ADMaxSizeX, width); status |= setIntegerParam(ADSizeX, width); status |= setIntegerParam(NDArraySizeX, width); GevGetFeatureValue(telCamHandle_, "Height", &type, sizeof(height), &height); status |= setIntegerParam(ADMaxSizeY, height); status |= setIntegerParam(ADSizeY, height); status |= setIntegerParam(NDArraySizeY, height); status |= setIntegerParam(NDArraySize, 2*width*height); callParamCallbacks(); } /** Constructor for shadobox; most parameters are simply passed to ADDriver::ADDriver. * After calling the base class constructor this method creates a thread to compute the simulated detector data, * and sets reasonable default values for parameters defined in this class, asynNDArrayDriver and ADDriver. * \param[in] portName The name of the asyn port driver to be created. * \param[in] serial_number The serial number used to connect to the shadobox * \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. */ shadobox::shadobox(const char *portName, char* serial_number, int maxBuffers, size_t maxMemory, int priority, int stackSize) : ADDriver(portName, 1, 0, maxBuffers, maxMemory, 0, 0, /* No interfaces beyond those set in ADDriver.cpp */ 0, 1, /* ASYN_CANBLOCK=0, ASYN_MULTIDEVICE=0, autoConnect=1 */ priority, stackSize), pRaw_(NULL), serial_number(serial_number) { int status = asynSuccess; char versionString[20]; const char *functionName = "shadobox"; /* Create the epicsEvents for signaling to the simulate task when acquisition starts and stops */ startEventId_ = epicsEventCreate(epicsEventEmpty); if (!startEventId_) { printf("%s:%s epicsEventCreate failure for start event\n", driverName, functionName); return; } startGrabTaskEventId_ = epicsEventCreate(epicsEventEmpty); if (!startGrabTaskEventId_) { printf("%s:%s epicsEventCreate failure for start grab task event\n", driverName, functionName); return; } stopEventId_ = epicsEventCreate(epicsEventEmpty); if (!stopEventId_) { printf("%s:%s epicsEventCreate failure for stop event\n", driverName, functionName); return; } imageReceivedId_ = epicsEventCreate(epicsEventEmpty); if (!imageReceivedId_) { printf("%s:%s epicsEventCreate failure for image received event\n", driverName, functionName); return; } createParam(ShadFullWellString, asynParamInt32, &ShadFullWell); createParam(ShadGainString, asynParamInt32, &ShadGain); createParam(ShadTrigModeString, asynParamInt32, &ShadTrigMode); createParam(ShadRetriesString, asynParamInt32, &ShadRetries); createParam(ShadReadOutModeString, asynParamInt32, &ShadReadOutMode); createParam(ShadTurboString, asynParamInt32, &ShadTurbo); createParam(ShadFFCEnableString, asynParamInt32, &ShadFFCEnable); createParam(ShadFFCActiveString, asynParamInt32, &ShadFFCActive); createParam(ShadDPCEnableString, asynParamInt32, &ShadDPCEnable); createParam(ShadDPCActiveString, asynParamInt32, &ShadDPCActive); status = connectCamera(); if (status){ printf("Didn't connect to camera\n"); return; } /* Create the thread that updates the images */ status = (epicsThreadCreate("ShadoboxMainDataTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)mainDataTaskC, this) == NULL); if (status) { printf("%s:%s epicsThreadCreate failure for image grab task\n", driverName, functionName); return; } /* Create the thread that updates the temperature*/ status = (epicsThreadCreate("ShadoboxTempReadTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)tempReadTaskC, this) == NULL); if (status) { printf("%s:%s epicsThreadCreate failure for temp read task\n", driverName, functionName); return; } /* Create the thread that grabs images from buffer */ status = (epicsThreadCreate("ShadoboxImageGrabTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)imageGrabTaskC, this) == NULL); if (status) { printf("%s:%s epicsThreadCreate failure for image grab task\n", driverName, functionName); return; } epicsAtExit(c_shutdown, this); return; } /** Configuration command, called directly or from iocsh */ extern "C" int shadoboxConfig(const char *portName, char* serialNumber, int maxBuffers, int maxMemory, int priority, int stackSize) { new shadobox(portName, serialNumber, (maxBuffers < 0) ? 0 : maxBuffers, (maxMemory < 0) ? 0 : maxMemory, priority, stackSize); return(asynSuccess); } /** Code for iocsh registration */ static const iocshArg shadoboxConfigArg0 = {"Port name", iocshArgString}; static const iocshArg shadoboxConfigArg1 = {"Serial Number", iocshArgString}; static const iocshArg shadoboxConfigArg2 = {"maxBuffers", iocshArgInt}; static const iocshArg shadoboxConfigArg3 = {"maxMemory", iocshArgInt}; static const iocshArg shadoboxConfigArg4 = {"priority", iocshArgInt}; static const iocshArg shadoboxConfigArg5 = {"stackSize", iocshArgInt}; static const iocshArg * const shadoboxConfigArgs[] = {&shadoboxConfigArg0, &shadoboxConfigArg1, &shadoboxConfigArg2, &shadoboxConfigArg3, &shadoboxConfigArg4, &shadoboxConfigArg5}; static const iocshFuncDef configShadobox = {"shadoboxConfig", 6, shadoboxConfigArgs}; static void configShadoboxCallFunc(const iocshArgBuf *args) { shadoboxConfig(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival); } static void shadoboxRegister(void) { iocshRegister(&configShadobox, configShadoboxCallFunc); } extern "C" { epicsExportRegistrar(shadoboxRegister); } Attachment:
ShadoBox HS Command Reference_rev09.pdf
| ||||||||||||||
ANJ, 14 Sep 2022 |
![]() · Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing · |