New driver for Shamrock spectrometers; only supported on Windows

This commit is contained in:
Mark Rivers
2014-04-12 07:52:42 -05:00
parent 7d0d38116b
commit 36a2f79c8a
2 changed files with 405 additions and 0 deletions
+404
View File
@@ -0,0 +1,404 @@
/*
* shamrock.cpp
*
* This is an EPICS driver for Andor Shamrock spectrographs
*
* Author: Mark Rivers
* Univerity of Chicago
*
* Created: April 9, 2014
*
*/
#include <iocsh.h>
#include <epicsString.h>
#include <epicsExit.h>
#include <asynPortDriver.h>
#include <ShamrockCIF.h>
#include <epicsExport.h>
static const char *driverName = "shamrock";
/* Shamrock driver specific parameters */
#define SRWavelengthString "SR_WAVELENGTH"
#define SRMinWavelengthString "SR_MIN_WAVELENGTH"
#define SRMaxWavelengthString "SR_MAX_WAVELENGTH"
#define SRCalibrationString "SR_CALIBRATION"
#define SRGratingString "SR_GRATING"
#define SRNumGratingsString "SR_NUM_GRATINGS"
#define SRGratingExistsString "SR_GRATING_EXISTS"
#define SRSlitExistsString "SR_SLIT_EXISTS"
#define SRSlitSizeString "SR_SLIT_SIZE"
#define MAX_ERROR_MESSAGE_SIZE 100
#define MAX_SLITS 4
#define MAX_GRATINGS 3
// Maximum number of address.
#define MAX_ADDR 4
/** Main driver class inherited from asyn asynPortDriver class.
* One instance of this class will control one spectrography.
*/
class shamrock : public asynPortDriver
{
public:
shamrock(const char *portName, int shamrockID, const char *iniPath, int priority, int stacksize);
/* virtual methods to override from ADDriver */
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
virtual asynStatus readFloat32Array(asynUser *pasynUser, epicsFloat32 *pValue, size_t nElements, size_t *nIn);
void report(FILE *fp, int details);
/**< These should be private but are called from C callback functions, must be public. */
void shutdown();
protected:
int SRWavelength_; /** Wavelength (float64 read/write) */
#define FIRST_SR_PARAM SRWavelength_
int SRMinWavelength_; /** Min wavelength (float64 read/write) */
int SRMaxWavelength_; /** Min wavelength (float64 read/write) */
int SRCalibration_; /** Calibration (float32 array read) */
int SRGrating_; /** Grating (int32 read/write) */
int SRNumGratings_; /** Number of gratings (int32 read) */
int SRGratingExists_; /** Grating exists (int32 read) */
int SRSlitExists_; /** Slit exists (int32 read) */
int SRSlitSize_; /** Slit width (float64 read/write) */
#define LAST_SR_PARAM SRSlitSize_
private:
/* Local methods to this class */
inline asynStatus checkError(int status, const char *functionName, const char *shamrockFunction);
asynStatus getStatus();
/* Data */
bool exiting_;
int shamrockId_;
bool slitIsPresent_[MAX_SLITS];
int numPixels_;
float *calibration_;
char lastError_[MAX_ERROR_MESSAGE_SIZE];
};
/** 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
* function instanciates one object from 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.
*/
extern "C" int shamrockConfig(const char *portName, int shamrockId, const char *iniPath,
int priority, int stackSize)
{
new shamrock( portName, shamrockId, iniPath, priority, stackSize);
return asynSuccess;
}
static void c_shutdown(void *arg)
{
shamrock *p = (shamrock *)arg;
p->shutdown();
}
/** 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),
exiting_(0), 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);
}
/* shutdown on exit */
epicsAtExit(c_shutdown, this);
return;
}
inline asynStatus shamrock::checkError(int status, const char *functionName, const char *shamrockFunction)
{
if (status != SHAMROCK_SUCCESS) {
ShamrockGetFunctionReturnDescription(status, lastError_, sizeof(lastError_));
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
"%s:%s: ERROR calling %s Description=%s\n",
driverName, functionName, shamrockFunction, lastError_);
return asynError;
}
return asynSuccess;
}
asynStatus shamrock::getStatus()
{
int error;
asynStatus status;
int grating;
float wavelength;
float width;
int i;
static const char *functionName = "getStatus";
error = ShamrockGetGrating(shamrockId_, &grating);
status = checkError(error, functionName, "ShamrockGetGrating");
if (status) return asynError;
setIntegerParam(SRGrating_, grating);
error = ShamrockGetWavelength(shamrockId_, &wavelength);
status = checkError(error, functionName, "ShamrockGetWavelength");
if (status) return asynError;
setDoubleParam(SRWavelength_, wavelength);
for (i=0; i<MAX_SLITS; i++) {
setDoubleParam(i, SRSlitSize_, 0.);
if (slitIsPresent_[i] == 0) continue;
error = ShamrockGetAutoSlitWidth(shamrockId_, i+1, &width);
status = checkError(error, functionName, "ShamrockGetAutoSlitWidth");
if (status) return asynError;
setDoubleParam(i, SRSlitSize_, width);
}
error = ShamrockGetCalibration(shamrockId_, calibration_, numPixels_);
status = checkError(error, functionName, "ShamrockGetCalibration");
setDoubleParam(0, SRMinWavelength_, calibration_[0]);
setDoubleParam(0, SRMaxWavelength_, calibration_[numPixels_-1]);
// We need to find a C/C++ library to do 3'rd order polynomial fit
// For now we do a first order fit!
double slope = (calibration_[numPixels_-1] - calibration_[0]) / (numPixels_-1);
for (i=0; i<MAX_ADDR; i++) {
callParamCallbacks(i);
}
doCallbacksFloat32Array(calibration_, numPixels_, SRCalibration_, 0);
return asynSuccess;
}
void shamrock::shutdown(void)
{
exiting_ = 1;
ShamrockClose();
}
/** Sets an int32 parameter.
* \param[in] pasynUser asynUser structure that contains the function code in pasynUser->reason.
* \param[in] value The value for this parameter
*
* Takes action if the function code requires it. ADAcquire, ADSizeX, and many other
* function codes make calls to the Firewire library from this function. */
asynStatus shamrock::writeInt32( asynUser *pasynUser, epicsInt32 value)
{
asynStatus status = asynSuccess;
int error;
int function = pasynUser->reason;
int addr;
static const char *functionName = "writeInt32";
pasynManager->getAddr(pasynUser, &addr);
if (addr < 0) addr=0;
/* Set the value in the parameter library. This may change later but that's OK */
status = setIntegerParam(addr, function, value);
if (function == SRGrating_) {
error = ShamrockSetGrating(shamrockId_, value);
status = checkError(error, functionName, "ShamrockSetGrating");
}
getStatus();
asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER,
"%s::%s function=%d, value=%d, status=%d\n",
driverName, functionName, function, value, status);
callParamCallbacks(addr);
return status;
}
/** Sets an float64 parameter.
* \param[in] pasynUser asynUser structure that contains the function code in pasynUser->reason.
* \param[in] value The value for this parameter
*
* Takes action if the function code requires it. */
asynStatus shamrock::writeFloat64( asynUser *pasynUser, epicsFloat64 value)
{
asynStatus status = asynSuccess;
int error;
int function = pasynUser->reason;
int addr;
static const char *functionName = "writeFloat64";
pasynManager->getAddr(pasynUser, &addr);
if (addr < 0) addr=0;
/* Set the value in the parameter library. This may change later but that's OK */
status = setDoubleParam(addr, function, value);
if (function == SRWavelength_) {
error = ShamrockSetWavelength(shamrockId_, (float) value);
status = checkError(error, functionName, "ShamrockSetWavelength");
}
else if (function == SRSlitSize_) {
if (slitIsPresent_[addr]) {
error = ShamrockSetAutoSlitWidth(shamrockId_, addr+1, (float) value);
status = checkError(error, functionName, "ShamrockSetSlit");
}
}
getStatus();
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s::%s function=%d, value=%f, status=%d\n",
driverName, functionName, function, value, status);
callParamCallbacks(addr);
return status;
}
/** Reads float32 array.
* \param[in] pasynUser asynUser structure that contains the function code in pasynUser->reason.
* \param[in] value The array
* \param[in] nElements The size of the array
* \param[out] Nin The number of elements copied to the array
* Takes action if the function code requires it. */
asynStatus shamrock::readFloat32Array(asynUser *pasynUser, epicsFloat32 *pValue, size_t nElements, size_t *nIn)
{
asynStatus status = asynSuccess;
int function = pasynUser->reason;
static const char *functionName = "readFloat32Array";
if (function == SRCalibration_) {
*nIn = numPixels_;
if (nElements < *nIn) *nIn = nElements;
memcpy(pValue, calibration_, *nIn * sizeof(float));
}
return status;
}
/** Print out a report; calls asynPortDriver::report to get base class report as well.
* \param[in] fp File pointer to write output to
* \param[in] details Level of detail desired.
*/
void shamrock::report(FILE *fp, int details)
{
static const char *functionName = "report";
asynPortDriver::report(fp, details);
return;
}
static const iocshArg configArg0 = {"Port name", iocshArgString};
static const iocshArg configArg1 = {"shamrockId", iocshArgInt};
static const iocshArg configArg2 = {"iniPath", iocshArgString};
static const iocshArg configArg3 = {"priority", iocshArgInt};
static const iocshArg configArg4 = {"stackSize", iocshArgInt};
static const iocshArg * const configArgs[] = {&configArg0,
&configArg1,
&configArg2,
&configArg3,
&configArg4};
static const iocshFuncDef configShamrock = {"shamrockConfig", 5, configArgs};
static void configCallFunc(const iocshArgBuf *args)
{
shamrockConfig(args[0].sval, args[1].ival, args[2].sval,
args[3].ival, args[4].ival);
}
static void shamrockRegister(void)
{
iocshRegister(&configShamrock, configCallFunc);
}
extern "C" {
epicsExportRegistrar(shamrockRegister);
}
+1
View File
@@ -0,0 +1 @@
registrar("shamrockRegister")