/*----------------------------------------------------------------------------- * This is a driver for the DELCam Neutron CCD camera. This driver has some * limitations: * - Due to the dark current of a CCD, only timer measurements * are useful. * - If there is no beam, the measurement has to be aborted. * - While reading the CCD, the computer locks up. * - No intermediate results can be retrieved while data acquisition is * active. This is due to the nature of the CCD readout: Each line is * swapped into a line buffer which then is sequentially read. This * may be a consequence of the fact that exposure just generates charges * on the CCD. * - This driver requires a Linux kernel module to be loaded beforehand. * - The DELCam's paralell port connector MUST be connected to the * paralell port of the computer running the SICServer. * - This code works only on Linux, porting to other OS requires different * drivers. * The DELCam uses a CCD which was originally developed as CCD for amateur * astronomers. The name of the project is Audine. This driver uses the * audine driver code. Look in audinelib.h for a WWW pointer. * * copyright: see file COPYRIGHT * * Mark Koennecke, March 2007 */ #include #include #include #include #include #include #include #include #include "audinelib.h" /* This delay is not the real value, but approximated */ /* time in ms to activate amplifier before use */ #define AMPLIFIER_DELAY 1 /* Time in ms to activate shutter before/after exposure */ #define SHUTTER_DELAY 200 /*=================== DaDa Structure =========================*/ typedef struct { AUD_HANDLE aud_handle; int amplictrl; int amplion; int shutterctrl; int nClear; int running; int error; int schnarch; int width, height; pCounter count; } Delcam, *pDelcam; /*====================== codes =============================================*/ #define NOBEAM -120 #define FAULT -121 /*------------------------------------------------------------------- Configures the HM from the options in pOpt and the HM data structure Returns 1 on success, 0 on failure ---------------------------------------------------------------------*/ static int DelcamConfigure(pHistDriver self, SConnection * pCon, pStringDict pOpt, SicsInterp * pSics) { pDelcam pPriv = NULL; char buffer[80]; int status, w, h; pPriv = (pDelcam) self->pPriv; if (StringDictGet(pOpt, "amplictrl", buffer, 79) == 1) { pPriv->amplictrl = atoi(buffer); } else { pPriv->amplictrl = 0; } if (pPriv->amplictrl < 0 || pPriv->amplictrl > 8) { SCWrite(pCon, "ERROR: invalid amplictrl value, range 0 - 8", eError); pPriv->amplictrl = 0; } if (StringDictGet(pOpt, "amplion", buffer, 79) == 1) { pPriv->amplion = atoi(buffer); } else { pPriv->amplion = 1; } if(pPriv->amplion != 0 && pPriv->amplion != 1){ SCWrite(pCon, "ERROR: invalid amplion value, 0,1 allowed", eError); pPriv->amplion = 1; } if (StringDictGet(pOpt, "shutterctrl", buffer, 79) == 1) { pPriv->shutterctrl = atoi(buffer); } else { pPriv->shutterctrl = 0; } if (StringDictGet(pOpt, "clear", buffer, 79) == 1) { pPriv->nClear = atoi(buffer); } else { pPriv->nClear = 1; } if (StringDictGet(pOpt, "schnarch", buffer, 79) == 1) { pPriv->schnarch = atoi(buffer); } else { pPriv->schnarch = 1; } if (StringDictGet(pOpt, "counter", buffer, 79) == 1) { pPriv->count = (pCounter) FindCommandData(pServ->pSics, buffer, "SingleCounter"); } if (pPriv->count == NULL) { SCWrite(pCon, "ERROR: no slave counter configured: need it desperatly!", eError); return 0; } pPriv->running = 0; if (pPriv->aud_handle == NULL) { pPriv->aud_handle = aud_open(); if (pPriv->aud_handle == NULL) { SCWrite(pCon, "ERROR: failed to open DELCam", eError); return 0; } } status = aud_geometry_get(pPriv->aud_handle, 0, 0, &w, &h, 0); if (status != 0) { snprintf(buffer, 80, "ERROR: errno %d while trying to read geometry", errno); SCWrite(pCon, buffer, eError); return 0; } sprintf(buffer, "%d", w); StringDictUpdate(self->pOption, "dim0", buffer); sprintf(buffer, "%d", h); StringDictUpdate(self->pOption, "dim1", buffer); configureHMdata(self->data, self->pOption, pCon); if (!resizeBuffer(self->data)) { SCWrite(pCon, "ERROR: out of memory allocating HMData for DELCam", eError); return 0; } pPriv->width = w; pPriv->height = h; return 1; } /*-------------------------------------------------------------------- Start histogramming, Returns HWFault on failure, 1 on success ----------------------------------------------------------------------*/ static int DelcamStart(pHistDriver self, SConnection * pCon) { pDelcam pPriv = NULL; int status, i; char buffer[80]; pPriv = (pDelcam) self->pPriv; /* * configure counter */ if (self->eCount != eTimer) { SCWrite(pCon, "WARNING: bad count mode switched to preset time", eWarning); } SetCounterMode(pPriv->count, eTimer); SetCounterPreset(pPriv->count, self->fCountPreset); /* * deal with amplifier */ if (pPriv->amplictrl |= 0) { status = aud_amplifier_ctrl_set(pPriv->aud_handle, pPriv->amplictrl); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to set amplifier, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; return HWFault; } } status = aud_amplifier_set(pPriv->aud_handle, 0); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to start amplifier, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; return HWFault; } usleep(AMPLIFIER_DELAY * 1000); /* * deal with shutter */ if (pPriv->shutterctrl |= 0) { status = aud_shutter_ctrl_set(pPriv->aud_handle, pPriv->shutterctrl); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to set shutterctrl, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; return HWFault; } status = aud_shutter_set(pPriv->aud_handle, 1); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to start shutter, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; return HWFault; } usleep(SHUTTER_DELAY * 1000); } /* * clear */ status = aud_clear(pPriv->aud_handle, pPriv->nClear); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to clear CCD, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; return HWFault; } pPriv->running = 1; clearHMData(self->data); return pPriv->count->pDriv->Start(pPriv->count->pDriv); } /*-------------------------------------------------------------------- Stops histogramming, Returns HWFault on failure, 1 on success ----------------------------------------------------------------------*/ static int DelcamHalt(pHistDriver self) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; return pPriv->count->pDriv->Halt(pPriv->count->pDriv); } /*-------------------------------------------------------------------- Checks histogramming status, Returns HWFault on failure, HWIdle when finished, HWBusy when counting ----------------------------------------------------------------------*/ static int DelcamCountStatus(pHistDriver self, SConnection * pCon) { pDelcam pPriv = NULL; int status, color, imSize = 0, i; float val; char buffer[80]; unsigned short *imData = NULL; char *shittyCompiler = NULL; pPriv = (pDelcam) self->pPriv; status = pPriv->count->pDriv->GetStatus(pPriv->count->pDriv, &val); if (status == HWNoBeam) { /* SCWrite(pCon,"WARNING: NO BEAM, during CCD measurement",eWarning); DelcamHalt(self); pPriv->error = NOBEAM; status = HWFault; */ return HWBusy; } if (status != HWBusy && pPriv->running == 1) { pPriv->count->pDriv->ReadValues(pPriv->count->pDriv); pPriv->running = 0; /* * stop the CCD and transfer data */ if (pPriv->shutterctrl |= 0) { status = aud_shutter_set(pPriv->aud_handle, 0); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to close shutter, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; status = HWFault; } usleep(SHUTTER_DELAY * 1000); } if(pPriv->amplion == 1){ status = aud_amplifier_set(pPriv->aud_handle, 1); if (status != 0) { snprintf(buffer, 80, "ERROR: failed to start amplifier, errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; status = HWFault; } usleep(AMPLIFIER_DELAY*1000); } usleep(pPriv->schnarch * 1000); SCWrite(pCon, "WARNING: starting readout, computer freeze for ~15 sec is normal during readout", eWarning); status = aud_image_read(pPriv->aud_handle, &shittyCompiler, &imSize, &pPriv->width, &pPriv->height, &color); imData = (unsigned short *) shittyCompiler; if (status != 0) { snprintf(buffer, 80, "ERROR: failed to read DELCam with errno = %d", errno); SCWrite(pCon, buffer, eError); pPriv->error = FAULT; status = HWFault; } if (imData != NULL) { for (i = 0; i < pPriv->width * pPriv->height; i++) { self->data->localBuffer[i] = (int) imData[i]; } free(imData); } SCWrite(pCon, "WARNING: CCD read",eWarning); } return status; } /*-------------------------------------------------------------------- Get info on error after last HWFault, returns 1 always. Puts an int error code into *code and errLen chars of error description into error ----------------------------------------------------------------------*/ static int DelcamGetError(pHistDriver self, int *code, char *error, int errLen) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; switch (pPriv->error) { case FAULT: snprintf(error, errLen, "ERROR: DELcam fault"); *code = FAULT; break; case NOBEAM: snprintf(error, errLen, "ERROR: ABORT for beam interruption"); *code = FAULT; break; default: return pPriv->count->pDriv->GetError(pPriv->count->pDriv, code, error, errLen); } return 0; } /*-------------------------------------------------------------------- Try to fix the HM error in code. Returns COREDO when the last operation needs to be redone, COTERM when the error cannot be fixed. ----------------------------------------------------------------------*/ static int DelcamFixIt(pHistDriver self, int code) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; switch (code) { case FAULT: case NOBEAM: return COTERM; break; default: return pPriv->count->pDriv->TryAndFixIt(pPriv->count->pDriv, code); break; } return COTERM; } /*-------------------------------------------------------------------- GetData reads updates the internal cache of monitor values from the hardware, Returns 1 or HWFault ----------------------------------------------------------------------*/ static int DelcamGetData(pHistDriver self, SConnection * pCon) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; return 1; } /*-------------------------------------------------------------------- GetMonitor reads the monitor value i. Returns either the monitor value or -9999 if no such monitor exists or an error occurred ----------------------------------------------------------------------*/ static long DelcamGetMonitor(pHistDriver self, int i, SConnection * pCon) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; return GetMonitor(pPriv->count, i, pCon); } /*-------------------------------------------------------------------- GetTime reads the total counting time. Returns either the value or -9999.99 if no such value exists or an error occurred ----------------------------------------------------------------------*/ static float DelcamGetTime(pHistDriver self, SConnection * pCon) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; return GetCountTime(pPriv->count, pCon); } /*-------------------------------------------------------------------- Pause histogramming, Returns HWFault on failure, 1 on success ----------------------------------------------------------------------*/ static int DelcamPause(pHistDriver self, SConnection * pCon) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; SCWrite(pCon, "WARNING: pausing pointless for CCD, IGNORED!", eWarning); return 1; } /*-------------------------------------------------------------------- Continue histogramming, Returns HWFault on failure, 1 on success ----------------------------------------------------------------------*/ static int DelcamContinue(pHistDriver self, SConnection * pCon) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; SCWrite(pCon, "WARNING: pausing pointless for CCD, IGNORED!", eWarning); return 1; } /*-------------------------------------------------------------------- Free the data associated with the private data structure of the driver ----------------------------------------------------------------------*/ static int DelcamFree(pHistDriver self) { pDelcam pPriv = NULL; pPriv = (pDelcam) self->pPriv; aud_close(pPriv->aud_handle); free(pPriv); return 1; } /*-------------------------------------------------------------------- Set The HM data or a subset of it. Returns HWFault or 1 ----------------------------------------------------------------------*/ static int DelcamSetHistogram(pHistDriver self, SConnection * pCon, int i, int iStart, int iEnd, HistInt * pData) { pDelcam pPriv = NULL; int j; pPriv = (pDelcam) self->pPriv; SCWrite(pCon, "WARNING: driver does not support setting HM", eWarning); return 1; } /*-------------------------------------------------------------------- Set HM to a preset value, Returns HWFault on failure, 1 on success ----------------------------------------------------------------------*/ static int DelcamPreset(pHistDriver self, SConnection * pCon, HistInt value) { pDelcam pPriv = NULL; int j; pPriv = (pDelcam) self->pPriv; for (j = 0; j < pPriv->width * pPriv->height; j++) { self->data->localBuffer[j] = value; } return 1; } /*-------------------------------------------------------------------- get The HM data or a subset of it. Returns HWFault or 1 ----------------------------------------------------------------------*/ static int DelcamGetHistogram(pHistDriver self, SConnection * pCon, int i, int iStart, int iEnd, HistInt * pData) { pDelcam pPriv = NULL; HistInt *data = NULL; pPriv = (pDelcam) self->pPriv; data = self->data->localBuffer + iStart; if (iEnd > getHMDataLength(self->data) || iStart < 0) { SCWrite(pCon, "ERROR: data length out of range", eError); return 0; } memcpy(pData, data, (iEnd - iStart) * sizeof(HistInt)); return 1; } /*-------------------------------------------------------------------- Make the HMDriver, returns a driver or NULL on failure ----------------------------------------------------------------------*/ pHistDriver MakeDelcamHM(pStringDict pOption) { pHistDriver pNew = NULL; pDelcam pPriv = NULL; /* create the general driver */ pNew = CreateHistDriver(pOption); if (!pNew) { return NULL; } /*Create private data structure */ pPriv = NULL; pPriv = (pDelcam) malloc(sizeof(Delcam)); if (pPriv == NULL) { return NULL; } memset(pPriv, 0, sizeof(Delcam)); pPriv->width = 768; pPriv->height = 512; pNew->pPriv = pPriv; /* add our options */ StringDictAddPair(pOption, "amplictrl", "0"); StringDictAddPair(pOption, "amplion", "1"); StringDictAddPair(pOption, "shutterctrl", "0"); StringDictAddPair(pOption, "clear", "1"); StringDictAddPair(pOption, "schnarch", "1"); StringDictAddPair(pOption, "counter", "unkown"); /* configure all those functions */ pNew->Configure = DelcamConfigure; pNew->Start = DelcamStart; pNew->Halt = DelcamHalt; pNew->GetCountStatus = DelcamCountStatus; pNew->GetError = DelcamGetError; pNew->TryAndFixIt = DelcamFixIt; pNew->GetData = DelcamGetData; pNew->GetHistogram = DelcamGetHistogram; pNew->SetHistogram = DelcamSetHistogram; pNew->GetMonitor = DelcamGetMonitor; pNew->GetTime = DelcamGetTime; pNew->Preset = DelcamPreset; pNew->FreePrivate = DelcamFree; pNew->Pause = DelcamPause; pNew->Continue = DelcamContinue; return pNew; }