Merge pull request #26 from pheest/master

Added capability for CCD multi-track use.
This commit is contained in:
Mark Rivers
2019-12-02 10:57:40 -06:00
committed by GitHub
5 changed files with 174 additions and 38 deletions

View File

@@ -4,6 +4,7 @@
include "ADBase.template"
include "NDFile.template"
include "CCDMultiTrack.template"
# These are the records that we modify from NDFile.template
record(mbbo, "$(P)$(R)FileFormat")
@@ -373,6 +374,8 @@ record(mbbo, "$(P)$(R)AndorReadOutMode")
field(ZRVL, "0")
field(ONST, "Image")
field(ONVL, "4")
field(TWST, "Random Track")
field(TWVL, "2")
field(VAL, "4")
}
@@ -384,6 +387,8 @@ record(mbbi, "$(P)$(R)AndorReadOutMode_RBV")
field(ZRVL, "0")
field(ONST, "Image")
field(ONVL, "4")
field(TWST, "Random Track")
field(TWVL, "2")
field(SCAN, "I/O Intr")
}
@@ -421,6 +426,40 @@ record(mbbi, "$(P)$(R)AndorVSPeriod_RBV")
field(SCAN, "I/O Intr")
}
record(mbbo, "$(P)$(R)AndorVSAmplitude")
{
field(PINI, "1")
field(DTYP, "asynInt32")
field(ZRST, "Normal")
field(ZRVL, "0")
field(ONST, "+1")
field(ONVL, "1")
field(TWST, "+2")
field(TWVL, "2")
field(THST, "+3")
field(THVL, "3")
field(FRST, "+4")
field(FRVL, "4")
field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ANDOR_VS_AMPLITUDE")
field(VAL, "0")
}
record(mbbi, "$(P)$(R)AndorVSAmplitude_RBV")
{
field(DTYP, "asynInt32")
field(ZRST, "Normal")
field(ZRVL, "0")
field(ONST, "+1")
field(ONVL, "1")
field(TWST, "+2")
field(TWVL, "2")
field(THST, "+3")
field(THVL, "3")
field(FRST, "+4")
field(FRVL, "4")
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))ANDOR_VS_AMPLITUDE")
field(SCAN, "I/O Intr")
}
#Records in ADBase that do not apply to Andor
record(mbbo, "$(P)$(R)ColorMode")

View File

@@ -11,6 +11,7 @@ $(P)$(R)AndorADCSpeed
$(P)$(R)AndorReadOutMode
$(P)$(R)AndorFTMode
$(P)$(R)AndorVSPeriod
$(P)$(R)AndorVSAmplitude
file "ADBase_settings.req", P=$(P), R=$(R)
file "NDFile_settings.req", P=$(P), R=$(R)
file "CCDMultiTrack_settings.req", P=$(P), R=$(R)

View File

@@ -7,6 +7,7 @@
* Updated Dec 2011 for Asyn 4-17 and areaDetector 1-7
*
* Major updates to get callbacks working, etc. by Mark Rivers Feb. 2011
* Updated by Peter Heesterman to support multi-track operation Oct. 2019
*
*/
@@ -114,10 +115,10 @@ static void exitHandler(void *drvPvt);
AndorCCD::AndorCCD(const char *portName, const char *installPath, int cameraSerial, int shamrockID,
int maxBuffers, size_t maxMemory, int priority, int stackSize)
: ADDriver(portName, 1, NUM_ANDOR_DET_PARAMS, maxBuffers, maxMemory,
: ADDriver(portName, 1, 0, maxBuffers, maxMemory,
asynEnumMask, asynEnumMask,
ASYN_CANBLOCK, 1, priority, stackSize),
mExiting(false), mShamrockId(shamrockID), mSPEDoc(0), mInitOK(false)
mExiting(false), mExited(0), mShamrockId(shamrockID), mMultiTrack(this), mSPEDoc(0), mInitOK(false)
{
int status = asynSuccess;
@@ -146,7 +147,7 @@ AndorCCD::AndorCCD(const char *portName, const char *installPath, int cameraSeri
createParam(AndorShutterModeString, asynParamInt32, &AndorShutterMode);
createParam(AndorShutterExTTLString, asynParamInt32, &AndorShutterExTTL);
createParam(AndorPalFileNameString, asynParamOctet, &AndorPalFileName);
createParam(AndorAccumulatePeriodString, asynParamFloat64, &AndorAccumulatePeriod);
createParam(AndorAccumulatePeriodString, asynParamFloat64, &AndorAccumulatePeriod);
createParam(AndorPreAmpGainString, asynParamInt32, &AndorPreAmpGain);
createParam(AndorEmGainString, asynParamInt32, &AndorEmGain);
createParam(AndorEmGainModeString, asynParamInt32, &AndorEmGainMode);
@@ -156,6 +157,8 @@ AndorCCD::AndorCCD(const char *portName, const char *installPath, int cameraSeri
createParam(AndorReadOutModeString, asynParamInt32, &AndorReadOutMode);
createParam(AndorFrameTransferModeString, asynParamInt32, &AndorFrameTransferMode);
createParam(AndorVerticalShiftPeriodString, asynParamInt32, &AndorVerticalShiftPeriod);
createParam(AndorVerticalShiftAmplitudeString, asynParamInt32, &AndorVerticalShiftAmplitude);
// Create the epicsEvent for signaling to the status task when parameters should have changed.
// This will cause it to do a poll immediately, rather than wait for the poll time period.
@@ -295,6 +298,7 @@ AndorCCD::AndorCCD(const char *portName, const char *installPath, int cameraSeri
setupPreAmpGains();
setupVerticalShiftPeriods();
status |= setIntegerParam(AndorVerticalShiftPeriod, mVSIndex);
status |= setIntegerParam(AndorVerticalShiftAmplitude, 0);
status |= setupShutter(-1);
callParamCallbacks();
@@ -352,10 +356,15 @@ AndorCCD::~AndorCCD()
{
static const char *functionName = "~AndorCCD";
this->lock();
mExiting = true;
this->lock();
printf("%s::%s Shutdown and freeing up memory...\n", driverName, functionName);
try {
int acquireStatus;
checkStatus(GetStatus(&acquireStatus));
if (acquireStatus == DRV_ACQUIRING)
checkStatus(AbortAcquisition());
epicsEventSignal(dataEvent);
checkStatus(FreeInternalMemory());
checkStatus(ShutDown());
} catch (const std::string &e) {
@@ -364,6 +373,8 @@ AndorCCD::~AndorCCD()
driverName, functionName, e.c_str());
}
this->unlock();
while (mExited < 2)
epicsThreadSleep(0.2);
}
@@ -666,7 +677,7 @@ asynStatus AndorCCD::writeInt32(asynUser *pasynUser, epicsInt32 value)
(function == AndorEmGainMode) || (function == AndorEmGainAdvanced) ||
(function == AndorAdcSpeed) || (function == AndorPreAmpGain) ||
(function == AndorReadOutMode) || (function == AndorFrameTransferMode) ||
(function == AndorVerticalShiftPeriod)) {
(function == AndorVerticalShiftPeriod) || (function == AndorVerticalShiftAmplitude)) {
status = setupAcquisition();
if (function == AndorAdcSpeed) setupPreAmpGains();
if (status != asynSuccess) setIntegerParam(function, oldValue);
@@ -815,11 +826,66 @@ asynStatus AndorCCD::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
driverName, functionName, status, function, value);
else
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s: function=%d, value=%f\n",
driverName, functionName, function, value);
"%s:%s: function=%d, value=%f\n",
driverName, functionName, function, value);
return status;
}
/* Called if tracks acquisition mode is being used.
Sets up the track defintion. */
void AndorCCD::setupTrackDefn(int minX, int sizeX, int binX)
{
static const char *functionName = "setupTrackDefn";
if (mMultiTrack.size() == 0)
{
asynPrint(this->pasynUserSelf, ASYN_TRACE_WARNING,
"%s:%s: A track defintion must be set to use tracks mode\n",
driverName, functionName);
return;
}
static const int ValuesPerTrack = 6;
std::vector<int> TrackDefn(mMultiTrack.size() * 6);
setIntegerParam(NDArraySizeY, mMultiTrack.DataHeight());
for (size_t TrackNo = 0; TrackNo < mMultiTrack.size(); TrackNo++)
{
/*
Each track must be defined by a group of six integers.
- The top and bottom positions of the tracks.
- The left and right positions for the area of interest within each track
- The horizontal and vertical binning for each track. */
TrackDefn[TrackNo * 6 + 0] = mMultiTrack.TrackStart(TrackNo);
TrackDefn[TrackNo * 6 + 1] = mMultiTrack.TrackEnd(TrackNo);
TrackDefn[TrackNo * 6 + 2] = minX + 1;
TrackDefn[TrackNo * 6 + 3] = minX + sizeX;
TrackDefn[TrackNo * 6 + 4] = binX;
TrackDefn[TrackNo * 6 + 5] = mMultiTrack.TrackBin(TrackNo);
}
checkStatus(SetCustomTrackHBin(binX));
checkStatus(SetComplexImage(int(TrackDefn.size() / ValuesPerTrack), &TrackDefn[0]));
}
/* Called to set tracks definition parameters.
Sets up the track defintion. */
asynStatus AndorCCD::writeInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements)
{
static const char *functionName = "writeInt32Array";
asynStatus status = asynSuccess;
try {
status = mMultiTrack.writeInt32Array(pasynUser, value, nElements);
if (status != asynError)
setupAcquisition();
else
status = ADDriver::writeInt32Array(pasynUser, value, nElements);
}
catch (const std::string &e) {
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: %s\n",
driverName, functionName, e.c_str());
status = asynError;
}
return status;
}
/** Controls shutter
* @param[in] command 0=close, 1=open, -1=no change, only set other parameters */
@@ -969,6 +1035,8 @@ unsigned int AndorCCD::checkStatus(unsigned int returnStatus)
throw std::string("ERROR: Error loading firmware.");
} else if (returnStatus == DRV_NOT_SUPPORTED) {
throw std::string("ERROR: Feature not supported.");
} else if (returnStatus == DRV_RANDOM_TRACK_ERROR) {
throw std::string("ERROR: Invalid combination of tracks");
} else {
sprintf(message, "ERROR: Unknown error code=%d returned from Andor SDK.", returnStatus);
throw std::string(message);
@@ -1020,8 +1088,8 @@ void AndorCCD::statusTask(void)
forcedFastPolls = 5;
}
if (mExiting) break;
this->lock();
if (mExiting) break;
try {
//Only read these if we are not acquiring data
@@ -1074,8 +1142,11 @@ void AndorCCD::statusTask(void)
this->unlock();
} //End of loop
printf("%s:%s: Status thread exiting ...\n", driverName, functionName);
asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s: Status thread exiting ...\n",
driverName, functionName);
mExited++;
}
/** Set up acquisition parameters */
@@ -1098,6 +1169,7 @@ asynStatus AndorCCD::setupAcquisition()
int readOutMode;
int frameTransferMode;
int verticalShiftPeriod;
int verticalShiftAmplitude;
static const char *functionName = "setupAcquisition";
if (!mInitOK) {
@@ -1185,17 +1257,23 @@ asynStatus AndorCCD::setupAcquisition()
// Unfortunately there does not seem to be a way to query the Andor SDK
// for the actual size of the image, so we must compute it.
setIntegerParam(NDArraySizeX, sizeX/binX);
setIntegerParam(NDArraySizeY, sizeY/binY);
if (readOutMode != ARRandomTrack)
// The data height dimension is set by setupTrackDefn for multi-track mode.
setIntegerParam(NDArraySizeY, sizeY/binY);
getIntegerParam(AndorFrameTransferMode, &frameTransferMode);
getIntegerParam(AndorVerticalShiftPeriod, &verticalShiftPeriod);
getIntegerParam(AndorVerticalShiftAmplitude, &verticalShiftAmplitude);
try {
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s:, SetReadMode(%d)\n",
driverName, functionName, readOutMode);
checkStatus(SetReadMode(readOutMode));
if (readOutMode == ARRandomTrack)
setupTrackDefn(minX, sizeX, binX);
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s:, SetTriggerMode(%d)\n",
@@ -1266,11 +1344,16 @@ asynStatus AndorCCD::setupAcquisition()
driverName, functionName, frameTransferMode);
checkStatus(SetFrameTransferMode(frameTransferMode));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s:, SetVSSpeed(%d)\n",
driverName, functionName, verticalShiftPeriod);
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s:, SetVSSpeed(%d)\n",
driverName, functionName, verticalShiftPeriod);
checkStatus(SetVSSpeed(verticalShiftPeriod));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s:, SetVSAmplitude(%d)\n",
driverName, functionName, verticalShiftAmplitude);
checkStatus(SetVSAmplitude(verticalShiftAmplitude));
switch (imageMode) {
case ADImageSingle:
if (numExposures == 1) {
@@ -1395,19 +1478,22 @@ void AndorCCD::dataTask(void)
epicsTimeStamp startTime;
NDArray *pArray;
int autoSave;
int readOutMode;
static const char *functionName = "dataTask";
printf("%s:%s: Data thread started...\n", driverName, functionName);
this->lock();
while(1) {
while(!mExiting) {
errorString = NULL;
//Wait for event from main thread to signal that data acquisition has started.
this->unlock();
status = epicsEventWait(dataEvent);
if (mExiting)
break;
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s:%s:, got data event\n",
driverName, functionName);
@@ -1419,6 +1505,7 @@ void AndorCCD::dataTask(void)
status = setupAcquisition();
if (status != asynSuccess) continue;
getIntegerParam(ADShutterMode, &adShutterMode);
getIntegerParam(AndorReadOutMode, &readOutMode);
if (adShutterMode == ADShutterModeEPICS) {
ADDriver::setShutter(ADShutterOpen);
}
@@ -1450,7 +1537,7 @@ void AndorCCD::dataTask(void)
acquiring = 0;
}
while (acquiring) {
while ((acquiring) && (!mExiting)) {
try {
checkStatus(GetStatus(&acquireStatus));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
@@ -1491,6 +1578,8 @@ void AndorCCD::dataTask(void)
dims[0] = sizeX;
dims[1] = sizeY;
pArray = this->pNDArrayPool->alloc(nDims, dims, dataType, 0, NULL);
if (readOutMode == ARRandomTrack)
mMultiTrack.storeTrackAttributes(pArray->pAttributeList);
// Read the oldest array
// Is there still an image available?
status = GetNumberNewImages(&firstImage, &lastImage);
@@ -1533,11 +1622,14 @@ void AndorCCD::dataTask(void)
callParamCallbacks();
}
} catch (const std::string &e) {
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: %s\n",
driverName, functionName, e.c_str());
errorString = const_cast<char *>(e.c_str());
setStringParam(AndorMessage, errorString);
if (!mExiting)
{
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: %s\n",
driverName, functionName, e.c_str());
errorString = const_cast<char *>(e.c_str());
setStringParam(AndorMessage, errorString);
}
}
}
@@ -1553,7 +1645,8 @@ void AndorCCD::dataTask(void)
/* Call the callbacks to update any changes */
callParamCallbacks();
} //End of loop
mExited++;
this->unlock();
}

View File

@@ -4,15 +4,17 @@
* @author Matthew Pearson
* @date June 2009
*
* Updated Dec 2011 for Asyn 4-17 and areaDetector 1-7
* Updated Dec 2011 for Asyn 4-17 and areaDetector 1-7
*
* Major updates to get callbacks working, etc. by Mark Rivers Feb. 2011
* Updated by Peter Heesterman to support multi-track operation Oct. 2019
*/
#ifndef ANDORCCD_H
#define ANDORCCD_H
#include <libxml/parser.h>
#include <CCDMultiTrack.h>
#include "ADDriver.h"
#include "SPEHeader.h"
@@ -38,6 +40,7 @@
#define AndorReadOutModeString "ANDOR_READOUT_MODE"
#define AndorFrameTransferModeString "ANDOR_FT_MODE"
#define AndorVerticalShiftPeriodString "ANDOR_VS_PERIOD"
#define AndorVerticalShiftAmplitudeString "ANDOR_VS_AMPLITUDE"
/**
* Structure defining an ADC speed for the ADAndor driver.
@@ -86,8 +89,9 @@ class AndorCCD : 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 writeInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements);
virtual void report(FILE *fp, int details);
virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[],
virtual asynStatus readEnum(asynUser *pasynUser, char *strings[], int values[], int severities[],
size_t nElements, size_t *nIn);
// Should be private, but are called from C so must be public
@@ -96,7 +100,7 @@ class AndorCCD : public ADDriver {
protected:
int AndorCoolerParam;
#define FIRST_ANDOR_PARAM AndorCoolerParam
#define FIRST_ANDOR_PARAM AndorCoolerParam
int AndorTempStatusMessage;
int AndorMessage;
int AndorShutterMode;
@@ -112,7 +116,8 @@ class AndorCCD : public ADDriver {
int AndorReadOutMode;
int AndorFrameTransferMode;
int AndorVerticalShiftPeriod;
#define LAST_ANDOR_PARAM AndorVerticalShiftPeriod
int AndorVerticalShiftAmplitude;
#define LAST_ANDOR_PARAM AndorVerticalShiftAmplitude
private:
@@ -121,13 +126,14 @@ class AndorCCD : public ADDriver {
asynStatus setupShutter(int command);
void saveDataFrame(int frameNumber);
void setupADCSpeeds();
void setupTrackDefn(int minX, int sizeX, int binX);
void setupPreAmpGains();
void setupVerticalShiftPeriods();
unsigned int SaveAsSPE(char *fullFileName);
/**
* Additional image mode to those in ADImageMode_t
*/
static const epicsInt32 AImageFastKinetics;
static const epicsInt32 AImageFastKinetics;
/**
* List of acquisiton modes.
@@ -197,7 +203,8 @@ class AndorCCD : public ADDriver {
unsigned int mAcquiringData;
char *mInstallPath;
bool mExiting;
int mExited;
/**
* ADC speed parameters
*/
@@ -222,17 +229,19 @@ class AndorCCD : public ADDriver {
float mAccumulatePeriod;
int mMinShutterOpenTime;
int mMinShutterCloseTime;
// Shamrock spectrometer ID
int mShamrockId;
// AndorCapabilities structure
AndorCapabilities mCapabilities;
CCDMultiTrack mMultiTrack;
// EM Gain parameters
int mEmGainRangeLow;
int mEmGainRangeHigh;
// SPE file header
tagCSMAHEAD *mSPEHeader;
xmlDocPtr mSPEDoc;
@@ -241,7 +250,4 @@ class AndorCCD : public ADDriver {
bool mInitOK;
};
#define NUM_ANDOR_DET_PARAMS ((int)(&LAST_ANDOR_PARAM - &FIRST_ANDOR_PARAM + 1))
#endif //ANDORCCD_H

View File

@@ -102,9 +102,6 @@ private:
bool flipperMirrorIsPresent_[MAX_FLIPPER_MIRRORS];
};
/** Number of asynPortDriver parameters this driver supports. */
#define NUM_SR_PARAMS ((int)(&LAST_SR_PARAM - &FIRST_SR_PARAM + 1))
/** Configuration function to configure one spectrograph.
*
* This function need to be called once for each spectrography to be used by the IOC. A call to this