Files
sicspsi/delcam.c
koennecke ccae9f0d16 - Currently disabled attempts at logging commands
- Added a warning for excessive data rates on monitors
- Added statistics to devser and thus to scriptcontext
- Added byte concatenation to dynstring
- Added aborting for reflection generation to fourmess.c
- Added data checksum testing to hipadaba, use for update tests
- Fixed interrupt discovery in network.c, caused invalid interrupt
  codes which in turn confused sicscron which had to be fixed too.
- Renamed ubcalc into ubcalcint in order to reclaim the ubcalc for Jurg
- Added an a3offset to tasub in order to fix what I perceive an IS problem
- Added support for the newer version of the Siemens SPS, the S7
- Added a not yet fully working sinqhttpopt driver which talks to
  http HM without libghttp
2010-12-20 10:18:03 +00:00

551 lines
17 KiB
C

/*-----------------------------------------------------------------------------
* 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 <errno.h>
#include <unistd.h>
#include <sics.h>
#include <countdriv.h>
#include <counter.h>
#include <HistMem.h>
#include <stringdict.h>
#include <HistDriv.i>
#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;
}