/** Reads the values of all the modules parameters, sets them in the parameter library**/ asynStatus mythen::getSettings() { int aux; epicsFloat32 faux; long long laux; epicsFloat64 DetTime; static const char *functionName = "getSettings"; if (acquiring_) { strcpy(outString_,"Called during Acquire"); inString_[0] = 0; goto error; } strcpy(outString_, "-get flatfieldcorrection"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux!=0 && aux!=1) goto error; setIntegerParam(SDUseFlatField, aux); strcpy(outString_, "-get badchannelinterpolation"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux!=0 && aux!=1) goto error; setIntegerParam(SDUseBadChanIntrpl, aux); strcpy(outString_, "-get ratecorrection"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux!=0 && aux!=1) goto error; setIntegerParam(SDUseCountRate, aux); strcpy(outString_, "-get nbits"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux < 0) goto error; nbits_ = aux; chanperline_ = 32/aux; setIntegerParam(SDBitDepth, aux); strcpy(outString_, "-get time"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux >= 0) DetTime = (aux * (1E-7)); else goto error; setDoubleParam(ADAcquireTime,DetTime); strcpy(outString_, "-get frames"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux >= 0) setIntegerParam(SDNumFrames, aux); strcpy(outString_, "-get tau"); writeReadMeter(); faux = stringToFloat32(this->inString_); if (faux == -1 || faux > 0) setDoubleParam(SDTau,faux); else goto error; strcpy(outString_, "-get kthresh"); writeReadMeter(); faux = stringToFloat32(this->inString_); if (faux < 0) goto error; else setDoubleParam(SDThreshold,faux); //Firmware greater than 3 commands if ((int)firmwareVersion_[1]%48 >=3) { strcpy(outString_, "-get energy"); writeReadMeter(); faux = stringToFloat32(this->inString_); if (faux < 0) goto error; else setDoubleParam(SDEnergy,faux); strcpy(outString_, "-get delafter"); writeReadMeter(); laux = stringToInt64(this->inString_); if (laux >= 0) DetTime = (laux * (1E-7)); else goto error; setDoubleParam(SDDelayTime,DetTime); /* Get trigger modes */ strcpy(outString_, "-get conttrig"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux < 0) goto error; if (aux == 1) setIntegerParam(SDTrigger, 2); else { strcpy(outString_, "-get trig"); writeReadMeter(); aux = stringToInt32(this->inString_); if (aux < 0) goto error; if (aux == 1) setIntegerParam(SDTrigger, 1); else setIntegerParam(SDTrigger, 0); } } callParamCallbacks(); // if (prevAcquiring) setAcquire(1); return asynSuccess; error: asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error, outString=%s, inString=%s\n", driverName, functionName, outString_, inString_); return asynError; }
/** Callback function that is called by the NDArray driver with new NDArray data. * Does image processing. * \param[in] pArray The NDArray from the callback. */ void NDPluginProcess::processCallbacks(NDArray *pArray) { /* This function does array processing. * It is called with the mutex already locked. It unlocks it during long calculations when private * structures don't need to be protected. */ size_t i; NDArray *pScratch=NULL; double *data, newData, newFilter; NDArrayInfo arrayInfo; double *background=NULL, *flatField=NULL, *filter=NULL; double value; size_t nElements; int saveBackground, enableBackground, validBackground; int saveFlatField, enableFlatField, validFlatField; double scaleFlatField; int enableOffsetScale, autoOffsetScale; double offset, scale, minValue, maxValue; double lowClip=0, highClip=0; int enableLowClip, enableHighClip; int resetFilter, autoResetFilter, filterCallbacks, doCallbacks=1; int enableFilter, numFilter; int dataType; int anyProcess; double oOffset, fOffset, rOffset, oScale, fScale; double oc1, oc2, oc3, oc4; double fc1, fc2, fc3, fc4; double rc1, rc2; double F1, F2, O1, O2; //const char* functionName = "processCallbacks"; /* Call the base class method */ NDPluginDriver::processCallbacks(pArray); /* Need to fetch all of these parameters while we still have the mutex */ getIntegerParam(NDPluginProcessDataType, &dataType); getIntegerParam(NDPluginProcessSaveBackground, &saveBackground); getIntegerParam(NDPluginProcessEnableBackground, &enableBackground); getIntegerParam(NDPluginProcessSaveFlatField, &saveFlatField); getIntegerParam(NDPluginProcessEnableFlatField, &enableFlatField); getDoubleParam (NDPluginProcessScaleFlatField, &scaleFlatField); getIntegerParam(NDPluginProcessEnableOffsetScale, &enableOffsetScale); getIntegerParam(NDPluginProcessAutoOffsetScale, &autoOffsetScale); getIntegerParam(NDPluginProcessEnableLowClip, &enableLowClip); getIntegerParam(NDPluginProcessEnableHighClip, &enableHighClip); getIntegerParam(NDPluginProcessEnableFilter, &enableFilter); getIntegerParam(NDPluginProcessResetFilter, &resetFilter); getIntegerParam(NDPluginProcessAutoResetFilter, &autoResetFilter); getIntegerParam(NDPluginProcessFilterCallbacks, &filterCallbacks); if (enableOffsetScale) { getDoubleParam (NDPluginProcessScale, &scale); getDoubleParam (NDPluginProcessOffset, &offset); } if (enableLowClip) getDoubleParam (NDPluginProcessLowClip, &lowClip); if (enableHighClip) getDoubleParam (NDPluginProcessHighClip, &highClip); if (resetFilter) setIntegerParam(NDPluginProcessResetFilter, 0); if (enableFilter) { getIntegerParam(NDPluginProcessNumFilter, &numFilter); getDoubleParam (NDPluginProcessOOffset, &oOffset); getDoubleParam (NDPluginProcessOScale, &oScale); getDoubleParam (NDPluginProcessOC1, &oc1); getDoubleParam (NDPluginProcessOC2, &oc2); getDoubleParam (NDPluginProcessOC3, &oc3); getDoubleParam (NDPluginProcessOC4, &oc4); getDoubleParam (NDPluginProcessFOffset, &fOffset); getDoubleParam (NDPluginProcessFScale, &fScale); getDoubleParam (NDPluginProcessFC1, &fc1); getDoubleParam (NDPluginProcessFC2, &fc2); getDoubleParam (NDPluginProcessFC3, &fc3); getDoubleParam (NDPluginProcessFC4, &fc4); getDoubleParam (NDPluginProcessROffset, &rOffset); getDoubleParam (NDPluginProcessRC1, &rc1); getDoubleParam (NDPluginProcessRC2, &rc2); } /* Release the lock now that we are only doing things that don't involve memory other thread * cannot access */ this->unlock(); /* Special case for automatic data type */ if (dataType == -1) dataType = (int)pArray->dataType; pArray->getInfo(&arrayInfo); nElements = arrayInfo.nElements; validBackground = 0; if (this->pBackground && (nElements == this->nBackgroundElements)) validBackground = 1; setIntegerParam(NDPluginProcessValidBackground, validBackground); validFlatField = 0; if (this->pFlatField && (nElements == this->nFlatFieldElements)) validFlatField = 1; setIntegerParam(NDPluginProcessValidFlatField, validFlatField); if (validBackground && enableBackground) background = (double *)this->pBackground->pData; if (validFlatField && enableFlatField) flatField = (double *)this->pFlatField->pData; anyProcess = ((enableBackground && validBackground) || (enableFlatField && validFlatField) || enableOffsetScale || autoOffsetScale || enableHighClip || enableLowClip || enableFilter); /* If no processing is to be done just convert the input array and do callbacks */ if (!anyProcess) { /* Convert the array to the desired output data type */ if (this->pArrays[0]) this->pArrays[0]->release(); this->pNDArrayPool->convert(pArray, &this->pArrays[0], (NDDataType_t)dataType); goto doCallbacks; } /* Make a copy of the array converted to double, because we cannot modify the input array */ this->pNDArrayPool->convert(pArray, &pScratch, NDFloat64); data = (double *)pScratch->pData; if (nElements > 0) { minValue = data[0]; maxValue = data[0]; } else { minValue = 0; maxValue = 1; } for (i=0; i<nElements; i++) { value = data[i]; if (autoOffsetScale) { if (data[i] < minValue) minValue = data[i]; if (data[i] > maxValue) maxValue = data[i]; } if (background) value -= background[i]; if (flatField) { if (flatField[i] != 0.) value *= scaleFlatField / flatField[i]; else value = scaleFlatField; } if (enableOffsetScale) value = (value + offset)*scale; if (enableHighClip && (value > highClip)) value = highClip; if (enableLowClip && (value < lowClip)) value = lowClip; data[i] = value; } if (enableFilter) { if (this->pFilter) { this->pFilter->getInfo(&arrayInfo); if (nElements != arrayInfo.nElements) { this->pFilter->release(); this->pFilter = NULL; } } if (!this->pFilter) { /* There is not a current filter array */ /* Make a copy of the current array, converted to double type */ this->pNDArrayPool->convert(pScratch, &this->pFilter, NDFloat64); resetFilter = 1; } if ((this->numFiltered >= numFilter) && autoResetFilter) resetFilter = 1; if (resetFilter) { filter = (double *)this->pFilter->pData; for (i=0; i<nElements; i++) { newFilter = rOffset; if (rc1) newFilter += rc1*filter[i]; if (rc2) newFilter += rc2*data[i]; filter[i] = newFilter; } this->numFiltered = 0; } /* Do the filtering */ if (this->numFiltered < numFilter) this->numFiltered++; filter = (double *)this->pFilter->pData; O1 = oScale * (oc1 + oc2/this->numFiltered); O2 = oScale * (oc3 + oc4/this->numFiltered); F1 = fScale * (fc1 + fc2/this->numFiltered); F2 = fScale * (fc3 + fc4/this->numFiltered); for (i=0; i<nElements; i++) { newData = oOffset; if (O1) newData += O1 * filter[i]; if (O2) newData += O2 * data[i]; newFilter = fOffset; if (F1) newFilter += F1 * filter[i]; if (F2) newFilter += F2 * data[i]; data[i] = newData; filter[i] = newFilter; } if ((this->numFiltered != numFilter) && filterCallbacks) doCallbacks = 0; } if (doCallbacks) { /* Convert the array to the desired output data type */ if (this->pArrays[0]) this->pArrays[0]->release(); this->pNDArrayPool->convert(pScratch, &this->pArrays[0], (NDDataType_t)dataType); } if (autoOffsetScale && this->pArrays[0] != NULL) { this->pArrays[0]->getInfo(&arrayInfo); double maxScale = pow(2., arrayInfo.bytesPerElement*8) - 1; scale = maxScale /(maxValue-minValue); offset = -minValue; setDoubleParam (NDPluginProcessScale, scale); setDoubleParam (NDPluginProcessOffset, offset); setDoubleParam (NDPluginProcessLowClip, 0); setDoubleParam (NDPluginProcessHighClip, maxScale); setIntegerParam(NDPluginProcessEnableOffsetScale, 1); setIntegerParam(NDPluginProcessEnableLowClip, 1); setIntegerParam(NDPluginProcessEnableHighClip, 1); } doCallbacks: if (doCallbacks) { this->lock(); /* Get the attributes for this driver */ this->getAttributes(this->pArrays[0]->pAttributeList); /* Call any clients who have registered for NDArray callbacks */ this->unlock(); doCallbacksGenericPointer(this->pArrays[0], NDArrayData, 0); } if (pScratch) pScratch->release(); /* We must enter the loop and exit with the mutex locked */ this->lock(); setIntegerParam(NDPluginProcessNumFiltered, this->numFiltered); callParamCallbacks(); if (autoOffsetScale && this->pArrays[0] != NULL) { setIntegerParam(NDPluginProcessAutoOffsetScale, 0); callParamCallbacks(); } }
/** * writeInt32. Write asyn integer values. */ asynStatus ADSBIG::writeInt32(asynUser *pasynUser, epicsInt32 value) { asynStatus status = asynSuccess; int function = pasynUser->reason; int addr = 0; int adStatus = 0; PAR_ERROR cam_err = CE_NO_ERROR; MY_LOGICAL te_status = FALSE; double ccd_temp_set = 0; int minX = 0; int minY = 0; int sizeX = 0; int sizeY = 0; int binning = 0; const char *functionName = "ADSBIG::writeInt32"; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Entry.\n", functionName); //Read the frame sizes getIntegerParam(ADMinX, &minX); getIntegerParam(ADMinY, &minY); getIntegerParam(ADSizeX, &sizeX); getIntegerParam(ADSizeY, &sizeY); getIntegerParam(ADBinX, &binning); getIntegerParam(ADStatus, &adStatus); if (function == ADAcquire) { if ((value==1) && ((adStatus == ADStatusIdle) || (adStatus == ADStatusError) || (adStatus == ADStatusAborted))) { m_Acquiring = 1; m_aborted = false; setIntegerParam(ADStatus, ADStatusAcquire); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Start Event.\n", functionName); epicsEventSignal(this->m_startEvent); } if ((value==0) && ((adStatus != ADStatusIdle) && (adStatus != ADStatusError) && (adStatus != ADStatusAborted))) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Abort Exposure.\n", functionName); abortExposure(); } } else if (function == ADSBIGDarkFieldParam) { if (value == 1) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Setting Dark Field Mode.\n", functionName); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Setting Light Field Mode.\n", functionName); } } else if (function == ADSBIGReadoutModeParam) { p_Cam->SetReadoutMode(value); if (value == 0) { binning = 1; } else if (value == 1) { binning = 2; } else if (value == 2) { binning = 3; } //If we change the binning, reset the frame sizes. This forces //the frame sizes to be set after the binning mode. //The SubFrame sizes have the be set after we know the binning anyway. p_Cam->SetSubFrame(0, 0, m_CamWidth/binning, m_CamHeight/binning); setIntegerParam(ADMinX, 0); setIntegerParam(ADMinY, 0); setIntegerParam(ADSizeX, m_CamWidth/binning); setIntegerParam(ADSizeY, m_CamHeight/binning); setIntegerParam(ADBinX, binning); setIntegerParam(ADBinY, binning); } else if (function == ADSBIGTEStatusParam) { getDoubleParam(ADTemperature, &ccd_temp_set); if (value == 1) { te_status = TRUE; } else { te_status = FALSE; } if ((cam_err = p_Cam->SetTemperatureRegulation(te_status, ccd_temp_set)) != CE_NO_ERROR) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. CSBIGCam::SetTemperatureRegulation returned an error. %s\n", functionName, p_Cam->GetErrorString(cam_err).c_str()); status = asynError; } } else if (function == ADMinX) { if (value > ((m_CamWidth/binning) - 1)) { value = (m_CamWidth/binning) - 1; } if ((value + sizeX) > (m_CamWidth/binning)) { sizeX = m_CamWidth/binning - value; setIntegerParam(ADSizeX, sizeX); } } else if (function == ADMinY) { if (value > ((m_CamHeight/binning) - 1)) { value = (m_CamHeight/binning) - 1; } if ((value + sizeY) > (m_CamHeight/binning)) { sizeY = m_CamHeight/binning - value; setIntegerParam(ADSizeY, sizeY); } } else if (function == ADSizeX) { if ((minX + value) > (m_CamWidth/binning)) { value = m_CamWidth/binning - minX; } } else if (function == ADSizeY) { if ((minY + value) > (m_CamHeight/binning)) { value = m_CamHeight/binning - minY; } } if (status != asynSuccess) { callParamCallbacks(addr); return asynError; } status = (asynStatus) setIntegerParam(addr, function, value); if (status!=asynSuccess) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s Error Setting Parameter. Asyn addr: %d, asynUser->reason: %d, value: %d\n", functionName, addr, function, value); return(status); } //Do callbacks so higher layers see any changes callParamCallbacks(addr); return status; }
/** Polls the axis. * This function reads the motor position, the limit status, the home status, the moving status, * and the drive power-on status. * It calls setIntegerParam() and setDoubleParam() for each item that it polls, * and then calls callParamCallbacks() at the end. * \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */ asynStatus SMChydraAxis::poll(bool *moving) { int done; int driveOn; int lowLimit; int highLimit; int ignoreLowLimit; int ignoreHighLimit; int axisStatus=-1; double position=0.0; asynStatus comStatus; static const char *functionName = "SMChydraAxis::poll"; // Read the current motor position sprintf(pC_->outString_, "%i np", (axisNo_ + 1)); comStatus = pC_->writeReadController(); if (comStatus) goto skip; // The response string is a double position = atof( (char *) &pC_->inString_); setDoubleParam(pC_->motorPosition_, (position / axisRes_) ); setDoubleParam(pC_->motorEncoderPosition_, (position / axisRes_) ); // Read the status of this motor sprintf(pC_->outString_, "%i nst", (axisNo_ + 1)); comStatus = pC_->writeReadController(); if (comStatus) goto skip; // The response string is an int axisStatus = atoi( (char *) &pC_->inString_); // Check the moving bit done = !(axisStatus & 0x1); setIntegerParam(pC_->motorStatusDone_, done); setIntegerParam(pC_->motorStatusMoving_, !done); *moving = done ? false:true; // Read the commanded velocity and acceleration sprintf(pC_->outString_, "%i gnv", (axisNo_ + 1)); comStatus = pC_->writeReadController(); sprintf(pC_->outString_, "%i gna", (axisNo_ + 1)); comStatus = pC_->writeReadController(); // Check the limit bit (0x40) if (axisStatus & 0x40) { asynPrint(this->pasynUser_, ASYN_TRACEIO_DRIVER, "%s: axis %i limit indicator active.\n", functionName, (axisNo_ + 1)); // query limits? } // Check the e-stop bit (0x80) if (axisStatus & 0x80) { asynPrint(this->pasynUser_, ASYN_TRACEIO_DRIVER, "%s: axis %i emergency stopped.\n", functionName, (axisNo_ + 1)); } // Check the e-stop switch active bit (0x200) if (axisStatus & 0x200) { asynPrint(this->pasynUser_, ASYN_TRACEIO_DRIVER, "%s: axis %i emergency stop switch active.\n", functionName, (axisNo_ + 1)); setIntegerParam(pC_->motorStatusProblem_, 1); } else{ setIntegerParam(pC_->motorStatusProblem_, 0); } // Check the device busy bit (0x400) if (axisStatus & 0x400) { asynPrint(this->pasynUser_, ASYN_TRACE_ERROR, "%s: axis %i device is busy - move commands discarded.\n", functionName, (axisNo_ + 1)); } // Read the limit status // Note: calibration switch = low limit; range measure switch = high limit // also need to read the switch confiruation to see if limits are ignored" // Read switch confiruation // Bit 0: polarity (0 = NO, 1 = NC) // Bit 1: mask (0 = enabled, 1 = disabled) sprintf(pC_->outString_, "%i getsw", (axisNo_ + 1)); comStatus = pC_->writeReadController(); if (comStatus) goto skip; sscanf(pC_->inString_, "%i %i", &lowLimitConfig_, &highLimitConfig_); ignoreLowLimit = lowLimitConfig_ & 0x2; ignoreHighLimit = highLimitConfig_ & 0x2; // Read status of switches 0=inactive 1=active sprintf(pC_->outString_, "%i getswst", (axisNo_ + 1)); comStatus = pC_->writeReadController(); if (comStatus) goto skip; // The response string is of the form "0 0" sscanf(pC_->inString_, "%i %i", &lowLimit, &highLimit); // if (ignoreLowLimit) setIntegerParam(pC_->motorStatusLowLimit_, 0); else setIntegerParam(pC_->motorStatusLowLimit_, lowLimit); if (ignoreHighLimit) setIntegerParam(pC_->motorStatusHighLimit_, 0); else setIntegerParam(pC_->motorStatusHighLimit_, highLimit); /*setIntegerParam(pC_->motorStatusAtHome_, limit);*/ // Check the drive power bit (0x100) driveOn = (axisStatus & 0x100) ? 0 : 1; setIntegerParam(pC_->motorStatusPowerOn_, driveOn); setIntegerParam(pC_->motorStatusProblem_, 0); skip: setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0); callParamCallbacks(); return comStatus ? asynError : asynSuccess; }
asynStatus drvQuadEM::doDataCallbacks() { epicsFloat64 doubleData[QE_MAX_DATA]; epicsFloat64 *pIn, *pOut; int numAverage; int numAveraged; int sampleSize = sizeof(doubleData); int count; epicsTimeStamp now; epicsFloat64 timeStamp; int arrayCounter; int i, j; size_t dims[2]; NDArray *pArrayAll, *pArraySingle; static const char *functionName = "doDataCallbacks"; getIntegerParam(P_NumAverage, &numAverage); while (1) { numAveraged = epicsRingBytesUsedBytes(ringBuffer_) / sampleSize; if (numAverage > 0) { if (numAveraged < numAverage) break; numAveraged = numAverage; setIntegerParam(P_NumAveraged, numAveraged); } else { setIntegerParam(P_NumAveraged, numAveraged); if (numAveraged < 1) break; } dims[0] = QE_MAX_DATA; dims[1] = numAveraged; epicsTimeGetCurrent(&now); getIntegerParam(NDArrayCounter, &arrayCounter); arrayCounter++; setIntegerParam(NDArrayCounter, arrayCounter); pArrayAll = pNDArrayPool->alloc(2, dims, NDFloat64, 0, 0); pArrayAll->uniqueId = arrayCounter; timeStamp = now.secPastEpoch + now.nsec / 1.e9; pArrayAll->timeStamp = timeStamp; getAttributes(pArrayAll->pAttributeList); count = epicsRingBytesGet(ringBuffer_, (char *)pArrayAll->pData, numAveraged * sampleSize); if (count != numAveraged * sampleSize) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: ring read failed\n", driverName, functionName); return asynError; } ringCount_ -= numAveraged; unlock(); doCallbacksGenericPointer(pArrayAll, NDArrayData, QE_MAX_DATA); lock(); // Copy data to arrays for each type of data, do callbacks on that. dims[0] = numAveraged; for (i=0; i<QE_MAX_DATA; i++) { pArraySingle = pNDArrayPool->alloc(1, dims, NDFloat64, 0, 0); pArraySingle->uniqueId = arrayCounter; pArraySingle->timeStamp = timeStamp; getAttributes(pArraySingle->pAttributeList); pIn = (epicsFloat64 *)pArrayAll->pData; pOut = (epicsFloat64 *)pArraySingle->pData; for (j=0; j<numAveraged; j++) { pOut[j] = pIn[i]; pIn += QE_MAX_DATA; } unlock(); doCallbacksGenericPointer(pArraySingle, NDArrayData, i); lock(); pArraySingle->release(); } pArrayAll->release(); callParamCallbacks(); // We only loop once if numAverage==0 if (numAverage == 0) break; } setIntegerParam(P_RingOverflows, 0); callParamCallbacks(); return asynSuccess; }
/** Constructor for HDF5 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] 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. */ hdf5Driver::hdf5Driver (const char *portName, int maxBuffers, size_t maxMemory, int priority, int stackSize) : ADDriver(portName, 1, NUM_HDF5_PARAMS, maxBuffers, maxMemory, 0, 0, /* No interfaces beyond ADDriver.cpp */ ASYN_CANBLOCK, /* ASYN_CANBLOCK=1, ASYN_MULTIDEVICE=0 */ 1, /* autoConnect=1 */ priority, stackSize), mStartEventId(epicsEventCreate(epicsEventEmpty)), mStopEventId(epicsEventCreate(epicsEventEmpty)), mDatasetsCount(0), mpDatasets(NULL) { int status = asynSuccess; const char *functionName = "hdf5Driver"; if (!mStartEventId) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s epicsEventCreate failure for start event\n", driverName, functionName); return; } if (!mStopEventId) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s epicsEventCreate failure for stop event\n", driverName, functionName); return; } createParam(HDF5FilePathString, asynParamOctet, &HDF5FilePath); createParam(HDF5FileExistsString, asynParamInt32, &HDF5FileExists); createParam(HDF5DatasetsCountString, asynParamInt32, &HDF5DatasetsCount); createParam(HDF5FirstFrameString, asynParamInt32, &HDF5FirstFrame); createParam(HDF5LastFrameString, asynParamInt32, &HDF5LastFrame); createParam(HDF5TotalFramesString, asynParamInt32, &HDF5TotalFrames); createParam(HDF5CurrentFrameString, asynParamInt32, &HDF5CurrentFrame); createParam(HDF5AutoLoadFrameString, asynParamInt32, &HDF5AutoLoadFrame); createParam(HDF5LoopString, asynParamInt32, &HDF5Loop); status = asynSuccess; status |= setStringParam (HDF5FilePath, ""); status |= setIntegerParam(HDF5FileExists, 0); status |= setIntegerParam(HDF5FirstFrame, 0); status |= setIntegerParam(HDF5LastFrame, 0); status |= setIntegerParam(HDF5TotalFrames, 0); status |= setIntegerParam(HDF5CurrentFrame, 0); status |= setIntegerParam(HDF5AutoLoadFrame, 0); status |= setIntegerParam(HDF5Loop, 0); status |= setDoubleParam (ADAcquirePeriod, 0.02); callParamCallbacks(); if (status) { printf("%s: unable to set driver parameters\n", functionName); return; } /* Create the thread that updates the images */ status = (epicsThreadCreate("hdf5DrvTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)hdf5TaskC, this) == NULL); if (status) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s epicsThreadCreate failure for task\n", driverName, functionName); return; } }
/** This thread controls acquisition, reads image files to get the image data, * and does the callbacks to send it to higher layers */ void hdf5Driver::hdf5Task (void) { const char *functionName = "hdf5Task"; int status = asynSuccess; epicsTimeStamp startTime, endTime; int imageMode, currentFrame, colorMode; double acquirePeriod, elapsedTime, delay; this->lock(); for(;;) { int acquire; getIntegerParam(ADAcquire, &acquire); if (!acquire) { this->unlock(); // Wait for semaphore unlocked asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: waiting for acquire to start\n", driverName, functionName); status = epicsEventWait(this->mStartEventId); this->lock(); acquire = 1; setStringParam(ADStatusMessage, "Acquiring data"); setIntegerParam(ADNumImagesCounter, 0); } // Are there datasets loaded? if(!mDatasetsCount) { setStringParam(ADStatusMessage, "No datasets loaded"); goto error; } // Get acquisition parameters epicsTimeGetCurrent(&startTime); getIntegerParam(ADImageMode, &imageMode); getDoubleParam(ADAcquirePeriod, &acquirePeriod); getIntegerParam(HDF5CurrentFrame, ¤tFrame); setIntegerParam(ADStatus, ADStatusAcquire); callParamCallbacks(); // Get information to allocate NDArray size_t dims[2]; NDDataType_t dataType; if(getFrameInfo(currentFrame, dims, &dataType)) { setStringParam(ADStatusMessage, "Failed to get frame info"); goto error; } // Allocate NDArray NDArray *pImage; if(!(pImage = pNDArrayPool->alloc(2, dims, dataType, 0, NULL))) { setStringParam(ADStatusMessage, "Failed to allocate frame"); goto error; } // Copy data into NDArray if(getFrameData(currentFrame, pImage->pData)) { setStringParam(ADStatusMessage, "Failed to read frame data"); goto error; } // Set ColorMode colorMode = NDColorModeMono; pImage->pAttributeList->add("ColorMode", "Color mode", NDAttrInt32, &colorMode); // Call plugins callbacks int arrayCallbacks; getIntegerParam(NDArrayCallbacks, &arrayCallbacks); if (arrayCallbacks) { this->unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: calling imageData callback\n", driverName, functionName); doCallbacksGenericPointer(pImage, NDArrayData, 0); this->lock(); } pImage->release(); // Get the current parameters int lastFrame, imageCounter, numImages, numImagesCounter; getIntegerParam(HDF5LastFrame, &lastFrame); getIntegerParam(NDArrayCounter, &imageCounter); getIntegerParam(ADNumImages, &numImages); getIntegerParam(ADNumImagesCounter, &numImagesCounter); setIntegerParam(NDArrayCounter, ++imageCounter); setIntegerParam(ADNumImagesCounter, ++numImagesCounter); setIntegerParam(HDF5CurrentFrame, ++currentFrame); // Put the frame number and time stamp into the buffer pImage->uniqueId = imageCounter; pImage->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9; updateTimeStamp(&pImage->epicsTS); // Prepare loop if necessary int loop; getIntegerParam(HDF5Loop, &loop); if (loop && currentFrame > lastFrame) { getIntegerParam(HDF5FirstFrame, ¤tFrame); setIntegerParam(HDF5CurrentFrame, currentFrame); } // See if acquisition is done if (imageMode == ADImageSingle || currentFrame > lastFrame || (imageMode == ADImageMultiple && numImagesCounter >= numImages)) { // First do callback on ADStatus setStringParam(ADStatusMessage, "Waiting for acquisition"); setIntegerParam(ADStatus, ADStatusIdle); acquire = 0; setIntegerParam(ADAcquire, acquire); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: acquisition completed\n", driverName, functionName); } callParamCallbacks(); // Delay next acquisition and check if received STOP signal if(acquire) { epicsTimeGetCurrent(&endTime); elapsedTime = epicsTimeDiffInSeconds(&endTime, &startTime); delay = acquirePeriod - elapsedTime; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: delay=%f\n", driverName, functionName, delay); if(delay > 0.0) { // Set the status to waiting to indicate we are in the delay setIntegerParam(ADStatus, ADStatusWaiting); callParamCallbacks(); this->unlock(); status = epicsEventWaitWithTimeout(mStopEventId, delay); this->lock(); if (status == epicsEventWaitOK) { acquire = 0; if (imageMode == ADImageContinuous) setIntegerParam(ADStatus, ADStatusIdle); else setIntegerParam(ADStatus, ADStatusAborted); callParamCallbacks(); } } } continue; error: setIntegerParam(ADAcquire, 0); setIntegerParam(ADStatus, ADStatusError); callParamCallbacks(); continue; } }
asynStatus NDPluginAttribute::writeInt32(asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; asynStatus status = asynSuccess; int numTSPoints, currentTSPoint; int i; static const char *functionName = "NDPluginAttribute::writeInt32"; /* Set the parameter in the parameter library. */ status = (asynStatus) setIntegerParam(function, value); if (function == NDPluginAttributeReset) { getIntegerParam(NDPluginAttributeTSNumPoints, &numTSPoints); for (i=0; i<maxAttributes_; i++) { setDoubleParam(i, NDPluginAttributeVal, 0.0); setDoubleParam(i, NDPluginAttributeValSum, 0.0); // Clear the time series array memset(pTSArray_[i], 0, numTSPoints*sizeof(epicsFloat64)); doCallbacksFloat64Array(this->pTSArray_[i], numTSPoints, NDPluginAttributeTSArrayValue, i); callParamCallbacks(i); } setIntegerParam(NDPluginAttributeTSCurrentPoint, 0); } else if (function == NDPluginAttributeTSNumPoints) { for (i=0; i<maxAttributes_; i++) { free(pTSArray_[i]); pTSArray_[i] = static_cast<epicsFloat64 *>(calloc(value, sizeof(epicsFloat64))); } } else if (function == NDPluginAttributeTSControl) { switch (value) { case TSEraseStart: setIntegerParam(NDPluginAttributeTSCurrentPoint, 0); setIntegerParam(NDPluginAttributeTSAcquiring, 1); getIntegerParam(NDPluginAttributeTSNumPoints, &numTSPoints); for (i=0; i<maxAttributes_; i++) { memset(pTSArray_[i], 0, numTSPoints*sizeof(epicsFloat64)); } doTimeSeriesCallbacks(); break; case TSStart: getIntegerParam(NDPluginAttributeTSNumPoints, &numTSPoints); getIntegerParam(NDPluginAttributeTSCurrentPoint, ¤tTSPoint); if (currentTSPoint < numTSPoints) { setIntegerParam(NDPluginAttributeTSAcquiring, 1); } break; case TSStop: setIntegerParam(NDPluginAttributeTSAcquiring, 0); doTimeSeriesCallbacks(); break; case TSRead: doTimeSeriesCallbacks(); break; } } else { /* If this parameter belongs to a base class call its method */ if (function < FIRST_NDPLUGIN_ATTR_PARAM) status = NDPluginDriver::writeInt32(pasynUser, value); } /* Do callbacks so higher layers see any changes */ status = (asynStatus) callParamCallbacks(); if (status) epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s: status=%d, function=%d, value=%d", functionName, status, function, value); else asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s: function=%d, value=%d\n", functionName, function, value); return status; }
/** * \param[in] pArray The NDArray from the callback. */ void NDPluginAttribute::processCallbacks(NDArray *pArray) { /* * This function is called with the mutex already locked. It unlocks it during long calculations when private * structures don't need to be protected. */ int status = 0; int currentTSPoint; int numTSPoints; int TSAcquiring; double valueSum; int i; char attrName[MAX_ATTR_NAME_] = {0}; NDAttribute *pAttribute = NULL; NDAttributeList *pAttrList = NULL; epicsFloat64 attrValue = 0.0; static const char *functionName = "NDPluginAttribute::processCallbacks"; /* Call the base class method */ NDPluginDriver::beginProcessCallbacks(pArray); /* Get the attributes for this driver */ pAttrList = pArray->pAttributeList; getIntegerParam(NDPluginAttributeTSCurrentPoint, ¤tTSPoint); getIntegerParam(NDPluginAttributeTSNumPoints, &numTSPoints); getIntegerParam(NDPluginAttributeTSAcquiring, &TSAcquiring); for (i=0; i<maxAttributes_; i++) { getStringParam(i, NDPluginAttributeAttrName, MAX_ATTR_NAME_, attrName); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "Finding the attribute %s\n", attrName); if (strcmp(attrName, UNIQUE_ID_NAME_) == 0) { attrValue = (epicsFloat64) pArray->uniqueId; } else if (strcmp(attrName, TIMESTAMP_NAME_) == 0) { attrValue = pArray->timeStamp; } else if (strcmp(attrName, EPICS_TS_SEC_NAME_) == 0) { attrValue = (epicsFloat64)pArray->epicsTS.secPastEpoch; } else if (strcmp(attrName, EPICS_TS_NSEC_NAME_) == 0) { attrValue = (epicsFloat64)pArray->epicsTS.nsec; } else { pAttribute = pAttrList->find(attrName); if (pAttribute) { status = pAttribute->getValue(NDAttrFloat64, &attrValue); if (status != asynSuccess) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Error reading value for NDAttribute %s. \n", functionName, attrName); continue; } asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "Attribute %s value is %f\n", attrName, attrValue); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Error finding NDAttribute %s. \n", functionName, attrName); continue; } } setDoubleParam(i, NDPluginAttributeVal, attrValue); getDoubleParam(i, NDPluginAttributeValSum, &valueSum); valueSum += attrValue; setDoubleParam(i, NDPluginAttributeValSum, valueSum); if (TSAcquiring) { pTSArray_[i][currentTSPoint] = attrValue; } callParamCallbacks(i); } if (TSAcquiring) { currentTSPoint++; setIntegerParam(NDPluginAttributeTSCurrentPoint, currentTSPoint); if (currentTSPoint >= numTSPoints) { doTimeSeriesCallbacks(); setIntegerParam(NDPluginAttributeTSAcquiring, 0); } } }
/** Called when asyn clients call pasynInt32->write(). * This function performs actions for some parameters, including NDReadFile, NDWriteFile and NDFileCapture. * For other parameters it calls NDPluginDriver::writeInt32 to see if that method understands the parameter. * 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 NDPluginFile::writeInt32(asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; asynStatus status = asynSuccess; static const char* functionName = "writeInt32"; /* Set the parameter in the parameter library. */ status = (asynStatus) setIntegerParam(function, value); if (function == NDWriteFile) { if (value) { /* Call the callbacks so the status changes */ callParamCallbacks(); if (this->pArrays[0]) { status = writeFileBase(); } else { asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s::%s: ERROR, no valid array to write", driverName, functionName); status = asynError; } /* Set the flag back to 0, since this could be a busy record */ setIntegerParam(NDWriteFile, 0); } } else if (function == NDReadFile) { if (value) { /* Call the callbacks so the status changes */ callParamCallbacks(); status = readFileBase(); /* Set the flag back to 0, since this could be a busy record */ setIntegerParam(NDReadFile, 0); } } else if (function == NDFileCapture) { if (value) { // Started capture or stream // Reset the value temporarily until the doCapture() has called the // inherited openFile() method and the writer is in a good state to // start writing frames. // See comments on: https://github.com/areaDetector/ADCore/pull/100 setIntegerParam(NDFileCapture, 0); /* Latch the NDFileLazyOpen parameter so that we don't need to care * if the user modifies this parameter before first frame has arrived. */ int paramFileLazyOpen = 0; getIntegerParam(NDFileLazyOpen, ¶mFileLazyOpen); this->lazyOpen = (paramFileLazyOpen != 0); /* So far everything is OK, so we just clear the FileWriteStatus parameters */ setIntegerParam(NDFileWriteStatus, NDFileWriteOK); setStringParam(NDFileWriteMessage, ""); setStringParam(NDFullFileName, ""); } /* Must call doCapture if capturing was just started or stopped */ status = doCapture(value); if (status == asynSuccess) { if (this->lazyOpen) setStringParam(NDFileWriteMessage, "Lazy Open..."); setIntegerParam(NDFileCapture, value); } else { setIntegerParam(NDFileCapture, 0); } } else { /* This was not a parameter that this driver understands, try the base class */ status = NDPluginDriver::writeInt32(pasynUser, value); } /* Do callbacks so higher layers see any changes */ status = 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; }
/** Callback function that is called by the NDArray driver with new NDArray data. * Draws overlays on top of the array. * \param[in] pArray The NDArray from the callback. */ void NDPluginOverlay::processCallbacks(NDArray *pArray) { /* This function draws overlays * It is called with the mutex already locked. It unlocks it during long calculations when private * structures don't need to be protected. */ int use; int itemp; int overlay; NDArray *pOutput; //static const char* functionName = "processCallbacks"; /* Call the base class method */ NDPluginDriver::processCallbacks(pArray); /* We always keep the last array so read() can use it. * Release previous one. */ if (this->pArrays[0]) { this->pArrays[0]->release(); } /* Copy the input array so we can modify it. */ this->pArrays[0] = this->pNDArrayPool->copy(pArray, NULL, 1); pOutput = this->pArrays[0]; /* Get information about the array needed later */ pOutput->getInfo(&this->arrayInfo); setIntegerParam(NDPluginOverlayMaxSizeX, (int)arrayInfo.xSize); setIntegerParam(NDPluginOverlayMaxSizeY, (int)arrayInfo.ySize); /* Loop over the overlays in this driver */ for (overlay=0; overlay<this->maxOverlays; overlay++) { pOverlay = &this->pOverlays[overlay]; getIntegerParam(overlay, NDPluginOverlayUse, &use); asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "NDPluginOverlay::processCallbacks, overlay=%d, use=%d\n", overlay, use); if (!use) continue; /* Need to fetch all of these parameters while we still have the mutex */ getIntegerParam(overlay, NDPluginOverlayPositionX, &itemp); pOverlay->PositionX = itemp; pOverlay->PositionX = MAX(pOverlay->PositionX, 0); pOverlay->PositionX = MIN(pOverlay->PositionX, this->arrayInfo.xSize-1); getIntegerParam(overlay, NDPluginOverlayPositionY, &itemp); pOverlay->PositionY = itemp; pOverlay->PositionY = MAX(pOverlay->PositionY, 0); pOverlay->PositionY = MIN(pOverlay->PositionY, this->arrayInfo.ySize-1); getIntegerParam(overlay, NDPluginOverlaySizeX, &itemp); pOverlay->SizeX = itemp; getIntegerParam(overlay, NDPluginOverlaySizeY, &itemp); pOverlay->SizeY = itemp; getIntegerParam(overlay, NDPluginOverlayWidthX, &itemp); pOverlay->WidthX = itemp; getIntegerParam(overlay, NDPluginOverlayWidthY, &itemp); pOverlay->WidthY = itemp; getIntegerParam(overlay, NDPluginOverlayShape, &itemp); pOverlay->shape = (NDOverlayShape_t)itemp; getIntegerParam(overlay, NDPluginOverlayDrawMode, &itemp); pOverlay->drawMode = (NDOverlayDrawMode_t)itemp; getIntegerParam(overlay, NDPluginOverlayRed, &pOverlay->red); getIntegerParam(overlay, NDPluginOverlayGreen, &pOverlay->green); getIntegerParam(overlay, NDPluginOverlayBlue, &pOverlay->blue); getStringParam( overlay, NDPluginOverlayTimeStampFormat, sizeof(pOverlay->TimeStampFormat), pOverlay->TimeStampFormat); getIntegerParam(overlay, NDPluginOverlayFont, &pOverlay->Font); getStringParam( overlay, NDPluginOverlayDisplayText, sizeof(pOverlay->DisplayText), pOverlay->DisplayText); pOverlay->DisplayText[sizeof(pOverlay->DisplayText)-1] = 0; /* This function is called with the lock taken, and it must be set when we exit. * The following code can be exected without the mutex because we are not accessing memory * that other threads can access. */ this->unlock(); this->doOverlay(pOutput, pOverlay); this->lock(); } /* Get the attributes for this driver */ this->getAttributes(this->pArrays[0]->pAttributeList); /* Call any clients who have registered for NDArray callbacks */ this->unlock(); doCallbacksGenericPointer(this->pArrays[0], NDArrayData, 0); this->lock(); callParamCallbacks(); }
/** Base method for writing a file * Handles logic for NDFileModeSingle, NDFileModeCapture and NDFileModeStream when the derived class does or * does not support NDPulginFileMultiple. Calls writeFile in the derived class. */ asynStatus NDPluginFile::writeFileBase() { int status = asynSuccess; int fileWriteMode; int numCapture, numCaptured; int i; bool doLazyOpen; int deleteDriverFile; NDArray *pArray; NDAttribute *pAttribute; char driverFileName[MAX_FILENAME_LEN]; char errorMessage[256]; static const char* functionName = "writeFileBase"; /* Make sure there is a valid array */ if (!this->pArrays[0]) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s: ERROR, must collect an array to get dimensions first\n", driverName, functionName); return(asynError); } NDArray *pArrayOut = this->pArrays[0]; // Must increase reference count on this array because another thread might decrement the count on pArrays[0] // when we have the mutex unlocked pArrayOut->reserve(); getIntegerParam(NDFileWriteMode, &fileWriteMode); getIntegerParam(NDFileNumCapture, &numCapture); getIntegerParam(NDFileNumCaptured, &numCaptured); setIntegerParam(NDFileWriteStatus, NDFileWriteOK); setStringParam(NDFileWriteMessage, ""); /* We unlock the overall mutex here because we want the callbacks to be able to queue new * frames without waiting while we write files here. The only restriction is that the * callbacks must not modify any part of the class structure that we use here. */ switch(fileWriteMode) { case NDFileModeSingle: setIntegerParam(NDWriteFile, 1); callParamCallbacks(); // Some file writing plugins (e.g. HDF5) use the value of NDFileNumCaptured // even in single mode setIntegerParam(NDFileNumCaptured, 1); status = this->openFileBase(NDFileModeWrite, pArrayOut); if (status == asynSuccess) { this->unlock(); epicsMutexLock(this->fileMutexId); status = this->writeFile(pArrayOut); epicsMutexUnlock(this->fileMutexId); this->lock(); NDPluginDriver::endProcessCallbacks(pArrayOut, true, true); if (status) { epicsSnprintf(errorMessage, sizeof(errorMessage)-1, "Error writing file, status=%d", status); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s %s\n", driverName, functionName, errorMessage); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, errorMessage); } else { status = this->closeFileBase(); } } setIntegerParam(NDWriteFile, 0); callParamCallbacks(); break; case NDFileModeCapture: /* Write the file */ if (!this->pCapture) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s: ERROR, no capture buffer present\n", driverName, functionName); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, "ERROR, no capture buffer present"); break; } setIntegerParam(NDWriteFile, 1); callParamCallbacks(); if (this->supportsMultipleArrays) status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, pArrayOut); if (status == asynSuccess) { for (i=0; i<numCaptured; i++) { pArray = this->pCapture[i]; if (!this->supportsMultipleArrays) status = this->openFileBase(NDFileModeWrite, pArray); else this->attrFileNameCheck(); if (status == asynSuccess) { this->unlock(); epicsMutexLock(this->fileMutexId); status = this->writeFile(pArray); epicsMutexUnlock(this->fileMutexId); this->lock(); NDPluginDriver::endProcessCallbacks(pArray, true, true); if (status) { epicsSnprintf(errorMessage, sizeof(errorMessage)-1, "Error writing file, status=%d", status); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s %s\n", driverName, functionName, errorMessage); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, errorMessage); } else { if (!this->supportsMultipleArrays) status = this->closeFileBase(); } } } } freeCaptureBuffer(numCapture); if ((status == asynSuccess) && this->supportsMultipleArrays) status = this->closeFileBase(); this->registerInitFrameInfo(NULL); setIntegerParam(NDFileNumCaptured, 0); setIntegerParam(NDWriteFile, 0); callParamCallbacks(); break; case NDFileModeStream: doLazyOpen = this->lazyOpen && (numCaptured == 0); if (!this->supportsMultipleArrays || doLazyOpen) status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, pArrayOut); else this->attrFileNameCheck(); if (!this->isFrameValid(pArrayOut)) { setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, "Invalid frame. Ignoring."); status = asynError; } if (status == asynSuccess) { this->unlock(); epicsMutexLock(this->fileMutexId); status = this->writeFile(pArrayOut); epicsMutexUnlock(this->fileMutexId); this->lock(); NDPluginDriver::endProcessCallbacks(pArrayOut, true, true); if (status) { epicsSnprintf(errorMessage, sizeof(errorMessage)-1, "Error writing file, status=%d", status); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s %s\n", driverName, functionName, errorMessage); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, errorMessage); } else { status = this->attrFileCloseCheck(); if (!this->supportsMultipleArrays) status = this->closeFileBase(); } } break; default: asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s: ERROR, unknown fileWriteMode %d\n", driverName, functionName, fileWriteMode); break; } /* Check to see if we should delete the original file * Only do this if all of the following conditions are met * - DeleteOriginalFile is true * - There were no errors above * - The NDFullFileName attribute is present and contains a non-blank string */ getIntegerParam(NDFileDeleteDriverFile, &deleteDriverFile); if ((status == asynSuccess) && deleteDriverFile) { pAttribute = pArrayOut->pAttributeList->find("DriverFileName"); if (pAttribute) { status = pAttribute->getValue(NDAttrString, driverFileName, sizeof(driverFileName)); if ((status == asynSuccess) && (strlen(driverFileName) > 0)) { status = remove(driverFileName); if (status != 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s: error deleting file %s, error=%s\n", driverName, functionName, driverFileName, strerror(errno)); } } } } // Decrease reference count pArrayOut->release(); return (asynStatus) status; }
epicsInt32 mythen::dataCallback(epicsInt32 *pData) { NDArray *pImage; int ndims = 1; size_t dims[2]; int totalBytes; int arrayCallbacks; int imageCounter; epicsTimeStamp timeStamp; epicsInt32 colorMode = NDColorModeMono; // printf ("pData[0] = %X\n",pData[0]); if (pData == NULL || pData[0] < 0) return(0); dims[0] = MAX_DIMS; dims[1] = 1; totalBytes = this->nmodules*MAX_DIMS*sizeof(epicsInt32); /* Get the current time */ epicsTimeGetCurrent(&timeStamp); /* Allocate a new image buffer */ pImage = this->pNDArrayPool->alloc(ndims, dims, NDInt32, totalBytes, NULL); if (readmode_==0) decodeRawReadout(this->nmodules, this->nbits_, pData, (int *)pImage->pData); else decodeRawReadout(this->nmodules, 24, pData, (int *)pImage->pData); // memcpy(pImage->pData, pData, totalBytes); pImage->dataType = NDUInt32; pImage->ndims = ndims; pImage->dims[0].size = dims[0]; pImage->dims[0].offset = 0; pImage->dims[0].binning = 1; pImage->dims[1].size = dims[1]; pImage->dims[1].offset = 0; pImage->dims[1].binning = 1; pImage->pAttributeList->add("ColorMode", "Color Mode", NDAttrInt32, &colorMode); /* Increase image counter */ getIntegerParam(NDArrayCounter, &imageCounter); imageCounter++; setIntegerParam(NDArrayCounter, imageCounter); /* Set the uniqueId and time stamp */ pImage->uniqueId = imageCounter; pImage->timeStamp = timeStamp.secPastEpoch + timeStamp.nsec / 1e9; /* Get any attributes that have been defined for this driver */ this->getAttributes(pImage->pAttributeList); getIntegerParam(NDArrayCallbacks, &arrayCallbacks); if (arrayCallbacks) { /* 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(pImage, NDArrayData, 0); this->lock(); } /* We save the most recent good image buffer so it can be used in the * readADImage function. Now release it. */ if (this->pArrays[0]) this->pArrays[0]->release(); this->pArrays[0] = pImage; /* Update any changed parameters */ callParamCallbacks(); return(1); }
void mythen::acquisitionTask() { size_t nread, nread_expect; size_t nwrite; int eventStatus; int imageMode; epicsInt32 acquire, eomReason; double acquireTime; asynStatus status = asynSuccess; int dataOK; static const char *functionName = "acquisitionTask"; this->lock(); 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 || !acquiring_) { 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(); eventStatus = epicsEventWait(this->startEventId_); // setStringParam(ADStatusMessage, "Acquiring data"); // setIntegerParam(ADNumImagesCounter, 0); // getIntegerParam(ADAcquire, &acquire); //printf("Read Mode: %d\tnModules: %d\t chanperline: %d\n", readmode_,this->nmodules,chanperline_); if (readmode_==0) //Raw Mode nread_expect = sizeof(epicsInt32)*this->nmodules*(1280/chanperline_); else nread_expect = sizeof(epicsInt32)*this->nmodules*(1280); dataOK = 1; eventStatus = getStatus(); setIntegerParam(ADStatus, eventStatus); if (eventStatus!=ADStatusError) { getDoubleParam(ADAcquireTime,&acquireTime); // printf("Acquisition start - expect %d\n",nread_expect); // Work on the cases of what are you getting from getstatus do { nread=0; if (readmode_==0) strcpy(outString_, "-readoutraw"); else strcpy(outString_, "-readout"); status = pasynOctetSyncIO->writeRead(pasynUserMeter_, outString_, strlen(outString_), (char *)detArray_, nread_expect, M1K_TIMEOUT+acquireTime, &nwrite, &nread, &eomReason); //Timeout is M1K_TIMEOUT + AcquireTime //printf("nread_expected = %d\tnread = %d\n", nread_expect,nread); if(nread == nread_expect) { this->lock(); dataOK = dataCallback(detArray_); this->unlock(); if (!dataOK) { eventStatus = getStatus(); setIntegerParam(ADStatus, eventStatus); } } else { eventStatus = getStatus(); setIntegerParam(ADStatus, eventStatus); //printf("Data not size expected ADStatus: %d\n",eventStatus); } if(status != asynSuccess) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error using readout command status=%d, nRead=%d, eomReason=%d\n", driverName, functionName, status, (int)nread, eomReason); } } while (status == asynSuccess && (eventStatus==ADStatusAcquire||eventStatus==ADStatusReadout) && acquiring_); } this->lock(); } if (eventStatus!=ADStatusError ) { printf("Acquisition finish\n"); getIntegerParam(ADImageMode, &imageMode); if (imageMode == ADImageSingle || imageMode == ADImageMultiple) { printf("ADAcquire Callback\n"); acquiring_ = 0; setIntegerParam(ADAcquire, 0); callParamCallbacks(); } } else { //Abort read asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error timed out waiting for data\n", driverName, functionName); acquiring_ = 0; setAcquire(0); setIntegerParam(ADAcquire, 0); callParamCallbacks(); } } }
asynStatus isisdaeDriver::writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual) { int function = pasynUser->reason; asynStatus status = asynSuccess; const char *paramName = NULL; getParamName(function, ¶mName); const char* functionName = "writeOctet"; std::string value_s; // we might get an embedded NULL from channel access char waveform records if ( (maxChars > 0) && (value[maxChars-1] == '\0') ) { value_s.assign(value, maxChars-1); } else { value_s.assign(value, maxChars); } m_iface->resetMessages(); try { if (function == P_RunTitle) { m_iface->setRunTitle(value_s); } else if (function == P_SamplePar) { std::vector<std::string> tokens; boost::split(tokens, value_s, boost::is_any_of("\2")); // name, type, units, value if (tokens.size() == 4) { translateBeamlineType(tokens[1]); m_iface->setSampleParameter(tokens[0], tokens[1], tokens[2], tokens[3]); } else { throw std::runtime_error("SampleParameter: not enough tokens"); } } else if (function == P_BeamlinePar) { std::vector<std::string> tokens; boost::split(tokens, value_s, boost::is_any_of("\2")); // name, type, units, value if (tokens.size() == 4) { translateBeamlineType(tokens[1]); m_iface->setBeamlineParameter(tokens[0], tokens[1], tokens[2], tokens[3]); } else { throw std::runtime_error("BeamlineParameter: not enough tokens"); } } else if (function == P_RBNumber) { char user[256]; getStringParam(P_UserName, sizeof(user), user); m_iface->setUserParameters(atol(value_s.c_str()), user, "", ""); } else if (function == P_UserName) { char rbno[16]; getStringParam(P_RBNumber, sizeof(rbno), rbno); m_iface->setUserParameters(atol(rbno), value_s, "", ""); } else if (function == P_DAESettings) { m_iface->setDAESettingsXML(value_s); } else if (function == P_HardwarePeriodsSettings) { m_iface->setHardwarePeriodsSettingsXML(value_s); } else if (function == P_UpdateSettings) { m_iface->setUpdateSettingsXML(value_s); } else if (function == P_TCBSettings) { std::string tcb_xml; if (uncompressString(value_s, tcb_xml) == 0) { unsigned found = tcb_xml.find_last_of(">"); // in cased junk on end m_iface->setTCBSettingsXML(tcb_xml.substr(0,found+1)); } } else if (function == P_SnapshotCRPT) { beginStateTransition(RS_STORING); m_iface->snapshotCRPT(value_s, 1, 1); endStateTransition(); } reportMessages(); status = asynPortDriver::writeOctet(pasynUser, value_s.c_str(), value_s.size(), nActual); asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d, name=%s, value=%s\n", driverName, functionName, function, paramName, value_s.c_str()); if (status == asynSuccess) { *nActual = maxChars; // to keep result happy in case we skipped an embedded trailing NULL } return status; } catch(const std::exception& ex) { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s", driverName, functionName, status, function, paramName, value_s.c_str(), ex.what()); reportErrors(ex.what()); callParamCallbacks(); // this flushes P_ErrMsgs endStateTransition(); *nActual = 0; return asynError; } }
void ecAsyn::on_pdo_message(PDO_MESSAGE * pdo, int size) { lock(); char * meta = pdo->buffer + pdo->size + SLAVE_METADATA_CNT * devid; assert(meta + 1 - pdo->buffer < size); epicsInt32 slave_info = meta[0]; epicsInt32 al_state = meta[1]; epicsInt32 error_flag = meta[2]; epicsInt32 disable = pdo->wc_state != EC_WC_COMPLETE || al_state != EC_AL_STATE_OP || slave_info != 0; asynStatus paramStatus = asynSuccess; if (slave_info != 0) { paramStatus = asynDisconnected; } // perhaps set paramStatus to // asynDisabled if pdo->wc_state != EC_WC_COMPLETE setIntegerParam(P_SLAVEINFO, slave_info); setIntegerParam(P_AL_STATE, al_state); setParamStatus(P_AL_STATE, paramStatus); setIntegerParam(P_ERROR_FLAG, error_flag); setParamStatus(P_ERROR_FLAG, paramStatus); setIntegerParam(P_DISABLE, disable); setParamStatus(P_DISABLE, paramStatus); for(ELLNODE * node = ellFirst(&device->pdo_entry_mappings); node; node = ellNext(node)) { EC_PDO_ENTRY_MAPPING * mapping = (EC_PDO_ENTRY_MAPPING *)node; int mpdoe_param = mapping->pdo_entry->parameter; if (mapping->pdo_entry->datatype[0] == 'F') { double val = cast_double(mapping, pdo->buffer, 0); if (disable) { setDoubleParam(mpdoe_param, MINFLOAT); } else { setDoubleParam(mpdoe_param, val); } setParamStatus(mpdoe_param, paramStatus); } else { int32_t val = cast_int32(mapping, pdo->buffer, 0); // can't make SDIS work with I/O intr (some values get lost) // so using this for now if(disable) { setIntegerParam(mpdoe_param, INT32_MIN); } else { setIntegerParam(mpdoe_param, val); } setParamStatus(mpdoe_param, paramStatus); } } callParamCallbacks(); unlock(); }
void isisdaeDriver::pollerThread2() { static const char* functionName = "isisdaePoller2"; std::map<std::string, DAEValue> values; unsigned long counter = 0; double delay = 2.0; long this_rf = 0, this_gf = 0, last_rf = 0, last_gf = 0; bool check_settings; std::string daeSettings; std::string tcbSettings, tcbSettingComp; std::string hardwarePeriodsSettings; std::string updateSettings; std::string vetoStatus; lock(); while(true) { unlock(); epicsThreadSleep(delay); lock(); if (m_inStateTrans) // do nothing if in state transition { continue; } check_settings = ( (counter == 0) || (m_RunStatus == RS_SETUP && counter % 2 == 0) || (counter % 10 == 0) ); try { m_iface->getRunDataFromDAE(values); m_iface->getVetoStatus(vetoStatus); if (check_settings) { m_iface->getDAESettingsXML(daeSettings); m_iface->getTCBSettingsXML(tcbSettings); m_iface->getHardwarePeriodsSettingsXML(hardwarePeriodsSettings); m_iface->getUpdateSettingsXML(updateSettings); } this_gf = m_iface->getGoodFrames(); this_rf = m_iface->getRawFrames(); } catch(const std::exception& ex) { std::cerr << ex.what() << std::endl; continue; } if (this_rf > last_rf) { m_vetopc = 100.0 * (1.0 - static_cast<double>(this_gf - last_gf) / static_cast<double>(this_rf - last_rf)); } else { m_vetopc = 0.0; } last_rf = this_rf; last_gf = this_gf; setStringParam(P_RunTitle, values["RunTitle"]); setStringParam(P_RBNumber, values["RBNumber"]); const char* rn = values["RunNumber"]; setStringParam(P_RunNumber, rn); setIntegerParam(P_IRunNumber, atol(rn)); setStringParam(P_InstName, values["InstName"]); setStringParam(P_UserName, values["UserName"]); setStringParam(P_UserTelephone, values["UserTelephone"]); setStringParam(P_StartTime, values["StartTime"]); setDoubleParam(P_NPRatio, values["N/P Ratio"]); setStringParam(P_ISISCycle, values["ISISCycle"]); setStringParam(P_DAETimingSource, values["DAETimingSource"]); setStringParam(P_PeriodType, values["Period Type"]); setIntegerParam(P_RawFramesPeriod, values["RawFramesPeriod"]); setIntegerParam(P_GoodFramesPeriod, values["GoodFramesPeriod"]); setIntegerParam(P_RunDurationTotal, values["RunDurationTotal"]); setIntegerParam(P_RunDurationPeriod, values["RunDurationPeriod"]); setIntegerParam(P_NumTimeChannels, values["NumberOfTimeChannels"]); setIntegerParam(P_NumPeriods, values["NumberOfPeriods"]); setIntegerParam(P_DAEMemoryUsed, values["DAEMemoryUsed"]); setIntegerParam(P_Period, values["CurrentPeriod"]); setIntegerParam(P_NumSpectra, values["NumberOfSpectra"]); setIntegerParam(P_MonitorCounts, values["MonitorCounts"]); setIntegerParam(P_PeriodSequence, values["PeriodSequence"]); setIntegerParam(P_MonitorSpectrum, values["MonitorSpectrum"]); setDoubleParam(P_BeamCurrent, values["BeamCurrent"]); setDoubleParam(P_TotalUAmps, values["TotalUAmps"]); setDoubleParam(P_MonitorFrom, values["MonitorFrom"]); setDoubleParam(P_MonitorTo, values["MonitorTo"]); setDoubleParam(P_TotalDaeCounts, values["TotalDAECounts"]); setDoubleParam(P_CountRate, values["CountRate"]); setDoubleParam(P_EventModeFraction, values["EventModeCardFraction"]); setDoubleParam(P_VetoPC, m_vetopc); setStringParam(P_VetoStatus, vetoStatus.c_str() ); if (check_settings) { setStringParam(P_DAESettings, daeSettings.c_str()); if (compressString(tcbSettings, tcbSettingComp) == 0) { setStringParam(P_TCBSettings, tcbSettingComp.c_str()); } setStringParam(P_HardwarePeriodsSettings, hardwarePeriodsSettings.c_str() ); setStringParam(P_UpdateSettings, updateSettings.c_str() ); std::string val; getDAEXML(daeSettings, "/Cluster/String[Name='Wiring Table']/Val", val); setStringParam(P_wiringTableFile, val.c_str()); getDAEXML(daeSettings, "/Cluster/String[Name='Detector Table']/Val", val); setStringParam(P_detectorTableFile, val.c_str()); getDAEXML(daeSettings, "/Cluster/String[Name='Spectra Table']/Val", val); setStringParam(P_spectraTableFile, val.c_str()); getDAEXML(tcbSettings, "/Cluster/String[Name='Time Channel File']/Val", val); setStringParam(P_tcbFile, val.c_str()); getDAEXML(hardwarePeriodsSettings, "/Cluster/String[Name='Period File']/Val", val); setStringParam(P_periodsFile, val.c_str()); } std::list<std::string> messages; std::string all_msgs; m_iface->getAsyncMessages(messages); for(std::list<std::string>::const_iterator it=messages.begin(); it != messages.end(); ++it) { std::string mess_ts; isisdaeInterface::stripTimeStamp(it->c_str(), mess_ts); all_msgs.append(mess_ts); errlogSevPrintf(errlogInfo, "%s", mess_ts.c_str()); } if (all_msgs.size() > 0) { setStringParam(P_AllMsgs, all_msgs.c_str()); } messages.clear(); callParamCallbacks(); ++counter; } }
/** Constructor for NDPluginDLL; most parameters are simply passed to NDPluginDriver::NDPluginDriver. * After calling the base class constructor this method sets reasonable default values for all of the * Transform parameters. * \param[in] portName The name of the asyn port driver to be created. * \param[in] queueSize The number of NDArrays that the input queue for this plugin can hold when * NDPluginDriverBlockingCallbacks=0. Larger queues can decrease the number of dropped arrays, * at the expense of more NDArray buffers being allocated from the underlying driver's NDArrayPool. * \param[in] blockingCallbacks Initial setting for the NDPluginDriverBlockingCallbacks flag. * 0=callbacks are queued and executed by the callback thread; 1 callbacks execute in the thread * of the driver doing the callbacks. * \param[in] NDArrayPort Name of asyn port driver for initial source of NDArray callbacks. * \param[in] NDArrayAddr asyn port driver address for initial source of NDArray callbacks. * \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. */ NDPluginDLL::NDPluginDLL(const char *portName, int queueSize, int blockingCallbacks, const char *NDArrayPort, int NDArrayAddr, int maxBuffers, size_t maxMemory, int priority, int stackSize) /* Invoke the base class constructor */ : NDPluginDriver(portName, queueSize, blockingCallbacks, NDArrayPort, NDArrayAddr, 1, 1024, maxBuffers, maxMemory, asynInt32ArrayMask | asynFloat64ArrayMask | asynGenericPointerMask, asynInt32ArrayMask | asynFloat64ArrayMask | asynGenericPointerMask, ASYN_MULTIDEVICE, 1, priority, stackSize) { asynStatus status; const char *functionName = "NDPluginDLL"; int ii, jj; int dims[2]; HMODULE hMod; OBJMAKER makeControllerObjects; int gg; int_string *params; // map the params from asyn assign param to the enumerated param in the dll. mapAsyn2DLL = new std::map<int,int>; mapDLL2Asyn = new std::map<int,int>; dims[0] =1024; dims[1] = 1024; this->pRaw = this->pNDArrayPool->alloc(2, dims, NDUInt16, 0, NULL); printf("Made NDArray, X = %i Y = %i Type = %i \n",1024, 1024,3); printf("Image data pointer = %i \n", (long)(pRaw->pData)); hMod = LoadLibrary (dll_name); if (NULL == hMod) { printf("Load DLL failed\n"); exit(0); } makeControllerObjects = (OBJMAKER) GetProcAddress (hMod, "makeControllerObjects"); if (NULL == makeControllerObjects) { long erx=GetLastError(); printf("Cannot get Proc Address. Error= %i\n",erx); } makeControllerObjects( (int*)&num_controllers, (genCamController*)controllers, (void*)madSimCallback, &(this->pRaw->pData)); printf("Controllers Found: %i \n",num_controllers); madSimPtr=this; // start threads per object // for (int k = 0; k<num_controllers; k++) // { // Sleep(2000); // madSimCallback(genCamControllerEnum::make_new_thread,controllers[k]); // } // // get param lists from the DLL and make all params. // int asyn_param; int enum_param; int ptype; int nparam; for (int k = 0; k<num_controllers; k++) { params=controllers[k]->getCompleteParamIntStrArray(); nparam=controllers[k]->getTotalNumParams(); for (int pp=0;pp<nparam;pp++) { if (pp==12) trapHere(); enum_param=params[pp].x; ptype= controllers[k]->getParamType(enum_param); switch(ptype) { case putGetParameters::paramInt: createParam(params[pp].str,asynParamInt32,&asyn_param); (*mapAsyn2DLL)[asyn_param] = params[pp].x; (*mapDLL2Asyn)[params[pp].x] = asyn_param; break; case putGetParameters::paramDouble: createParam(params[pp].str,asynParamFloat64,&asyn_param); (*mapAsyn2DLL)[asyn_param] = params[pp].x; (*mapDLL2Asyn)[params[pp].x] = asyn_param; break; case putGetParameters::paramString: createParam(params[pp].str,asynParamOctet,&asyn_param); (*mapAsyn2DLL)[asyn_param] = params[pp].x; (*mapDLL2Asyn)[params[pp].x] = asyn_param; break; case putGetParameters::paramPtr: createParam(params[pp].str,asynParamInt32,&asyn_param); (*mapAsyn2DLL)[asyn_param] = params[pp].x; (*mapDLL2Asyn)[params[pp].x] = asyn_param; break; default: printf("ERROR: NDPluginDLL::NDPluginDLL: Create Undef Param\n"); break; } } // copy ALL parameters from detector to this local Area Detector object //so EPICS can relect what detector is doing. lock(); copyParamsFromDet(0); callParamCallbacks(); unlock(); } // createParam(NDPluginDLLNameString, asynParamOctet, &NDPluginDLLName); // createParam(NDPluginDLL1TypeString, asynParamInt32, &NDPluginDLL1Type); /* Set the plugin type string */ // setStringParam(NDPluginDriverPluginType, "NDPluginDLL"); // setStringParam(NDPluginDLLName, ""); // setIntegerParam(NDPluginDLL1Type, 0); NDArrayDataPub=NDArrayData; /* Try to connect to the array port */ status = connectToArrayPort(); }
/** 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 hdf5Driver::writeInt32 (asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; asynStatus status = asynSuccess; const char *functionName = "writeInt32"; int adstatus, acquiring, imageMode; getIntegerParam(ADAcquire, &acquiring); getIntegerParam(ADStatus, &adstatus); getIntegerParam(ADImageMode, &imageMode); if (function == ADAcquire) { if (value && !acquiring) { setStringParam(ADStatusMessage, "Acquiring data"); setIntegerParam(ADStatus, ADStatusAcquire); callParamCallbacks(); epicsEventSignal(this->mStartEventId); } else if (!value && acquiring) { setStringParam(ADStatusMessage, "Acquisition stopped"); if(imageMode == ADImageContinuous) setIntegerParam(ADStatus, ADStatusIdle); else setIntegerParam(ADStatus, ADStatusAborted); callParamCallbacks(); epicsEventSignal(this->mStopEventId); } } else if(function == HDF5CurrentFrame) { int first, last; getIntegerParam(HDF5FirstFrame, &first); getIntegerParam(HDF5LastFrame, &last); if(value < first) value = first; else if(value > last) value = last; } else if(function < FIRST_HDF5_PARAM) status = ADDriver::writeInt32(pasynUser, value); if(status) { asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:%s: error, status=%d function=%d, value=%d\n", driverName, functionName, status, function, value); return status; } status = setIntegerParam(function, value); 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; }
/** Constructor for the shamrock class * \param[in] portName asyn port name to assign to the camera. * \param[in] shamrockID The spectrograph index. * \param[in] iniPath The path to the camera ini file * \param[in] priority The EPICS thread priority for this driver. 0=use asyn default. * \param[in] stackSize The size of the stack for the EPICS port thread. 0=use asyn default. */ shamrock::shamrock(const char *portName, int shamrockID, const char *iniPath, int priority, int stackSize) : asynPortDriver(portName, MAX_ADDR, NUM_SR_PARAMS, asynInt32Mask | asynFloat64Mask | asynFloat32ArrayMask | asynDrvUserMask, asynInt32Mask | asynFloat64Mask | asynFloat32ArrayMask, ASYN_CANBLOCK | ASYN_MULTIDEVICE, 1, priority, stackSize), shamrockId_(shamrockID) { static const char *functionName = "shamrock"; int status; int error; float minWavelength, maxWavelength; int numDevices; int numGratings; float pixelWidth; int i; createParam(SRWavelengthString, asynParamFloat64, &SRWavelength_); createParam(SRMinWavelengthString, asynParamFloat64, &SRMinWavelength_); createParam(SRMaxWavelengthString, asynParamFloat64, &SRMaxWavelength_); createParam(SRCalibrationString, asynParamFloat32Array, &SRCalibration_); createParam(SRGratingString, asynParamInt32, &SRGrating_); createParam(SRNumGratingsString, asynParamInt32, &SRNumGratings_); createParam(SRGratingExistsString, asynParamInt32, &SRGratingExists_); createParam(SRSlitExistsString, asynParamInt32, &SRSlitExists_); createParam(SRSlitSizeString, asynParamFloat64, &SRSlitSize_); error = ShamrockInitialize((char *)iniPath); status = checkError(error, functionName, "ShamrockInitialize"); if (status) return; error = ShamrockGetNumberDevices(&numDevices); status = checkError(error, functionName, "ShamrockGetNumberDevices"); if (status) return; if (numDevices < 1) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: No Shamrock spectrographs found, numDevices=%d\n", driverName, functionName, numDevices); return; } // Determine the number of pixels on the attached CCD and the pixel size error = ShamrockGetNumberPixels(shamrockId_, &numPixels_); status = checkError(error, functionName, "ShamrockGetNumberPixels"); error = ShamrockGetPixelWidth(shamrockId_, &pixelWidth); status = checkError(error, functionName, "ShamrockGetPixelWidth"); calibration_ = (float *)calloc(numPixels_, sizeof(float)); // Determine which slits are present for (i=0; i<MAX_SLITS; i++) { int present; error = ShamrockAutoSlitIsPresent(shamrockId_, i+1, &present); status = checkError(error, functionName, "ShamrockAutoSlitIsPresent"); slitIsPresent_[i] = (present == 1); setIntegerParam(i, SRSlitExists_, slitIsPresent_[i]); } // Determine how many gratings are present error = ShamrockGetNumberGratings(shamrockId_, &numGratings); status = checkError(error, functionName, "ShamrockGetNumberGratings"); setIntegerParam(SRNumGratings_, numGratings); // Get wavelength range of each grating for (i=1; i<=numGratings; i++) { setIntegerParam(i, SRGratingExists_, 1); error = ShamrockGetWavelengthLimits(shamrockId_, i, &minWavelength, &maxWavelength); status = checkError(error, functionName, "ShamrockGetWavelengthLimits"); setDoubleParam(i, SRMinWavelength_, minWavelength); setDoubleParam(i, SRMaxWavelength_, maxWavelength); } for (i=numGratings; i<MAX_GRATINGS; i++) { setIntegerParam(i, SRGratingExists_, 0); } getStatus(); for (i=0; i<MAX_ADDR; i++) { callParamCallbacks(i); } return; }
asynStatus hdf5Driver::openFile (const char *path) { asynStatus status = asynSuccess; const char *functionName = "loadFile"; hid_t fileId, groupId; H5G_info_t groupInfo; size_t totalFrames = 0; size_t maxWidth = 0, maxHeight = 0; // Reset some parameters setIntegerParam(HDF5DatasetsCount, 0); setIntegerParam(HDF5TotalFrames, 0); setIntegerParam(HDF5FirstFrame, 0); setIntegerParam(HDF5LastFrame, 0); setIntegerParam(HDF5CurrentFrame, 0); setIntegerParam(ADMaxSizeX, 0); setIntegerParam(ADMaxSizeY, 0); callParamCallbacks(); // Get a file handle if((fileId = H5Fopen(path, H5F_ACC_RDONLY, H5P_DEFAULT)) < 0) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s couldn't open file '%s'\n", driverName, functionName, path); status = asynError; goto end; } // Get a handle to the '/entry' group if((groupId = H5Gopen2(fileId, "/entry", H5P_DEFAULT)) < 0) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s couldn't open 'entry' group\n", driverName, functionName); status = asynError; goto closeFile; } // Need groupInfo to obtain number of links if(H5Gget_info(groupId, &groupInfo)) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s couldn't get group info\n", driverName, functionName); status = asynError; goto closeGroup; } // Deallocate information of previous file if(mpDatasets) { for(size_t i = 0; i < mDatasetsCount; ++i) H5Dclose(mpDatasets[i].id); free(mpDatasets); } // Allocate memory to store dataset information mpDatasets = (struct dsetInfo*) calloc(groupInfo.nlinks, sizeof(*mpDatasets)); mDatasetsCount = 0; // Iterate over '/entry' objects for(size_t i = 0; i < groupInfo.nlinks; ++i) { // Get object name char dsetName[256]; H5Lget_name_by_idx(groupId, ".", H5_INDEX_NAME, H5_ITER_INC, i, dsetName, sizeof(dsetName), H5P_DEFAULT); // If it doesn't start with 'data' it isn't a dataset. Ignore it. if(strncmp(dsetName, "data", 4)) continue; // Get a handle to the dataset info structure struct dsetInfo *pDSet = &mpDatasets[mDatasetsCount++]; pDSet->id = H5Dopen2(groupId, dsetName, H5P_DEFAULT); // Read dataset attributes H5LTget_attribute_int(pDSet->id, ".", "image_nr_low", &pDSet->imageNrLow); H5LTget_attribute_int(pDSet->id, ".", "image_nr_high", &pDSet->imageNrHigh); // Read dimensions (assume a 3D dataset) hsize_t dims[3] = {0,0,0}; H5LTget_dataset_info(pDSet->id, ".", dims, NULL, NULL); totalFrames += dims[0]; pDSet->height = dims[1]; pDSet->width = dims[2]; // Calculate maxHeight and maxWidth if(dims[1] > maxHeight) maxHeight = dims[1]; if(dims[2] > maxWidth) maxWidth = dims[2]; // Read type if(parseType(pDSet->id, &pDSet->type)) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s couldn't parse dataset type\n", driverName, functionName); status = asynError; } } // Update parameters setIntegerParam(HDF5DatasetsCount, (int) mDatasetsCount); setIntegerParam(HDF5TotalFrames, (int) totalFrames); if(mDatasetsCount > 0) { int firstFrame = mpDatasets[0].imageNrLow; int lastFrame = mpDatasets[mDatasetsCount-1].imageNrHigh; setIntegerParam(HDF5FirstFrame, firstFrame); setIntegerParam(HDF5LastFrame, lastFrame); setIntegerParam(HDF5CurrentFrame, firstFrame); setIntegerParam(ADMaxSizeX, maxWidth); setIntegerParam(ADMaxSizeY, maxHeight); int autoLoad; getIntegerParam(HDF5AutoLoadFrame, &autoLoad); if(autoLoad) { setIntegerParam(ADImageMode, ADImageSingle); setIntegerParam(ADNumImages, 1); setIntegerParam(ADAcquire, 1); epicsEventSignal(mStartEventId); } } callParamCallbacks(); closeGroup: H5Gclose(groupId); closeFile: H5Fclose(fileId); end: return status; }
/** Callback function that is called by the NDArray driver with new NDArray data. * Does image statistics. * \param[in] pArray The NDArray from the callback. */ void NDPluginStats::processCallbacks(NDArray *pArray) { /* This function does array statistics. * It is called with the mutex already locked. It unlocks it during long calculations when private * structures don't need to be protected. */ NDDimension_t bgdDims[ND_ARRAY_MAX_DIMS], *pDim; size_t bgdPixels; int bgdWidth; int dim; NDStats_t stats, *pStats=&stats, statsTemp, *pStatsTemp=&statsTemp; double bgdCounts, avgBgd; NDArray *pBgdArray=NULL; int computeStatistics, computeCentroid, computeProfiles, computeHistogram; size_t sizeX=0, sizeY=0; int i; int itemp; int numTSPoints, currentTSPoint, TSAcquiring; NDArrayInfo arrayInfo; const char* functionName = "processCallbacks"; /* Call the base class method */ NDPluginDriver::processCallbacks(pArray); pArray->getInfo(&arrayInfo); getIntegerParam(NDPluginStatsComputeStatistics, &computeStatistics); getIntegerParam(NDPluginStatsComputeCentroid, &computeCentroid); getIntegerParam(NDPluginStatsComputeProfiles, &computeProfiles); getIntegerParam(NDPluginStatsComputeHistogram, &computeHistogram); if (pArray->ndims > 0) sizeX = pArray->dims[0].size; if (pArray->ndims == 1) sizeY = 1; if (pArray->ndims > 1) sizeY = pArray->dims[1].size; if (sizeX != this->profileSizeX) { this->profileSizeX = sizeX; setIntegerParam(NDPluginStatsProfileSizeX, (int)this->profileSizeX); for (i=0; i<MAX_PROFILE_TYPES; i++) { if (this->profileX[i]) free(this->profileX[i]); this->profileX[i] = (double *)malloc(this->profileSizeX * sizeof(double)); } } if (sizeY != this->profileSizeY) { this->profileSizeY = sizeY; setIntegerParam(NDPluginStatsProfileSizeY, (int)this->profileSizeY); for (i=0; i<MAX_PROFILE_TYPES; i++) { if (this->profileY[i]) free(this->profileY[i]); this->profileY[i] = (double *)malloc(this->profileSizeY * sizeof(double)); } } if (computeStatistics) { getIntegerParam(NDPluginStatsBgdWidth, &bgdWidth); doComputeStatistics(pArray, pStats); /* If there is a non-zero background width then compute the background counts */ if (bgdWidth > 0) { bgdPixels = 0; bgdCounts = 0.; /* Initialize the dimensions of the background array */ for (dim=0; dim<pArray->ndims; dim++) { pArray->initDimension(&bgdDims[dim], pArray->dims[dim].size); } for (dim=0; dim<pArray->ndims; dim++) { pDim = &bgdDims[dim]; pDim->offset = 0; pDim->size = MIN((size_t)bgdWidth, pDim->size); this->pNDArrayPool->convert(pArray, &pBgdArray, pArray->dataType, bgdDims); pDim->size = pArray->dims[dim].size; if (!pBgdArray) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, error allocating array buffer in convert\n", driverName, functionName); continue; } doComputeStatistics(pBgdArray, pStatsTemp); pBgdArray->release(); bgdPixels += pStatsTemp->nElements; bgdCounts += pStatsTemp->total; pDim->offset = MAX(0, pDim->size - 1 - bgdWidth); pDim->size = MIN((size_t)bgdWidth, pArray->dims[dim].size - pDim->offset); this->pNDArrayPool->convert(pArray, &pBgdArray, pArray->dataType, bgdDims); pDim->offset = 0; pDim->size = pArray->dims[dim].size; if (!pBgdArray) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s, error allocating array buffer in convert\n", driverName, functionName); continue; } doComputeStatistics(pBgdArray, pStatsTemp); pBgdArray->release(); bgdPixels += pStatsTemp->nElements; bgdCounts += pStatsTemp->total; } if (bgdPixels < 1) bgdPixels = 1; avgBgd = bgdCounts / bgdPixels; pStats->net = pStats->total - avgBgd*pStats->nElements; } setDoubleParam(NDPluginStatsMinValue, pStats->min); setDoubleParam(NDPluginStatsMinX, (double)pStats->minX); setDoubleParam(NDPluginStatsMinY, (double)pStats->minY); setDoubleParam(NDPluginStatsMaxValue, pStats->max); setDoubleParam(NDPluginStatsMaxX, (double)pStats->maxX); setDoubleParam(NDPluginStatsMaxY, (double)pStats->maxY); setDoubleParam(NDPluginStatsMeanValue, pStats->mean); setDoubleParam(NDPluginStatsSigmaValue, pStats->sigma); setDoubleParam(NDPluginStatsTotal, pStats->total); setDoubleParam(NDPluginStatsNet, pStats->net); asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER, (char *)pArray->pData, arrayInfo.totalBytes, "%s:%s min=%f, max=%f, mean=%f, total=%f, net=%f", driverName, functionName, pStats->min, pStats->max, pStats->mean, pStats->total, pStats->net); } if (computeCentroid) { doComputeCentroid(pArray); setDoubleParam(NDPluginStatsCentroidX, this->centroidX); setDoubleParam(NDPluginStatsCentroidY, this->centroidY); setDoubleParam(NDPluginStatsSigmaX, this->sigmaX); setDoubleParam(NDPluginStatsSigmaY, this->sigmaY); setDoubleParam(NDPluginStatsSigmaXY, this->sigmaXY); } if (computeProfiles) { doComputeProfiles(pArray); } if (computeHistogram) { getIntegerParam(NDPluginStatsHistSize, &itemp); this->histSizeNew = itemp; getDoubleParam (NDPluginStatsHistMin, &this->histMin); getDoubleParam (NDPluginStatsHistMax, &this->histMax); doComputeHistogram(pArray); setDoubleParam(NDPluginStatsHistEntropy, this->histEntropy); doCallbacksFloat64Array(this->histogram, this->histogramSize, NDPluginStatsHistArray, 0); } getIntegerParam(NDPluginStatsTSCurrentPoint, ¤tTSPoint); getIntegerParam(NDPluginStatsTSNumPoints, &numTSPoints); getIntegerParam(NDPluginStatsTSAcquiring, &TSAcquiring); if (TSAcquiring) { timeSeries[TSMinValue][currentTSPoint] = pStats->min; timeSeries[TSMinX][currentTSPoint] = (double)pStats->minX; timeSeries[TSMinY][currentTSPoint] = (double)pStats->minY; timeSeries[TSMaxValue][currentTSPoint] = pStats->max; timeSeries[TSMaxX][currentTSPoint] = (double)pStats->maxX; timeSeries[TSMaxY][currentTSPoint] = (double)pStats->maxY; timeSeries[TSMeanValue][currentTSPoint] = pStats->mean; timeSeries[TSSigmaValue][currentTSPoint] = pStats->sigma; timeSeries[TSTotal][currentTSPoint] = pStats->total; timeSeries[TSNet][currentTSPoint] = pStats->net; timeSeries[TSCentroidX][currentTSPoint] = this->centroidX; timeSeries[TSCentroidY][currentTSPoint] = this->centroidY; timeSeries[TSSigmaX][currentTSPoint] = this->sigmaX; timeSeries[TSSigmaY][currentTSPoint] = this->sigmaY; timeSeries[TSSigmaXY][currentTSPoint] = this->sigmaXY; currentTSPoint++; setIntegerParam(NDPluginStatsTSCurrentPoint, currentTSPoint); if (currentTSPoint >= numTSPoints) { setIntegerParam(NDPluginStatsTSAcquiring, 0); doTimeSeriesCallbacks(); } } /* Save a copy of this array for calculations when cursor is moved or threshold is changed */ if (this->pArrays[0]) this->pArrays[0]->release(); this->pArrays[0] = this->pNDArrayPool->copy(pArray, NULL, 1); callParamCallbacks(); }
/** This function computes the sums, diffs and positions, and does callbacks * \param[in] raw Array of raw current readings */ void drvQuadEM::computePositions(epicsFloat64 raw[QE_MAX_INPUTS]) { int i; int count; int numAverage; int ringOverflows; int geometry; epicsFloat64 currentOffset[QE_MAX_INPUTS]; epicsFloat64 currentScale[QE_MAX_INPUTS]; epicsFloat64 positionOffset[2]; epicsFloat64 positionScale[2]; epicsInt32 intData[QE_MAX_DATA]; epicsFloat64 doubleData[QE_MAX_DATA]; epicsFloat64 denom; static const char *functionName = "computePositions"; getIntegerParam(P_Geometry, &geometry); // If the ring buffer is full then remove the oldest entry if (epicsRingBytesFreeBytes(ringBuffer_) < (int)sizeof(doubleData)) { count = epicsRingBytesGet(ringBuffer_, (char *)&doubleData, sizeof(doubleData)); ringCount_--; getIntegerParam(P_RingOverflows, &ringOverflows); ringOverflows++; setIntegerParam(P_RingOverflows, ringOverflows); } for (i=0; i<QE_MAX_INPUTS; i++) { getDoubleParam(i, P_CurrentOffset, ¤tOffset[i]); getDoubleParam(i, P_CurrentScale, ¤tScale[i]); doubleData[i] = raw[i]*currentScale[i] - currentOffset[i]; } for (i=0; i<2; i++) { getDoubleParam(i, P_PositionOffset, &positionOffset[i]); getDoubleParam(i, P_PositionScale, &positionScale[i]); } doubleData[QESumAll] = doubleData[QECurrent1] + doubleData[QECurrent2] + doubleData[QECurrent3] + doubleData[QECurrent4]; if (geometry == QEGeometrySquare) { doubleData[QESumX] = doubleData[QESumAll]; doubleData[QESumY] = doubleData[QESumAll]; doubleData[QEDiffX] = (doubleData[QECurrent2] + doubleData[QECurrent3]) - (doubleData[QECurrent1] + doubleData[QECurrent4]); doubleData[QEDiffY] = (doubleData[QECurrent1] + doubleData[QECurrent2]) - (doubleData[QECurrent3] + doubleData[QECurrent4]); } else { doubleData[QESumX] = doubleData[QECurrent1] + doubleData[QECurrent2]; doubleData[QESumY] = doubleData[QECurrent3] + doubleData[QECurrent4]; doubleData[QEDiffX] = doubleData[QECurrent2] - doubleData[QECurrent1]; doubleData[QEDiffY] = doubleData[QECurrent4] - doubleData[QECurrent3]; } denom = doubleData[QESumX]; if (denom == 0.) denom = 1.; doubleData[QEPositionX] = (positionScale[0] * doubleData[QEDiffX] / denom) - positionOffset[0]; denom = doubleData[QESumY]; if (denom == 0.) denom = 1.; doubleData[QEPositionY] = (positionScale[1] * doubleData[QEDiffY] / denom) - positionOffset[1]; count = epicsRingBytesPut(ringBuffer_, (char *)&doubleData, sizeof(doubleData)); ringCount_++; if (count != sizeof(doubleData)) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error writing ring buffer, count=%d, should be %d\n", driverName, functionName, count, (int)sizeof(doubleData)); } getIntegerParam(P_NumAverage, &numAverage); if (numAverage > 0) { if (ringCount_ >= numAverage) { triggerCallbacks(); } } for (i=0; i<QE_MAX_DATA; i++) { intData[i] = (epicsInt32)doubleData[i]; setDoubleParam(i, P_DoubleData, doubleData[i]); callParamCallbacks(i); } doCallbacksInt32Array(intData, QE_MAX_DATA, P_IntArrayData, 0); }
/** Called when asyn clients call pasynInt32->write(). * This function performs actions for some parameters. * 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 NDPluginStats::writeInt32(asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; asynStatus status = asynSuccess; int i; int numPoints, currentPoint; static const char *functionName = "writeInt32"; /* Set the parameter in the parameter library. */ status = (asynStatus) setIntegerParam(function, value); if (function == NDPluginStatsCursorX) { this->cursorX = value; if (this->pArrays[0]) { doComputeProfiles(this->pArrays[0]); } } else if (function == NDPluginStatsCursorY) { this->cursorY = value; if (this->pArrays[0]) { doComputeProfiles(this->pArrays[0]); } } else if (function == NDPluginStatsTSNumPoints) { for (i=0; i<MAX_TIME_SERIES_TYPES; i++) { free(this->timeSeries[i]); timeSeries[i] = (double *)calloc(value, sizeof(double)); } } else if (function == NDPluginStatsTSControl) { switch (value) { case TSEraseStart: setIntegerParam(NDPluginStatsTSCurrentPoint, 0); setIntegerParam(NDPluginStatsTSAcquiring, 1); getIntegerParam(NDPluginStatsTSNumPoints, &numPoints); for (i=0; i<MAX_TIME_SERIES_TYPES; i++) { memset(this->timeSeries[i], 0, numPoints*sizeof(double)); } break; case TSStart: getIntegerParam(NDPluginStatsTSNumPoints, &numPoints); getIntegerParam(NDPluginStatsTSCurrentPoint, ¤tPoint); if (currentPoint < numPoints) { setIntegerParam(NDPluginStatsTSAcquiring, 1); } break; case TSStop: setIntegerParam(NDPluginStatsTSAcquiring, 0); doTimeSeriesCallbacks(); break; case TSRead: doTimeSeriesCallbacks(); break; } } else { /* If this parameter belongs to a base class call its method */ if (function < FIRST_NDPLUGIN_STATS_PARAM) status = NDPluginDriver::writeInt32(pasynUser, value); } /* 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=%d", 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 pasynInt32->write(). * \param[in] pasynUser pasynUser structure that encodes the reason and address. * \param[in] value Value to write. */ asynStatus drvQuadEM::writeInt32(asynUser *pasynUser, epicsInt32 value) { int function = pasynUser->reason; int status = asynSuccess; int channel; const char *paramName; const char* functionName = "writeInt32"; getAddress(pasynUser, &channel); /* Set the parameter in the parameter library. */ status |= setIntegerParam(channel, function, value); /* Fetch the parameter string name for possible use in debugging */ getParamName(function, ¶mName); if (function == P_Acquire) { if (value) { epicsRingBytesFlush(ringBuffer_); ringCount_ = 0; } status |= setAcquire(value); } else if (function == P_AcquireMode) { if (value != QEAcquireModeContinuous) { status |= setAcquire(0); setIntegerParam(P_Acquire, 0); } status |= setAcquireMode(value); status |= readStatus(); } else if (function == P_BiasState) { status |= setBiasState(value); status |= readStatus(); } else if (function == P_BiasInterlock) { status |= setBiasInterlock(value); status |= readStatus(); } else if (function == P_NumChannels) { status |= setNumChannels(value); status |= readStatus(); } else if (function == P_NumAcquire) { status |= setNumAcquire(value); status |= readStatus(); } else if (function == P_PingPong) { status |= setPingPong(value); status |= readStatus(); } else if (function == P_Range) { status |= setRange(value); status |= readStatus(); } else if (function == P_ReadData) { status |= doDataCallbacks(); } else if (function == P_Resolution) { status |= setResolution(value); status |= readStatus(); } else if (function == P_TriggerMode) { status |= setTriggerMode(value); status |= readStatus(); } else if (function == P_ValuesPerRead) { valuesPerRead_ = value; status |= setValuesPerRead(value); status |= readStatus(); } else if (function == P_ReadFormat) { status |= setReadFormat(value); status |= readStatus(); } else if (function == P_ReadStatus) { // We don't do this if we are acquiring, too disruptive if (!acquiring_) { status |= readStatus(); } } else if (function == P_Reset) { status |= reset(); status |= readStatus(); } else { /* All other parameters just get set in parameter list, no need to * act on them here */ } /* Do callbacks so higher layers see any changes */ status |= (asynStatus) callParamCallbacks(); if (status) epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s:%s: status=%d, function=%d, name=%s, value=%d", driverName, functionName, status, function, paramName, value); else asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, "%s:%s: function=%d, name=%s, value=%d\n", driverName, functionName, function, paramName, value); return (asynStatus)status; }
/** Base method for writing a file * Handles logic for NDFileModeSingle, NDFileModeCapture and NDFileModeStream when the derived class does or * does not support NDPulginFileMultiple. Calls writeFile in the derived class. */ asynStatus NDPluginFile::writeFileBase() { int status = asynSuccess; int fileWriteMode; int numCapture, numCaptured; int i; int deleteDriverFile; NDArray *pArray; NDAttribute *pAttribute; char driverFileName[MAX_FILENAME_LEN]; char errorMessage[256]; const char* functionName = "writeFileBase"; /* Make sure there is a valid array */ if (!this->pArrays[0]) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: ERROR, must collect an array to get dimensions first\n", driverName, functionName); return(asynError); } getIntegerParam(NDFileWriteMode, &fileWriteMode); getIntegerParam(NDFileNumCapture, &numCapture); getIntegerParam(NDFileNumCaptured, &numCaptured); setIntegerParam(NDFileWriteStatus, NDFileWriteOK); setStringParam(NDFileWriteMessage, ""); /* We unlock the overall mutex here because we want the callbacks to be able to queue new * frames without waiting while we write files here. The only restriction is that the * callbacks must not modify any part of the class structure that we use here. */ switch(fileWriteMode) { case NDFileModeSingle: setIntegerParam(NDWriteFile, 1); callParamCallbacks(); status = this->openFileBase(NDFileModeWrite, this->pArrays[0]); if (status == asynSuccess) { this->unlock(); epicsMutexLock(this->fileMutexId); status = this->writeFile(this->pArrays[0]); epicsMutexUnlock(this->fileMutexId); this->lock(); if (status) { epicsSnprintf(errorMessage, sizeof(errorMessage)-1, "Error writing file, status=%d", status); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s %s\n", driverName, functionName, errorMessage); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, errorMessage); } else { status = this->closeFileBase(); } } setIntegerParam(NDWriteFile, 0); callParamCallbacks(); break; case NDFileModeCapture: /* Write the file */ if (!this->pCapture) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: ERROR, no capture buffer present\n", driverName, functionName); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, "ERROR, no capture buffer present"); break; } setIntegerParam(NDWriteFile, 1); callParamCallbacks(); if (this->supportsMultipleArrays) status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, this->pArrays[0]); if (status == asynSuccess) { for (i=0; i<numCaptured; i++) { pArray = this->pCapture[i]; if (!this->supportsMultipleArrays) status = this->openFileBase(NDFileModeWrite, pArray); if (status == asynSuccess) { this->unlock(); epicsMutexLock(this->fileMutexId); status = this->writeFile(pArray); epicsMutexUnlock(this->fileMutexId); this->lock(); if (status) { epicsSnprintf(errorMessage, sizeof(errorMessage)-1, "Error writing file, status=%d", status); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s %s\n", driverName, functionName, errorMessage); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, errorMessage); } else { if (!this->supportsMultipleArrays) status = this->closeFileBase(); } } } } freeCaptureBuffer(numCapture); if ((status == asynSuccess) && this->supportsMultipleArrays) status = this->closeFileBase(); setIntegerParam(NDFileNumCaptured, 0); setIntegerParam(NDWriteFile, 0); callParamCallbacks(); break; case NDFileModeStream: if (!this->supportsMultipleArrays) status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, this->pArrays[0]); if (status == asynSuccess) { this->unlock(); epicsMutexLock(this->fileMutexId); status = this->writeFile(this->pArrays[0]); epicsMutexUnlock(this->fileMutexId); this->lock(); if (status) { epicsSnprintf(errorMessage, sizeof(errorMessage)-1, "Error writing file, status=%d", status); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s %s\n", driverName, functionName, errorMessage); setIntegerParam(NDFileWriteStatus, NDFileWriteError); setStringParam(NDFileWriteMessage, errorMessage); } else { if (!this->supportsMultipleArrays) status = this->closeFileBase(); } } break; default: asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: ERROR, unknown fileWriteMode %d\n", driverName, functionName, fileWriteMode); break; } /* Check to see if we should delete the original file * Only do this if all of the following conditions are met * - DeleteOriginalFile is true * - There were no errors above * - The NDFullFileName attribute is present and contains a non-blank string */ getIntegerParam(NDFileDeleteDriverFile, &deleteDriverFile); if ((status == asynSuccess) && deleteDriverFile) { pAttribute = this->pArrays[0]->pAttributeList->find("DriverFileName"); if (pAttribute) { status = pAttribute->getValue(NDAttrString, driverFileName, sizeof(driverFileName)); if ((status == asynSuccess) && (strlen(driverFileName) > 0)) { status = remove(driverFileName); if (status != 0) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error deleting file %s, error=%s\n", driverName, functionName, driverFileName, strerror(errno)); } } } } return((asynStatus)status); }
/** Callback function that is called by the NDArray driver with new NDArray data. * If the plugin is running then it attaches position data to the NDArray as NDAttributes * and then passes the array on. If the plugin is not running then NDArrays are not * passed through to the next plugin(s) in the chain. * \param[in] pArray The NDArray from the callback. */ void NDPosPlugin::processCallbacks(NDArray *pArray) { int index = 0; int running = NDPOS_IDLE; int skip = 0; int mode = 0; int size = 0; int duplicates = 0; int dropped = 0; int expectedID = 0; int IDDifference = 0; epicsInt32 IDValue = 0; char IDName[MAX_STRING_SIZE]; static const char *functionName = "NDPosPlugin::processCallbacks"; // Call the base class method NDPluginDriver::processCallbacks(pArray); getIntegerParam(NDPos_Running, &running); // We must maintain the size of the list ourselves, as calling // size() on the list has a complexity of O(n) which causes a problem // once we get into tens of thousands of items. getIntegerParam(NDPos_CurrentQty, &size); // Only attach the position data to the array if we are running if (running == NDPOS_RUNNING){ getIntegerParam(NDPos_CurrentIndex, &index); if (index >= size){ // We've reached the end of our positions, stop to make sure we don't overflow setIntegerParam(NDPos_Running, NDPOS_IDLE); running = NDPOS_IDLE; } else { // Read the ID parameter from the NDArray. If it cannot be found then abort getStringParam(NDPos_IDName, MAX_STRING_SIZE, IDName); // Check for IDName, if it is empty the we use the unique ID of the array if (strcmp(IDName, "") == 0){ IDValue = pArray->uniqueId; } else { NDAttribute *IDAtt = pArray->pAttributeList->find(IDName); if (IDAtt){ epicsInt32 IDValue; if (IDAtt->getValue(NDAttrInt32, &IDValue, sizeof(epicsInt32)) == ND_ERROR){ // Error, unable to get the value from the ID attribute asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s ERROR: could not retrieve expected ID from attribute [%s]\n", driverName, functionName, IDName); setIntegerParam(NDPos_Running, NDPOS_IDLE); running = NDPOS_IDLE; } } else { // Error, unable to find the named ID attribute asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s ERROR: could not find attribute [%s]\n", driverName, functionName, IDName); setIntegerParam(NDPos_Running, NDPOS_IDLE); running = NDPOS_IDLE; } } if (running == NDPOS_RUNNING){ // Check the ID is the same as the expected index getIntegerParam(NDPos_IDDifference, &IDDifference); getIntegerParam(NDPos_ExpectedID, &expectedID); if (expectedID < IDValue){ asynPrint(this->pasynUserSelf, ASYN_TRACE_WARNING, "%s::%s WARNING: possible frame drop detected: expected ID [%d] received ID [%d]\n", driverName, functionName, expectedID, IDValue); // If expected is less than ID throw away positions and record dropped events getIntegerParam(NDPos_MissingFrames, &dropped); getIntegerParam(NDPos_Mode, &mode); if (mode == MODE_DISCARD){ while ((expectedID < IDValue) && (size > 0)){ // The index will stay the same, and we need to pop the value out of the position array positionArray.erase(positionArray.begin()); size--; expectedID += IDDifference; dropped++; } // If the size has dropped to zero then we've run out of positions, abort if (size == 0){ setIntegerParam(NDPos_Running, NDPOS_IDLE); running = NDPOS_IDLE; } setIntegerParam(NDPos_CurrentQty, size); } else if (mode == MODE_KEEP){ while (expectedID < IDValue && (index < size)){ index++; expectedID += IDDifference; dropped++; } // If the index has reached the size of the array then we've run out of positions, abort if (index == size){ setIntegerParam(NDPos_Running, NDPOS_IDLE); running = NDPOS_IDLE; } setIntegerParam(NDPos_CurrentIndex, index); } setIntegerParam(NDPos_ExpectedID, expectedID); setIntegerParam(NDPos_MissingFrames, dropped); } else if (expectedID > IDValue){ asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s ERROR: dropping frame! possible duplicate detected: expected ID [%d] received ID [%d]\n", driverName, functionName, expectedID, IDValue); // If expected is greater than ID then ignore the frame and record duplicate event getIntegerParam(NDPos_DuplicateFrames, &duplicates); duplicates++; setIntegerParam(NDPos_DuplicateFrames, duplicates); skip = 1; } } // Only perform the actual setting of positions if we aren't skipping if (skip == 0 && running == NDPOS_RUNNING){ // We always keep the last array so read() can use it. // Release previous one. Reserve new one below during the copy. if (this->pArrays[0]){ this->pArrays[0]->release(); this->pArrays[0] = NULL; } // We must make a copy of the array as we are going to alter it this->pArrays[0] = this->pNDArrayPool->copy(pArray, this->pArrays[0], 1); if (this->pArrays[0]){ std::list<std::map<std::string, double> >::iterator it = positionArray.begin(); std::advance(it, index); //std::map<std::string, double> pos = positionArray[index]; std::map<std::string, double> pos = *it; std::stringstream sspos; sspos << "["; bool firstTime = true; std::map<std::string, double>::iterator iter; for (iter = pos.begin(); iter != pos.end(); iter++){ if (firstTime){ firstTime = false; } else { sspos << ","; } sspos << iter->first << "=" << iter->second; // Create the NDAttribute with the position data NDAttribute *pAtt = new NDAttribute(iter->first.c_str(), "Position of NDArray", NDAttrSourceDriver, driverName, NDAttrFloat64, &(iter->second)); // Add the NDAttribute to the NDArray this->pArrays[0]->pAttributeList->add(pAtt); } sspos << "]"; setStringParam(NDPos_CurrentPos, sspos.str().c_str()); } else { // We were unable to allocate the required buffer (memory or qty exceeded). // This results in us dropping a frame, note it and print an error asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s ERROR: dropped frame! Could not allocate the required buffer\n", driverName, functionName); // Note the frame drop getIntegerParam(NDPluginDriverDroppedArrays, &dropped); dropped++; setIntegerParam(NDPluginDriverDroppedArrays, dropped); skip = 1; } // Check the mode getIntegerParam(NDPos_Mode, &mode); if (mode == MODE_DISCARD){ // The index will stay the same, and we need to pop the value out of the position array positionArray.erase(positionArray.begin()); size--; setIntegerParam(NDPos_CurrentQty, size); } else if (mode == MODE_KEEP){ index++; setIntegerParam(NDPos_CurrentIndex, index); } // Increment the expectedID by the difference expectedID += IDDifference; setIntegerParam(NDPos_ExpectedID, expectedID); } } // If the size has dropped to zero then we've run out of positions, abort if (size == 0){ setIntegerParam(NDPos_Running, NDPOS_IDLE); } callParamCallbacks(); if (skip == 0 && running == NDPOS_RUNNING){ this->unlock(); doCallbacksGenericPointer(this->pArrays[0], NDArrayData, 0); this->lock(); } } }
/** Callback function that is called by the NDArray driver with new NDArray data. * Saves a single file if NDFileWriteMode=NDFileModeSingle and NDAutoSave=1. * Stores array in a capture buffer if NDFileWriteMode=NDFileModeCapture and NDFileCapture=1. * Appends data to an open file if NDFileWriteMode=NDFileModeStream and NDFileCapture=1. * In capture or stream mode if the desired number of arrays has been saved (NDFileNumCaptured=NDFileNumCapture) * then it stops capture or streaming. * \param[in] pArray The NDArray from the callback. */ void NDPluginFile::processCallbacks(NDArray *pArray) { int fileWriteMode, autoSave, capture; int arrayCounter; int numCapture, numCaptured; //const char* functionName = "processCallbacks"; /* First check if the callback is really for this file saving plugin */ if (!this->attrIsProcessingRequired(pArray->pAttributeList)) return; /* Most plugins want to increment the arrayCounter each time they are called, which NDPluginDriver * does. However, for this plugin we only want to increment it when we actually got a callback we were * supposed to save. So we save the array counter before calling base method, increment it here */ getIntegerParam(NDArrayCounter, &arrayCounter); /* Call the base class method */ NDPluginDriver::processCallbacks(pArray); getIntegerParam(NDAutoSave, &autoSave); getIntegerParam(NDFileCapture, &capture); getIntegerParam(NDFileWriteMode, &fileWriteMode); getIntegerParam(NDFileNumCapture, &numCapture); getIntegerParam(NDFileNumCaptured, &numCaptured); /* We always keep the last array so read() can use it. * Release previous one, reserve new one */ if (this->pArrays[0]) this->pArrays[0]->release(); pArray->reserve(); this->pArrays[0] = pArray; switch(fileWriteMode) { case NDFileModeSingle: if (autoSave) { arrayCounter++; writeFileBase(); } break; case NDFileModeCapture: if (capture) { if (numCaptured < numCapture) { this->pNDArrayPool->copy(pArray, this->pCapture[numCaptured++], 1); arrayCounter++; setIntegerParam(NDFileNumCaptured, numCaptured); } if (numCaptured == numCapture) { if (autoSave) { writeFileBase(); } capture = 0; setIntegerParam(NDFileCapture, capture); } } break; case NDFileModeStream: if (capture) { numCaptured++; arrayCounter++; setIntegerParam(NDFileNumCaptured, numCaptured); writeFileBase(); if (numCaptured == numCapture) { doCapture(0); } } break; } /* Update the parameters. */ setIntegerParam(NDArrayCounter, arrayCounter); callParamCallbacks(); }
/** * Readout thread function */ void ADSBIG::readoutTask(void) { epicsEventWaitStatus eventStatus; epicsFloat64 timeout = 0.001; bool error = false; size_t dims[2]; int nDims = 2; epicsInt32 sizeX = 0; epicsInt32 sizeY = 0; epicsInt32 minX = 0; epicsInt32 minY = 0; NDDataType_t dataType; epicsInt32 iDataType = 0; epicsUInt32 dataSize = 0; epicsTimeStamp nowTime; NDArray *pArray = NULL; epicsInt32 numImagesCounter = 0; epicsInt32 imageCounter = 0; PAR_ERROR cam_err = CE_NO_ERROR; const char* functionName = "ADSBIG::readoutTask"; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Started Readout Thread.\n", functionName); while (1) { //Wait for a stop event, with a short timeout, to catch any that were done after last one. eventStatus = epicsEventWaitWithTimeout(m_stopEvent, timeout); if (eventStatus == epicsEventWaitOK) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Got Stop Event Before Start Event.\n", functionName); } lock(); if (!error) { setStringParam(ADStatusMessage, "Idle"); } callParamCallbacks(); unlock(); eventStatus = epicsEventWait(m_startEvent); if (eventStatus == epicsEventWaitOK) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Got Start Event.\n", functionName); error = false; setStringParam(ADStatusMessage, " "); lock(); setIntegerParam(ADNumImagesCounter, 0); setIntegerParam(ADNumExposuresCounter, 0); //Sanity checks if ((p_Cam == NULL) || (p_Img == NULL)) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s NULL pointer.\n", functionName); break; } //printf("%s Time before acqusition: ", functionName); //epicsTime::getCurrent().show(0); //Read the frame sizes getIntegerParam(ADMinX, &minX); getIntegerParam(ADMinY, &minY); getIntegerParam(ADSizeX, &sizeX); getIntegerParam(ADSizeY, &sizeY); p_Cam->SetSubFrame(minX, minY, sizeX, sizeY); //Read what type of image we want - light field or dark field? int darkField = 0; getIntegerParam(ADSBIGDarkFieldParam, &darkField); if (darkField > 0) { cam_err = p_Cam->GrabSetup(p_Img, SBDF_DARK_ONLY); } else { cam_err = p_Cam->GrabSetup(p_Img, SBDF_LIGHT_ONLY); } if (cam_err != CE_NO_ERROR) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. CSBIGCam::GrabSetup returned an error. %s\n", functionName, p_Cam->GetErrorString(cam_err).c_str()); error = true; setStringParam(ADStatusMessage, p_Cam->GetErrorString(cam_err).c_str()); } unsigned short binX = 0; unsigned short binY = 0; p_Img->GetBinning(binX, binY); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " binX: %d\n", binY); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " binY: %d\n", binX); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " PixelHeight: %f\n", p_Img->GetPixelHeight()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " PixelWidth: %f\n", p_Img->GetPixelWidth()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Height: %d\n", p_Img->GetHeight()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Width: %d\n", p_Img->GetWidth()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Readout Mode: %d\n", p_Cam->GetReadoutMode()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Dark Field: %d\n", darkField); if (!error) { //Do exposure callParamCallbacks(); unlock(); if (darkField > 0) { cam_err = p_Cam->GrabMain(p_Img, SBDF_DARK_ONLY); } else { cam_err = p_Cam->GrabMain(p_Img, SBDF_LIGHT_ONLY); } lock(); if (cam_err != CE_NO_ERROR) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. CSBIGCam::GrabMain returned an error. %s\n", functionName, p_Cam->GetErrorString(cam_err).c_str()); error = true; setStringParam(ADStatusMessage, p_Cam->GetErrorString(cam_err).c_str()); } setDoubleParam(ADSBIGPercentCompleteParam, 100.0); if (!m_aborted) { unsigned short *pData = p_Img->GetImagePointer(); //printf("%s Time after acqusition: ", functionName); //epicsTime::getCurrent().show(0); //Update counters getIntegerParam(NDArrayCounter, &imageCounter); imageCounter++; setIntegerParam(NDArrayCounter, imageCounter); getIntegerParam(ADNumImagesCounter, &numImagesCounter); numImagesCounter++; setIntegerParam(ADNumImagesCounter, numImagesCounter); //NDArray callbacks int arrayCallbacks = 0; getIntegerParam(NDArrayCallbacks, &arrayCallbacks); getIntegerParam(NDDataType, &iDataType); dataType = static_cast<NDDataType_t>(iDataType); if (dataType == NDUInt8) { dataSize = sizeX*sizeY*sizeof(epicsUInt8); } else if (dataType == NDUInt16) { dataSize = sizeX*sizeY*sizeof(epicsUInt16); } else if (dataType == NDUInt32) { dataSize = sizeX*sizeY*sizeof(epicsUInt32); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. ERROR: We can't handle this data type. dataType: %d\n", functionName, dataType); error = true; dataSize = 0; } setIntegerParam(NDArraySize, dataSize); if (!error) { if (arrayCallbacks) { //Allocate an NDArray dims[0] = sizeX; dims[1] = sizeY; if ((pArray = this->pNDArrayPool->alloc(nDims, dims, dataType, 0, NULL)) == NULL) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. ERROR: pArray is NULL.\n", functionName); } else { epicsTimeGetCurrent(&nowTime); pArray->uniqueId = imageCounter; pArray->timeStamp = nowTime.secPastEpoch + nowTime.nsec / 1.e9; updateTimeStamp(&pArray->epicsTS); //Get any attributes that have been defined for this driver this->getAttributes(pArray->pAttributeList); //We copy data because the SBIG class library holds onto the original buffer until the next acqusition asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Copying data. dataSize: %d\n", functionName, dataSize); memcpy(pArray->pData, pData, dataSize); unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Calling NDArray callback\n", functionName); doCallbacksGenericPointer(pArray, NDArrayData, 0); lock(); pArray->release(); } } setIntegerParam(ADStatus, ADStatusIdle); } else { setIntegerParam(ADStatus, ADStatusError); } } else { //end if (!m_aborted) setIntegerParam(ADStatus, ADStatusAborted); m_aborted = false; } } callParamCallbacks(); //Complete Acquire callback setIntegerParam(ADAcquire, 0); callParamCallbacks(); unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Completed acqusition.\n", functionName); } //end of start event } //end of while(1) asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s: ERROR: Exiting ADSBIGReadoutTask main loop.\n", functionName); }
/** Constructor for mythen 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] IPPortName The asyn network port connection to the Mythen * \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. */ mythen::mythen(const char *portName, const char *IPPortName, int maxBuffers, size_t maxMemory, int priority, int stackSize) : ADDriver(portName, 1, NUM_SD_PARAMS, maxBuffers, maxMemory, 0, 0, /* No interfaces beyond those set in ADDriver.cpp */ ASYN_CANBLOCK | ASYN_MULTIDEVICE, 1, /* ASYN_CANBLOCK=1, ASYN_MULTIDEVICE=1, autoConnect=1 */ priority, stackSize) // , pDetector(NULL) { int status = asynSuccess; // NDArray *pData; const char *functionName = "mythen"; IPPortName_ = epicsStrDup(IPPortName); isBigEndian_ = EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG; /* Create the epicsEvents for signaling to the mythen 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; } // Connect to the server status = pasynOctetSyncIO->connect(IPPortName, 0, &pasynUserMeter_, NULL); if (status) { printf("%s:%s: error calling pasynOctetSyncIO->connect, status=%d, error=%s\n", driverName, functionName, status, pasynUserMeter_->errorMessage); return; } createParam(SDSettingString, asynParamInt32, &SDSetting); createParam(SDDelayTimeString, asynParamFloat64, &SDDelayTime); createParam(SDThresholdString, asynParamFloat64, &SDThreshold); createParam(SDEnergyString, asynParamFloat64, &SDEnergy); createParam(SDUseFlatFieldString, asynParamInt32, &SDUseFlatField); createParam(SDUseCountRateString, asynParamInt32, &SDUseCountRate); createParam(SDUseBadChanIntrplString, asynParamInt32, &SDUseBadChanIntrpl); createParam(SDBitDepthString, asynParamInt32, &SDBitDepth); createParam(SDUseGatesString, asynParamInt32, &SDUseGates); createParam(SDNumGatesString, asynParamInt32, &SDNumGates); createParam(SDNumFramesString, asynParamInt32, &SDNumFrames); createParam(SDTriggerString, asynParamInt32, &SDTrigger); createParam(SDResetString, asynParamInt32, &SDReset); createParam(SDTauString, asynParamFloat64, &SDTau); createParam(SDNModulesString, asynParamInt32, &SDNModules); createParam(SDFirmwareVersionString, asynParamOctet, &SDFirmwareVersion); createParam(SDReadModeString, asynParamInt32, &SDReadMode); status = setStringParam (ADManufacturer, "Dectris"); status |= setStringParam (ADModel, "Mythen"); status |= getFirmware(); status |= setStringParam (SDFirmwareVersion, firmwareVersion_); int sensorSizeX = MAX_DIMS; int sensorSizeY = 1; status |= setIntegerParam(ADMaxSizeX, sensorSizeX); status |= setIntegerParam(ADMaxSizeY, sensorSizeY); int minX, minY, sizeX, sizeY; minX = 1; minY = 1; sizeX = MAX_DIMS; sizeY = 1; status |= setIntegerParam(ADMinX, minX); status |= setIntegerParam(ADMinY, minY); status |= setIntegerParam(ADSizeX, sizeX); status |= setIntegerParam(ADSizeY, sizeY); status |= setIntegerParam(NDArraySize, 0); status |= setIntegerParam(NDDataType, NDInt32); status |= setIntegerParam(ADImageMode, ADImageSingle); /* NOTE: these char type waveform record could not be initialized in iocInit * Instead use autosave to restore their values. * It is left here only for references. * */ status |= setIntegerParam(ADStatus, getStatus()); //Get Firmware version // Read the current settings from the device. This will set parameters in the parameter library. getSettings(); int aux; //get nmodules and check for errors strcpy(outString_, "-get nmodules"); status |= writeReadMeter(); aux = stringToInt32(this->inString_); if (aux < 0) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error, outString=%s, inString=%s\n", driverName, functionName, outString_, inString_); return; } this->nmodules=aux; status |= setIntegerParam(SDNModules, aux); detArray_ = (epicsInt32*) calloc(this->nmodules*1280, sizeof(epicsInt32)); tmpArray_ = (epicsUInt32*) calloc(this->nmodules*1280, sizeof(epicsInt32)); callParamCallbacks(); if (status) { printf("%s: unable to read camera parameters\n", functionName); return; } /* Register the shutdown function for epicsAtExit */ // epicsAtExit(c_shutdown, (void*)this); /* Create the thread that runs acquisition */ status = (epicsThreadCreate("acquisitionTask", epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)acquisitionTaskC, this) == NULL); /* Create the thread that polls status */ // status = (epicsThreadCreate("pollTask", // epicsThreadPriorityMedium, // epicsThreadGetStackSize(epicsThreadStackMedium), // (EPICSTHREADFUNC)pollTaskC, // this) == NULL); }