diff --git a/andorApp/src/shamrock.cpp b/andorApp/src/shamrock.cpp new file mode 100755 index 0000000..e024474 --- /dev/null +++ b/andorApp/src/shamrock.cpp @@ -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 +#include +#include + +#include + +#include + +#include + +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; ireason. + * \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); +} + diff --git a/andorApp/src/shamrockSupport.dbd b/andorApp/src/shamrockSupport.dbd new file mode 100644 index 0000000..ab2b50f --- /dev/null +++ b/andorApp/src/shamrockSupport.dbd @@ -0,0 +1 @@ +registrar("shamrockRegister")