diff --git a/roperApp/Db/roper.template b/roperApp/Db/roper.template index 3c052e2..bd31833 100644 --- a/roperApp/Db/roper.template +++ b/roperApp/Db/roper.template @@ -243,4 +243,48 @@ record(waveform, "$(P)$(R)Comment5_RBV") field(SCAN, "I/O Intr") } +# Temperature status +record(bi, "$(P)$(R)TempStatus_RBV") +{ + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ROPER_TEMP_STATUS") + field(ZNAM, "Not Locked") + field(ONAM, "Locked") + field(SCAN, "I/O Intr") +} + +# Background image file name +record(waveform,"$(P)$(R)BgdFileName") +{ + field(DTYP, "asynOctetWrite") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ROPER_DARKNAME") + field(FTVL, "CHAR") + field(NELM, "128") +} + +record(waveform,"$(P)$(R)BgdFileName_RBV") +{ + field(DTYP, "asynOctetRead") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ROPER_DARKNAME") + field(FTVL, "CHAR") + field(NELM, "128") + field(SCAN, "I/O Intr") +} + +record(bo, "$(P)$(R)UseBgd") +{ + field(PINI, "YES") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ROPER_BBACKSUBTRACT") + field(ZNAM, "No") + field(ONAM, "Yes") +} +record(bi, "$(P)$(R)UseBgd_RBV") +{ + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ROPER_BBACKSUBTRACT") + field(ZNAM, "No") + field(ONAM, "Yes") + field(SCAN, "I/O Intr") +} diff --git a/roperApp/Db/roper_settings.req b/roperApp/Db/roper_settings.req index b34d244..6f61b78 100644 --- a/roperApp/Db/roper_settings.req +++ b/roperApp/Db/roper_settings.req @@ -2,6 +2,8 @@ $(P)$(R)NumAcquisitions $(P)$(R)RoperShutterMode $(P)$(R)AutoDataType $(P)$(R)Temperature +$(P)$(R)UseBgd +$(P)$(R)BgdFileName $(P)$(R)Comment1 $(P)$(R)Comment2 $(P)$(R)Comment3 diff --git a/roperApp/op/adl/Roper.adl b/roperApp/op/adl/Roper.adl index f9dd5bd..ad6995d 100644 --- a/roperApp/op/adl/Roper.adl +++ b/roperApp/op/adl/Roper.adl @@ -1,14 +1,14 @@ file { - name="/home/epics/devel/areaDetector/ADApp/op/adl/Roper.adl" - version=030102 + name="/work/sls/config/medm/Roper.adl" + version=030105 } display { object { x=175 y=80 width=700 - height=820 + height=850 } clr=14 bclr=4 @@ -1212,7 +1212,7 @@ rectangle { x=5 y=340 width=335 - height=410 + height=500 } "basic attribute" { clr=14 @@ -2022,3 +2022,90 @@ composite { "composite name"="" "composite file"="ADAttrFile.adl" } +"text update" { + object { + x=114 + y=787 + width=200 + height=18 + } + monitor { + chan="$(P)$(R)BgdFileName_RBV" + clr=54 + bclr=4 + } + format="string" + limits { + } +} +"text entry" { + object { + x=16 + y=811 + width=300 + height=20 + } + control { + chan="$(P)$(R)BgdFileName" + clr=14 + bclr=51 + } + format="string" + limits { + } +} +menu { + object { + x=140 + y=757 + width=80 + height=20 + } + control { + chan="$(P)$(R)UseBgd" + clr=14 + bclr=51 + } +} +"text update" { + object { + x=235 + y=759 + width=79 + height=18 + } + monitor { + chan="$(P)$(R)UseBgd_RBV" + clr=54 + bclr=4 + } + format="string" + limits { + } +} +text { + object { + x=21 + y=757 + width=110 + height=20 + } + "basic attribute" { + clr=14 + } + textix="Background" + align="horiz. right" +} +text { + object { + x=31 + y=785 + width=60 + height=20 + } + "basic attribute" { + clr=14 + } + textix="File" + align="horiz. right" +} diff --git a/roperApp/src/CDocFile40.h b/roperApp/src/CDocFile40.h index 170c831..5e5e8d5 100644 --- a/roperApp/src/CDocFile40.h +++ b/roperApp/src/CDocFile40.h @@ -1,6 +1,6 @@ // Machine generated IDispatch wrapper class(es) created with Add Class from Typelib Wizard -#import "C:\\Program Files\\PI Acton\\WinView\\Winview.exe" no_namespace +#import "WINX32Lib.tlb" no_namespace // CDocFile40 wrapper class class CDocFile40 : public COleDispatchDriver diff --git a/roperApp/src/CExpSetup20.h b/roperApp/src/CExpSetup20.h index cd49ada..fb47161 100644 --- a/roperApp/src/CExpSetup20.h +++ b/roperApp/src/CExpSetup20.h @@ -1,6 +1,6 @@ // Machine generated IDispatch wrapper class(es) created with Add Class from Typelib Wizard -#import "C:\\Program Files\\PI Acton\\WinView\\Winview.exe" no_namespace +#import "WINX32Lib.tlb" no_namespace // CExpSetup20 wrapper class class CExpSetup20 : public COleDispatchDriver diff --git a/roperApp/src/CROIRect0.h b/roperApp/src/CROIRect0.h index 93e66c8..b05d506 100644 --- a/roperApp/src/CROIRect0.h +++ b/roperApp/src/CROIRect0.h @@ -1,6 +1,6 @@ // Machine generated IDispatch wrapper class(es) created with Add Class from Typelib Wizard -#import "C:\\Program Files\\PI Acton\\WinView\\Winview.exe" no_namespace +#import "WINX32Lib.tlb" no_namespace // CROIRect0 wrapper class class CROIRect0 : public COleDispatchDriver diff --git a/roperApp/src/CWinx32App20.h b/roperApp/src/CWinx32App20.h index ba4a86c..8e33f0f 100644 --- a/roperApp/src/CWinx32App20.h +++ b/roperApp/src/CWinx32App20.h @@ -9,7 +9,7 @@ #undef max #endif -#import "C:\\Program Files\\PI Acton\\WinView\\Winview.exe" no_namespace +#import "WINX32Lib.tlb" no_namespace // CWinx32App20 wrapper class class CWinx32App20 : public COleDispatchDriver diff --git a/roperApp/src/WINX32Lib.tlb b/roperApp/src/WINX32Lib.tlb new file mode 100644 index 0000000..adaf477 Binary files /dev/null and b/roperApp/src/WINX32Lib.tlb differ diff --git a/roperApp/src/roper.cpp b/roperApp/src/roper.cpp index 7a1692a..acd0f9c 100644 --- a/roperApp/src/roper.cpp +++ b/roperApp/src/roper.cpp @@ -94,6 +94,9 @@ typedef enum { #define RoperNumAcquisitionsString "ROPER_NACQUISITIONS" #define RoperNumAcquisitionsCounterString "ROPER_NACQUISITIONS_COUNTER" #define RoperAutoDataTypeString "AUTO_DATA_TYPE" +#define RoperTemperatureStatusString "ROPER_TEMP_STATUS" +#define RoperUseBackgroundString "ROPER_BBACKSUBTRACT" +#define RoperBackgroundFileNameString "ROPER_DARKNAME" #define RoperComment1String "COMMENT1" #define RoperComment2String "COMMENT2" #define RoperComment3String "COMMENT3" @@ -116,6 +119,7 @@ class roper : public ADDriver { /* These are the methods that we override from ADDriver */ virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); + virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual); virtual void setShutter(int open); virtual asynStatus drvUserCreate(asynUser *pasynUser, const char *drvInfo, const char **pptypeName, size_t *psize); @@ -128,6 +132,9 @@ class roper : public ADDriver { int RoperNumAcquisitions; int RoperNumAcquisitionsCounter; int RoperAutoDataType; + int RoperTemperatureStatus; + int RoperUseBackground; + int RoperBackgroundFileName; int RoperComment1; int RoperComment2; int RoperComment3; @@ -391,10 +398,14 @@ asynStatus roper::getStatus() varResult = pExpSetup->GetParam(EXP_GAIN, &result); setDoubleParam(ADGain, (double)varResult.lVal); //varResult = pExpSetup->GetParam(EXP_FOCUS_NFRAME, &result); + varResult = pExpSetup->GetParam(EXP_BBACKSUBTRACT, &result); + setIntegerParam(RoperUseBackground, varResult.lVal); varResult = pExpSetup->GetParam(EXP_EXPOSURE, &result); setDoubleParam(ADAcquireTime, varResult.dblVal); varResult = pExpSetup->GetParam(EXP_ACTUAL_TEMP, &result); setDoubleParam(ADTemperature, varResult.dblVal); + varResult = pExpSetup->GetParam(EXP_TEMP_STATUS, &result); + setIntegerParam(RoperTemperatureStatus, varResult.lVal); pROIDispatch = pExpSetup->GetROI(1); pROIRect->AttachDispatch(pROIDispatch); pROIRect->Get(&top, &left, &bottom, &right, &binX, &binY); @@ -406,6 +417,10 @@ asynStatus roper::getStatus() setIntegerParam(ADMinY, minY); setIntegerParam(ADSizeX, sizeX); setIntegerParam(ADSizeY, sizeY); + varResult = this->pExpSetup->GetParam(EXP_DARKNAME, &result); + char * backgroundFile = _com_util::ConvertBSTRToString(varResult.bstrVal); + setStringParam(RoperBackgroundFileName, backgroundFile); + delete[] backgroundFile; } catch(CException *pEx) { pEx->GetErrorMessage(this->errorMessage, sizeof(this->errorMessage)); @@ -565,7 +580,7 @@ void roper::roperTask() int acquire, autoSave; NDArray *pImage; double acquireTime, acquirePeriod, delay; - epicsTimeStamp startTime, endTime; + epicsTimeStamp startTime, currentTime, endTime; double elapsedTime; const char *functionName = "roperTask"; VARIANT varArg; @@ -655,6 +670,17 @@ void roper::roperTask() setShutter(ADShutterClosed); break; } + /* Check if exposure is finished. This works only if acquisition has + * one exposure per image and one image per acquisition. + * Ideally EXP_RUNNING could differentiate between exposure and readout. + */ + epicsTimeGetCurrent(¤tTime); + if (epicsTimeDiffInSeconds(¤tTime, &startTime)>=acquireTime) { + /* Close the shutter */ + setShutter(ADShutterClosed); + /* Detector status is readout */ + setIntegerParam(ADStatus, ADStatusReadout); + } } } catch(CException *pEx) { @@ -816,6 +842,8 @@ asynStatus roper::writeInt32(asynUser *pasynUser, epicsInt32 value) varArg.lVal = roperDataType; this->pExpSetup->SetParam(EXP_DATATYPE, &varArg); } + } else if (function == RoperUseBackground) { + this->pExpSetup->SetParam(EXP_BBACKSUBTRACT, &varArg); } else { needReadStatus = 0; /* If this parameter belongs to a base class call its method */ @@ -825,7 +853,7 @@ asynStatus roper::writeInt32(asynUser *pasynUser, epicsInt32 value) catch(CException *pEx) { pEx->GetErrorMessage(this->errorMessage, sizeof(this->errorMessage)); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: exception = %s\n", + "%s:%s: exception = %s\n", driverName, functionName, this->errorMessage); pEx->Delete(); status = asynError; @@ -837,13 +865,13 @@ asynStatus roper::writeInt32(asynUser *pasynUser, epicsInt32 value) /* Do callbacks so higher layers see any changes */ callParamCallbacks(); - if (status) - asynPrint(pasynUser, ASYN_TRACE_ERROR, - "%s:%s: error, status=%d function=%d, value=%d\n", + 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", + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d, value=%d\n", driverName, functionName, function, value); return status; } @@ -911,6 +939,63 @@ asynStatus roper::writeFloat64(asynUser *pasynUser, epicsFloat64 value) return status; } +/* Called when asyn clients call pasynOctet->write(). + * \param [in] pasynUser pasynUser structure that encodes the reason and address. + * \param [in] value Address of the string to write. + * \param [in] nChars Number of characters to write. + * \param [out] nActual Number of characters actually written. +*/ +asynStatus roper::writeOctet(asynUser *pasynUser, const char *value, size_t nChars, size_t *nActual) +{ + int function = pasynUser->reason; + asynStatus status = asynSuccess; + BSTR bstr; + VARIANT varArg; + const char* functionName="writeOctet"; + + /* Initialize the variant and set data type */ + VariantInit(&varArg); + varArg.vt = VT_BSTR; + + /* Set the parameter and readback in the parameter library. This may be overwritten when we read back the + * status at the end, but that's OK */ + status = setStringParam(function, value); + + try { + if (function == RoperBackgroundFileName) { + bstr = stringToBSTR((char*)value); + varArg.bstrVal = bstr; + this->pExpSetup->SetParam(EXP_DARKNAME, &varArg); + SysFreeString(bstr); + } else { + /* If this parameter belongs to a base class call its method */ + if (function < FIRST_ROPER_PARAM) status = ADDriver::writeOctet(pasynUser, value, nChars, nActual); + } + } + catch(CException *pEx) { + pEx->GetErrorMessage(this->errorMessage, sizeof(this->errorMessage)); + asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, + "%s:%s: exception = %s\n", + driverName, functionName, this->errorMessage); + pEx->Delete(); + } + + /* Do callbacks so higher layers see any changes */ + callParamCallbacks(); + + if (status) + asynPrint(pasynUser, ASYN_TRACE_ERROR, + "%s:%s, status=%d function=%d, value=%f\n", + driverName, functionName, status, function, value); + else + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s:%s: function=%d, value=%f\n", + driverName, functionName, function, value); + *nActual = nChars; + return status; +} + + /** Sets pasynUser->reason to one of the enum values for the parameters defined for * this class if the drvInfo field matches one the strings defined for it. @@ -1011,6 +1096,9 @@ roper::roper(const char *portName, createParam(RoperNumAcquisitionsString, asynParamInt32, &RoperNumAcquisitions); createParam(RoperNumAcquisitionsCounterString, asynParamInt32, &RoperNumAcquisitionsCounter); createParam(RoperAutoDataTypeString, asynParamInt32, &RoperAutoDataType); + createParam(RoperTemperatureStatusString, asynParamInt32, &RoperTemperatureStatus); + createParam(RoperUseBackgroundString, asynParamInt32, &RoperUseBackground); + createParam(RoperBackgroundFileNameString, asynParamOctet, &RoperBackgroundFileName); createParam(RoperComment1String, asynParamOctet, &RoperComment1); createParam(RoperComment2String, asynParamOctet, &RoperComment2); createParam(RoperComment3String, asynParamOctet, &RoperComment3);