diff --git a/ecbcounter.c b/ecbcounter.c new file mode 100644 index 0000000..6158b8a --- /dev/null +++ b/ecbcounter.c @@ -0,0 +1,586 @@ +/*---------------------------------------------------------------------------- + This is a single counter implemented on top of the Risoe ECB electronic + + copyright: see file COPYRIGHT + + Mark Koennecke, January-February 2003 + ---------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ecb.h" +#include + +/*------------------ our private data structure ------------------------*/ +typedef struct { + pECB ecb; /* the ECB system we talk to */ + unsigned char prescaler[8]; /* an array for the prescaler values */ + int tfreq; /* timer frequency */ + unsigned char control; /* marks the control monitor */ + int state; /* current counting state */ +}ECBCounter, *pECBCounter; + +/*----------------- private defines ------------------------------------*/ +#define STFRD 137 +#define STREAD 138 +#define STOPS 136 +#define STCLEA 134 +#define PRELOA 139 +#define STLOAD 156 +#define STCPRE 133 +#define STARTS 135 +#define SPCSTA 169 + +/*------------------ state codes --------------------------------------*/ +#define IDLE 0 +#define COUNT 2 +#define NOBEAM 3 +/*--------------------------------------------------------------------*/ +#define MAX_COUNT 4294967295.0 +/*------------------ error codes --------------------------------------*/ +#define COMMERROR -300 +#define TOMANYCOUNTS -301 +#define NOSEND -302 +#define INVALIDCOUNTER -304 +#define INVALIDPRESCALER -305 +#define BADFREQ -306 +/*======================================================================*/ +static int readScaler(pECBCounter pPriv, int scaler, int *count){ + int status; + Z80_reg in, out; + Ecb_pack data; + + in.c = (unsigned char)scaler; + status = ecbExecute(pPriv->ecb,STREAD,in,&out); + if(status != 1){ + return COMMERROR; + } + + data.b.byt3 = out.c; + data.b.byt2 = out.b; + data.b.byt1 = out.d; + data.b.byt0 = out.e; + if(scaler == 0){ + *count = data.result/pPriv->tfreq; + } else { + *count = data.result; + } + + return 1; +} +/*---------------------------------------------------------------------*/ +static int check4Beam(struct __COUNTER *pCter, int *beam){ + Z80_reg in, out; + pECBCounter self = NULL; + int status; + + self = (pECBCounter)pCter->pData; + assert(self); + + in.c = 1; + status = ecbExecute(self->ecb,SPCSTA,in,&out); + if(status != 1){ + pCter->iErrorCode = COMMERROR; + return HWFault; + } + *beam = (int)out.d; + return 1; +} +/*----------------------------------------------------------------------*/ +static int stopScalers(pECBCounter self){ + int status; + Z80_reg in, out; + + status = ecbExecute(self->ecb,STOPS,in,&out); + if(status != 1){ + return COMMERROR; + } + return 1; +} +/*======================================================================== + These two functions currently rely on the idea that the ECB stops + and starts without clearing counters in between. The sequence of + things necessary to start it, suggests this. If this is not the case then + this will not work. +===========================================================================*/ +static int ECBPause(struct __COUNTER *self){ + int status; + pECBCounter pPriv = NULL; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + if((status = stopScalers(pPriv)) <= 0){ + self->iErrorCode = status; + return HWFault; + } + return OKOK; +} +/*=======================================================================*/ +static int ECBContinue(struct __COUNTER *self){ + int status; + pECBCounter pPriv = NULL; + Z80_reg in, out; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + status = ecbExecute(pPriv->ecb,STARTS,in,&out); + if(status != 1){ + self->iErrorCode = status; + return HWFault; + } + + return OKOK; +} +/*-----------------------------------------------------------------------*/ +static int ECBGetStatus(struct __COUNTER *self, float *fControl){ + pECBCounter pPriv = (pECBCounter)self->pData; + int status, result, scaler; + Z80_reg in, out; + int count, beam; + + assert(pPriv); + + /* + This can happen after a stop + */ + if(pPriv->state == IDLE){ + return HWIdle; + } + + /* + read status bit + */ + status = ecbExecute(pPriv->ecb,STFRD,in,&out); + if(status != 1){ + self->iErrorCode = COMMERROR; + pPriv->state = IDLE; + return HWFault; + } + /* + read beam status + */ + status = check4Beam(self,&beam); + if(status != 1){ + self->iErrorCode = COMMERROR; + return HWFault; + } + beam &= 1; + + /* + sophisticated logic in order to keep track of the various states + the thing can be in. Complicated by the fact that the status becomes + idle (out.d = 0) when the measurement is paused due to the lack of + beam. + */ + if(pPriv->state == COUNT && beam == 1){ + ECBPause(self); + pPriv->state = NOBEAM; + SetStatus(eOutOfBeam); + result = HWNoBeam; + } + if(pPriv->state == NOBEAM && beam == 0){ + ECBContinue(self); + pPriv->state = COUNT; + SetStatus(eCounting); + return HWBusy; + } + if(pPriv->state == NOBEAM && beam == 1){ + return HWNoBeam; + } + if(out.d == 0 && pPriv->state == COUNT){ + result = HWIdle; + pPriv->state = IDLE; + } else { + result = HWBusy; + } + + + /* + select which scaler to read + */ + if(self->eMode == eTimer){ + scaler = 0; + }else { + scaler = pPriv->control; + } + + readScaler(pPriv,scaler,&count); + /* + ignore errors on this one + */ + *fControl = (float)count; + + return result; +} +/*=====================================================================*/ +static int clearScalers(pECBCounter self){ + int status; + Z80_reg in, out; + + status = ecbExecute(self->ecb,STCLEA,in,&out); + if(status != 1){ + return COMMERROR; + } + return 1; +} +/*----------------------------------------------------------------------*/ +static int loadPrescalers(pECBCounter self){ + Z80_reg in, out; + int status, i; + + for(i = 0; i < 8; i++){ + in.c = (unsigned char)i; + in.d = self->prescaler[i]; + status = ecbExecute(self->ecb,PRELOA,in,&out); + if(status != 1){ + return COMMERROR; + } + } + return 1; +} +/*----------------------------------------------------------------------*/ +static int loadPreset(pECBCounter self, int preset, unsigned char control){ + Z80_reg in, out; + Ecb_pack data; + int status, i; + + data.result = preset; + + in.c = data.b.byt3; + in.b = data.b.byt2; + in.e = data.b.byt1; + in.d = data.b.byt0; + status = ecbExecute(self->ecb,STLOAD,in,&out); + if(status != 1){ + return COMMERROR; + } + + in.b = data.b.byt2; + in.e = data.b.byt1; + in.d = data.b.byt0; + in.c = 4*control; + status = ecbExecute(self->ecb,STCPRE,in,&out); + if(status != 1){ + return COMMERROR; + } + return 1; +} +/*-----------------------------------------------------------------------*/ +static int ECBStart(struct __COUNTER *self){ + pECBCounter pPriv = NULL; + int preset, status, controlUnit; + Z80_reg in, out; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + /* + check if the preset is permissible + */ + preset = (int)rint(self->fPreset); + if(preset > MAX_COUNT){ + self->iErrorCode = TOMANYCOUNTS; + return HWFault; + } + if(self->eMode == eTimer){ + controlUnit = 0; + preset *= pPriv->tfreq; + if(preset > MAX_COUNT){ + self->iErrorCode = TOMANYCOUNTS; + return HWFault; + } + } else { + controlUnit = pPriv->control; + } + + if((status = stopScalers(pPriv)) <= 0){ + self->iErrorCode = status; + return HWFault; + } + + if((status = clearScalers(pPriv)) <= 0){ + self->iErrorCode = status; + return HWFault; + } + + if((status = loadPrescalers(pPriv)) <= 0){ + self->iErrorCode = status; + return HWFault; + } + + if((status = loadPreset(pPriv, preset,(unsigned char)controlUnit)) <= 0){ + self->iErrorCode = status; + return HWFault; + } + + status = ecbExecute(pPriv->ecb,STARTS,in,&out); + if(status != 1){ + self->iErrorCode = status; + return HWFault; + } + + pPriv->state = COUNT; + return OKOK; +} +/*=======================================================================*/ +static int ECBHalt(struct __COUNTER *self){ + int status; + pECBCounter pPriv = NULL; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + pPriv->state = IDLE; + if((status = stopScalers(pPriv)) <= 0){ + self->iErrorCode = status; + return HWFault; + } + return OKOK; +} +/*=======================================================================*/ +static int ECBTransfer(struct __COUNTER *self){ + int status, count, i; + pECBCounter pPriv = NULL; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + /* + read time + */ + status = readScaler(pPriv,0,&count); + if(status <= 0){ + self->iErrorCode = COMMERROR; + return HWFault; + } + self->fTime = (float)count; + + /* + read other scalers + */ + for(i = 1; i < 8; i++){ + status = readScaler(pPriv,i,&count); + if(status <= 0){ + self->iErrorCode = COMMERROR; + return HWFault; + } + self->lCounts[i-1] = count; + } + return OKOK; +} +/*======================================================================*/ +static int ECBGetError(struct __COUNTER *self, int *iCode, + char *errorText, int errlen){ + char pBueffel[132]; + + *iCode = self->iErrorCode; + switch(self->iErrorCode){ + case COMMERROR: + strncpy(errorText,"Communication error with ECB",errlen); + break; + case TOMANYCOUNTS: + strncpy(errorText,"Preset is to high!",errlen); + break; + case NOSEND: + strncpy(errorText,"Cannot send naked data to ECB",errlen); + break; + case UNKNOWNPAR: + strncpy(errorText,"parameter unknown",errlen); + break; + case INVALIDCOUNTER: + strncpy(errorText,"Invalid counter number requested, 0-7 allowed", + errlen); + break; + case INVALIDPRESCALER: + strncpy(errorText,"Invalid prescaler value, allowed 1 or 10", + errlen); + break; + case BADFREQ: + strncpy(errorText,"Bad timer frequency: 10 or 1000 allowed",errlen); + break; + default: + sprintf(pBueffel,"Unknown error code %d", self->iErrorCode); + strncpy(errorText,pBueffel,errlen); + break; + } + return 1; +} +/*=======================================================================*/ +static int ECBFixIt(struct __COUNTER *self, int iCode){ + return COTERM; +} +/*======================================================================*/ + +/******************************************************************************* +* Load the parameters 'dot' and 'divide' for a motor or an encoder. +* 'dot' specifies the placement of a punctuation mark on the display +* of f.ex a motor position. 'divide' specifies how many times the po- +* sition is to be divided by two before it is displayed. +******************************************************************************/ +static void +Dot_divide (int device, int data, pECB ecb) +{ + int function, dot, divide; + Z80_reg x_inreg, out; + + if (data == 0) /* If zero, dont send dot/divide) */ + return; + + dot = 0; + while ((data%10) == 0) + { + dot++; + data /= 10; + } + divide = 0; + while ((data%2) == 0) + { + divide++; + data /= 2; + } + if (data != 1) /* If != 1, not a binary No. */ + return; + if (dot > 0) + dot = 8 - dot; + x_inreg.c = 0; /* Specify input */ + x_inreg.b = (unsigned char) device; + x_inreg.d = (unsigned char) dot; /* Dot position */ + x_inreg.e = (unsigned char) divide; /* No. of times to divide by 2 */ + + ecbExecute(ecb,170,x_inreg,&out); + return; +} +/*-----------------------------------------------------------------------*/ +static int ECBSet(struct __COUNTER *self, char *name, + int iCter, float fVal){ + pECBCounter pPriv = NULL; + int iVal; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + iVal = (int)rint(fVal); + + if(strcmp(name,"prescaler") == 0){ + if(iCter < 0 || iCter > 7){ + self->iErrorCode = INVALIDCOUNTER; + return HWFault; + } + if(iVal != 1 && iVal != 10){ + self->iErrorCode = INVALIDPRESCALER; + return HWFault; + } + pPriv->prescaler[iCter] = (unsigned char)iVal; + return OKOK; + } else if(strcmp(name,"tfreq") == 0){ + if(fVal == 1000){ + pPriv->prescaler[0] = 1; + pPriv->tfreq = 1000; + Dot_divide(64,1000,pPriv->ecb); + return OKOK; + } else if(fVal == 10){ + pPriv->tfreq = 10; + pPriv->prescaler[0] = 10; + Dot_divide(64,10,pPriv->ecb); + return OKOK; + } else { + self->iErrorCode = BADFREQ; + return HWFault; + } + } else { + self->iErrorCode = UNKNOWNPAR; + return HWFault; + } +} +/*===================================================================*/ +static int ECBGet(struct __COUNTER *self, char *name, + int iCter, float *fVal){ + pECBCounter pPriv = NULL; + + assert(self); + pPriv = (pECBCounter)self->pData; + assert(pPriv); + + if(strcmp(name,"prescaler") == 0){ + *fVal = (float)pPriv->prescaler[iCter]; + return OKOK; + } else if(strcmp(name,"tfreq") == 0){ + *fVal = (float)pPriv->tfreq; + return OKOK; + } else{ + self->iErrorCode = UNKNOWNPAR; + return HWFault; + } +} +/*=====================================================================*/ +static int ECBSend(struct __COUNTER *self, char *text, + char *reply, int replylen){ + strncpy(reply,"ECB does not feast on ASCII strings, refused!", + replylen); + return OKOK; +} +/*====================================================================*/ +pCounterDriver MakeECBCounter(char *ecb){ + pECBCounter pPriv = NULL; + pCounterDriver self = NULL; + int i; + + /* + memory for everybody + */ + self = CreateCounterDriver("ecb","ecb"); + pPriv = (pECBCounter)malloc(sizeof(ECBCounter)); + if(self == NULL || pPriv == NULL){ + return NULL; + } + memset(pPriv,0,sizeof(ECBCounter)); + + /* + initialize private data structure + */ + pPriv->ecb = (pECB)FindCommandData(pServ->pSics,ecb,"ECB"); + if(pPriv->ecb == NULL){ + DeleteCounterDriver(self); + free(pPriv); + return NULL; + } + for(i = 0; i < 8; i++){ + pPriv->prescaler[i] = 1; + } + pPriv->tfreq = 1000; + pPriv->control = 1; + + + /* + assign function pointers + */ + self->GetStatus = ECBGetStatus; + self->Start = ECBStart; + self->Pause = ECBPause; + self->Continue = ECBContinue; + self->Halt = ECBHalt; + self->ReadValues = ECBTransfer; + self->GetError = ECBGetError; + self->TryAndFixIt = ECBFixIt; + self->Set = ECBSet; + self->Get = ECBGet; + self->Send = ECBSend; + self->KillPrivate = NULL; + + self->pData = pPriv; + return self; +} diff --git a/ecbcounter.h b/ecbcounter.h new file mode 100644 index 0000000..eb12145 --- /dev/null +++ b/ecbcounter.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + Header file for the counter driver for the Risoe ECB system. + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2003 + -------------------------------------------------------------------------*/ + +#ifndef ECBCOUNTER +#define ECBCOUNTER + +#include "countdriv.h" + +pCounterDriver MakeECBCounter(char *ecb); +void KillECBCounter(CounterDriver *pDriv); + +#endif diff --git a/el737driv.c b/el737driv.c new file mode 100644 index 0000000..b36f99a --- /dev/null +++ b/el737driv.c @@ -0,0 +1,693 @@ +/*---------------------------------------------------------------------- + This is driver for a standard PSI EL737 counter box as used at + SINQ + + copyright: see file COPYRIGHT + + extracted from countdriv.c. Mark Koennecke, June 2003 + -----------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "hardsup/sinq_prototypes.h" +#include "hardsup/el737_def.h" +#include "hardsup/el737fix.h" +/*----------------------------- EL737 ------------------------------------*/ + typedef struct { + char *host; + int iPort; + int iChannel; + void *pData; + int finishCount; + } EL737st; +/*------------------------------------------------------------------------*/ + static int EL737GetStatus(struct __COUNTER *self, float *fControl) + { + int iRet; + int iC1, iC2, iC3,iC4,iRS; + float fTime; + EL737st *pEL737; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS); + if(self->eMode == eTimer) + { + *fControl = fTime; + } + else + { + *fControl = iC1; + } + /* store time */ + self->fTime = fTime; + + if(iRet != 1) + { + return HWFault; + } + self->lCounts[0] = iC2; + self->lCounts[1] = iC1; + self->lCounts[2] = iC3; + self->lCounts[3] = iC4; + + /* get extra counters for 8-fold counter boxes */ + iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4); + self->lCounts[4] = iC1; + self->lCounts[5] = iC2; + self->lCounts[6] = iC3; + self->lCounts[7] = iC4; + if(iRS == 0) + { + pEL737->finishCount++; + if(pEL737->finishCount >= 2) + { + return HWIdle; + } + else + { + return HWBusy; + } + } + else if((iRS == 1) || (iRS == 2)) + { + pEL737->finishCount = 0; + return HWBusy; + } + else if( (iRS == 5) || (iRS == 6)) + { + pEL737->finishCount = 0; + return HWNoBeam; + } + else + { + pEL737->finishCount = 0; + return HWPause; + } + } +#ifdef NONINTF + extern float nintf(float f); +#endif +/*-------------------------------------------------------------------------*/ + static int EL737Start(struct __COUNTER *self) + { + int iRet, iRS; + EL737st *pEL737; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + + self->fTime = 0.; + + if(self->eMode == ePreset) + { + iRet = EL737_StartCnt(&pEL737->pData,(int)nintf(self->fPreset),&iRS); + if(iRet == 1) + { + pEL737->finishCount = 0; + return OKOK; + } + else + { + return HWFault; + } + } + else if(self->eMode == eTimer) + { + iRet = EL737_StartTime(&pEL737->pData,self->fPreset,&iRS); + if(iRet == 1) + { + pEL737->finishCount = 0; + return OKOK; + } + else + { + return HWFault; + } + } + return 0; + } +/*-------------------------------------------------------------------------*/ + static int EL737Pause(struct __COUNTER *self) + { + int iRet, iRS; + EL737st *pEL737; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + + iRet = EL737_Pause(&pEL737->pData,&iRS); + if(iRet == 1) + { + return OKOK; + } + else + { + return HWFault; + } + return 0; + } +/*-------------------------------------------------------------------------*/ + static int EL737Continue(struct __COUNTER *self) + { + int iRet, iRS; + EL737st *pEL737; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + + iRet = EL737_Continue(&pEL737->pData,&iRS); + if(iRet == 1) + { + return OKOK; + } + else + { + return HWFault; + } + return 0; + } +/*--------------------------------------------------------------------------*/ + static int EL737Halt(struct __COUNTER *self) + { + int iRet, iC1, iC2, iC3, iC4,iRS; + float fPreset; + EL737st *pEL737; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + + + iRet = EL737_Stop(&pEL737->pData,&iC1, &iC2,&iC3,&iC4,&fPreset,&iRS); + if(iRet == 1) + { + self->lCounts[0] = iC2; + self->lCounts[1] = iC1; + self->lCounts[2] = iC3; + self->lCounts[3] = iC4; + return OKOK; + } + return HWFault; + } +/*--------------------------------------------------------------------------*/ + static int EL737ReadValues(struct __COUNTER *self) + { + int iRet; + int iC1, iC2, iC3,iC4,iRS; + float fTime; + EL737st *pEL737; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + + iRet = EL737_GetStatus(&pEL737->pData,&iC1,&iC2,&iC3,&iC4,&fTime,&iRS); + if(iRet != 1) + { + return HWFault; + } + self->fTime = fTime; + + self->lCounts[0] = iC2; + self->lCounts[1] = iC1; + self->lCounts[2] = iC3; + self->lCounts[3] = iC4; + /* get extra counters for 8-fold counter boxes */ + iRet = EL737_GetStatusExtra(&pEL737->pData,&iC1,&iC2,&iC3,&iC4); + self->lCounts[4] = iC1; + self->lCounts[5] = iC2; + self->lCounts[6] = iC3; + self->lCounts[7] = iC4; + + return OKOK; + } +/*--------------------------------------------------------------------------- + + EL737Error2Text converts between an EL734 error code to text +-----------------------------------------------------------------------------*/ + static void EL737Error2Text(char *pBuffer, int iErr) + { + switch(iErr) + { + case EL737__BAD_ADR: + strcpy(pBuffer,"EL737__BAD_ADR"); + break; + case EL737__BAD_OVFL: + strcpy(pBuffer,"EL737__BAD_OVFL"); + break; + case EL737__BAD_BSY: + strcpy(pBuffer,"EL737__BAD_BSY"); + break; + case EL737__BAD_SNTX: + strcpy(pBuffer,"EL737__BAD_SNTX"); + break; + case EL737__BAD_CONNECT: + strcpy(pBuffer,"EL737__BAD_CONNECT"); + break; + case EL737__BAD_FLUSH: + strcpy(pBuffer,"EL737__BAD_FLUSH"); + break; + case EL737__BAD_DEV: + strcpy(pBuffer,"EL734__BAD_DEV"); + break; + case EL737__BAD_ID: + strcpy(pBuffer,"EL737__BAD_ID"); + break; + case EL737__BAD_ILLG: + strcpy(pBuffer,"EL737__BAD_ILLG"); + break; + case EL737__BAD_LOC: + strcpy(pBuffer,"EL737__BAD_LOC"); + break; + case EL737__BAD_MALLOC: + strcpy(pBuffer,"EL737__BAD_MALLOC"); + break; + case EL737__BAD_NOT_BCD: + strcpy(pBuffer,"EL737__BAD_NOT_BCD"); + break; + case EL737__BAD_OFL: + strcpy(pBuffer,"EL737__BAD_OFL"); + break; + case EL737__BAD_PAR: + strcpy(pBuffer,"EL737__BAD_PAR"); + break; + + case EL737__BAD_RECV: + strcpy(pBuffer,"EL737__BAD_RECV"); + break; + case EL737__BAD_RECV_NET: + strcpy(pBuffer,"EL737__BAD_RECV_NET"); + break; + case EL737__BAD_RECV_PIPE: + strcpy(pBuffer,"EL737__BAD_RECV_PIPE"); + break; + case EL737__BAD_RECV_UNKN: + strcpy(pBuffer,"EL737__BAD_RECV_UNKN"); + break; + case EL737__BAD_RECVLEN: + strcpy(pBuffer,"EL737__BAD_RECVLEN"); + break; + case EL737__BAD_RECV1: + strcpy(pBuffer,"EL737__BAD_RECV1"); + break; + case EL737__BAD_RECV1_NET: + strcpy(pBuffer,"EL737__BAD_RECV1_NET"); + break; + case EL737__BAD_RECV1_PIPE: + strcpy(pBuffer,"EL737__BAD_RECV1_PIPE"); + break; + case EL737__BAD_RNG: + strcpy(pBuffer,"EL737__BAD_RNG"); + break; + case EL737__BAD_SEND: + strcpy(pBuffer,"EL737__BAD_SEND"); + break; + case EL737__BAD_SEND_PIPE: + strcpy(pBuffer,"EL737__BAD_SEND_PIPE"); + break; + case EL737__BAD_SEND_NET: + strcpy(pBuffer,"EL737__BAD_SEND_NET"); + break; + case EL737__BAD_SEND_UNKN: + strcpy(pBuffer,"EL737__BAD_SEND_UNKN"); + break; + case EL737__BAD_SENDLEN: + strcpy(pBuffer,"EL737__BAD_SENDLEN"); + break; + case EL737__BAD_SOCKET: + strcpy(pBuffer,"EL737__BAD_SOCKET"); + break; + case EL737__BAD_TMO: + strcpy(pBuffer,"EL737__BAD_TMO"); + break; + case EL737__FORCED_CLOSED: + strcpy(pBuffer,"EL737__FORCED_CLOSED"); + break; + case EL737__BAD_ASYNSRV: + strcpy(pBuffer,"EL737__BAD_ASYNSRV"); + break; + default: + sprintf(pBuffer,"Unknown EL737 error %d", iErr); + break; + } + } + +/*--------------------------------------------------------------------------*/ + static int EL737GetError(struct __COUNTER *self, int *iCode, + char *error, int iErrLen) + { + char *pErr = NULL; + int iC1, iC2, iC3; + char pBueffel[256]; + + if(self->iErrorCode == UNKNOWNPAR) + { + strncpy(error,"unknown internal parameter code",iErrLen); + *iCode = self->iErrorCode; + self->iErrorCode = 0; + return 1; + } + else if(self->iErrorCode == BADCOUNTER) + { + strncpy(error,"monitor cannot be selected",iErrLen); + *iCode = self->iErrorCode; + self->iErrorCode = 0; + return 1; + } + + EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3); + EL737Error2Text(pBueffel,iC1); + + strncpy(error,pBueffel,iErrLen); + *iCode = iC1; + return 1; + } +/*--------------------------------------------------------------------------*/ + static int EL737TryAndFixIt(struct __COUNTER *self, int iCode) + { + EL737st *pEL737; + int iRet; + char pCommand[50], pReply[50]; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + switch(iCode) + { + case EL737__BAD_ILLG: + case EL737__BAD_ADR: + case EL737__BAD_PAR: + case EL737__BAD_TMO: + case EL737__BAD_REPLY: + case EL737__BAD_SNTX: + case EL737__BAD_OVFL: + return COREDO; + break; + case EL737__BAD_BSY: + strcpy(pCommand,"S \r"); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49); + if(iRet < 0) + { + return COTERM; + } + else + { + return COREDO; + } + break; + case EL737__BAD_LOC: + strcpy(pCommand,"rmt 1\r"); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49); + if(iRet < 0) + { + return COTERM; + } + strcpy(pCommand,"echo 2\r"); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49); + if(iRet < 0) + { + return COTERM; + } + strcpy(pCommand,"ra\r"); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,49); + if(iRet < 0) + { + return COTERM; + } + return COREDO; + break; + case EL737__BAD_DEV: + case EL737__BAD_ID: + case EL737__BAD_NOT_BCD: + case UNKNOWNPAR: + case BADCOUNTER: + return COTERM; + break; + case EL737__FORCED_CLOSED: + iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort, + pEL737->iChannel); + if(iRet == 1) + { + return COREDO; + } + else + { + return COTERM; + } + break; + case EL737__BAD_OFL: + EL737_Close(&pEL737->pData,0); + iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort, + pEL737->iChannel); + if(iRet == 1) + { + return COREDO; + } + else + { + return COTERM; + } + break; +/* case EL737__BAD_ASYNSRV: + EL737_Close(&pEL737->pData,1); + return COREDO; +*/ default: + /* try to reopen connection */ + + EL737_Close(&pEL737->pData,1); + iRet = EL737_Open(&pEL737->pData,pEL737->host, pEL737->iPort, + pEL737->iChannel); + if(iRet == 1) + { + return COREDO; + } + else + { + return COTERM; + } + break; + } + return COTERM; + } +/*-------------------------------------------------------------------------*/ + static int EL737Set(struct __COUNTER *self, char *name, int iCter, + float fVal) + { + int iRet; + EL737st *pEL737; + char pCommand[80],pReply[80]; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + if(strcmp(name,"threshold") == 0) + { + sprintf(pCommand,"DL %1.1d %f\r",iCter,fVal); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79); + if(iRet == 1) + { + if(pCommand[0] == '?') + { + self->iErrorCode = BADCOUNTER; + return HWFault; + } + } + else + { + return HWFault; + } + sprintf(pCommand,"DR %1.1d \r",iCter); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79); + if(iRet == 1) + { + if(pCommand[0] == '?') + { + self->iErrorCode = BADCOUNTER; + return HWFault; + } + return OKOK; + } + else + { + return HWFault; + } + } + else + { + self->iErrorCode = UNKNOWNPAR; + return HWFault; + } + } +/*-------------------------------------------------------------------------*/ + static int EL737Get(struct __COUNTER *self, char *name, int iCter, + float *fVal) + { + int iRet; + EL737st *pEL737; + char pCommand[80],pReply[80]; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + if(strcmp(name,"threshold") == 0) + { + sprintf(pCommand,"DL %1.1d\r",iCter); + iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79); + if(iRet == 1) + { + if(pReply[0] == '?') + { + self->iErrorCode = BADCOUNTER; + return HWFault; + } + sscanf(pReply,"%f",fVal); + return OKOK; + } + else + { + return HWFault; + } + } + else + { + self->iErrorCode = UNKNOWNPAR; + return HWFault; + } + } +/*-------------------------------------------------------------------------*/ + static int EL737Send(struct __COUNTER *self, char *pText, char *pReply, + int iReplyLen) + { + EL737st *pEL737; + char pBuffer[256]; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + /* ensure a \r at the end of the text */ + if(strlen(pText) > 254) + { + strncpy(pReply,"Command to long",iReplyLen); + return 1; + } + strcpy(pBuffer,pText); + if(strchr(pBuffer,(int)'\r') == NULL) + { + strcat(pBuffer,"\r"); + } + + return EL737_SendCmnd(&pEL737->pData,pBuffer,pReply,iReplyLen); + } +/*-------------------------------------------------------------------------*/ +pCounterDriver CreateEL737Counter(SConnection *pCon, char *name, + int argc, char *argv[]){ + char *pHost; + int iPort, iChannel; + + if(argc < 3){ + SCWrite(pCon, + "ERROR: insuficient number of arguments to create EL737 counter", + eError); + return NULL; + } + if(!isNumeric(argv[1]) || !isNumeric(argv[2])){ + SCWrite(pCon,"ERROR: expected numeric arguments for port and channel", + eError); + return NULL; + } + iPort = atoi(argv[1]); + iChannel = atoi(argv[2]); + return NewEL737Counter(name,argv[0],iPort,iChannel); +} +/*--------------------------------------------------------------------------*/ + pCounterDriver NewEL737Counter(char *name, char *host, int iPort, int iChannel) + { + pCounterDriver pRes = NULL; + EL737st *pData = NULL; + int iRet; + int iC1, iC2, iC3; + char *pErr; + char pBueffel[132]; + + pRes = CreateCounterDriver(name, "EL737"); + if(!pRes) + { + return NULL; + } + + /* open connection to counter */ + pData = (EL737st *)malloc(sizeof(EL737st)); + if(!pData) + { + DeleteCounterDriver(pRes); + return NULL; + } + pData->host = strdup(host); + pData->iPort = iPort; + pData->iChannel = iChannel; + pData->pData = NULL; + iRet = EL737_Open(&(pData->pData), host,iPort,iChannel); + if(iRet != 1) + { + EL737_ErrInfo(&pErr,&iC1,&iC2, &iC3); + DeleteCounterDriver(pRes); + if(pData->host) + { + free(pData->host); + } + return NULL; + } + pRes->pData = (void *)pData; + + /* assign functions */ + pRes->GetStatus = EL737GetStatus; + pRes->Start = EL737Start; + pRes->Halt = EL737Halt; + pRes->ReadValues = EL737ReadValues; + pRes->GetError = EL737GetError; + pRes->TryAndFixIt = EL737TryAndFixIt; + pRes->Pause = EL737Pause; + pRes->Continue = EL737Continue; + pRes->Set = EL737Set; + pRes->Get = EL737Get; + pRes->Send = EL737Send; + pRes->KillPrivate = KillEL737Counter; + pRes->iNoOfMonitors = 7; + pRes->fTime = 0.; + + return pRes; +} +/*--------------------------------------------------------------------------*/ + void KillEL737Counter(pCounterDriver self) + { + EL737st *pEL737 = NULL; + + assert(self); + pEL737 = (EL737st *)self->pData; + assert(pEL737); + + EL737_Close(&pEL737->pData,0); + if(pEL737->host) + { + free(pEL737->host); + } + } diff --git a/eurodriv.c b/eurodriv.c new file mode 100644 index 0000000..191ebca --- /dev/null +++ b/eurodriv.c @@ -0,0 +1,395 @@ +/*-------------------------------------------------------------------------- + E U R O D R I V + + This file contains the implementation for the Eurotherm temperature + controller as used at SANS. The Eurotherm is a grossly strange device + which has a very weird command protocoll. The implementation here uses + the EI-Bisynch Protocoll option. This has to be configured in the + Eurotherm on the manual interface!! Also watch out for the unusual RS232- + setting: 7 bits, even parity, 1 stop bit. + + Mark Koennecke, May 1999 + + Copyright: see copyright.h +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + typedef struct __EVDriver *pEVDriver; + +#include +#include "hardsup/el734_def.h" +#include "hardsup/el734fix.h" +#include "hardsup/serialsinq.h" +#include "eurodriv.h" + +#define INVALIDANSWER -1005 +#define INVALIDNUMBER -1006 +#define ERRNAK -1007 +#define NOSEND -1008 +/*-----------------------------------------------------------------------*/ + typedef struct { + void *pData; + char *pHost; + int iPort; + int iChannel; + int iLastError; + } EuroDriv, *pEuroDriv; + +/*------------------------------------------------------------------------*/ + int EuroGetParameter(void **pData, char *pPar,int iLen, float *fVal) + { + char pCommand[20]; + char pReply[20]; + char *pStart = NULL, *pEnd = NULL; + int iRet,i; + + /* configure the serial port */ + SerialATerm(pData,"1\x3"); /* ETX */ + pCommand[0] = '\x4'; /* EOT */ + pCommand[1] = '0'; /* GID*/ + pCommand[2] = '0'; /* GID*/ + pCommand[3] = '1'; /* UID*/ + pCommand[4] = '1'; /* UID*/ + pCommand[5] = '1'; /* CHAN */ + for(i = 0; i < iLen; i++) + { + pCommand[6+i] = pPar[i]; + } + pCommand[6+iLen] = '\x5'; /* ENQ*/ + pCommand[7+iLen] = '\0'; + + /* send */ + iRet = SerialWriteRead(pData,pCommand,pReply,19); + if(iRet != 1) + { + return iRet; + } + + /* decode reply */ + pStart = strstr(pReply,pPar); + if(!pStart) + { + if(strstr(pReply,"?TMO")) + { + return EL734__BAD_TMO; + } + else + { + return INVALIDANSWER; + } + } + iRet = sscanf(pStart+strlen(pPar),"%f",fVal); + if(iRet != 1) + { + return INVALIDNUMBER; + } + return 1; + } +/*------------------------------------------------------------------------*/ + int EuroSetParameter(void **pData, char *pPar,int iLen, + char *pFormat, float fVal) + { + char pCommand[30]; + char pNum[10]; + char *pPtr, *pPtr2; + char pReply[20]; + char bcc; + int iRet,i; + + + /* configure the serial port */ + SerialATerm(pData,"1\x06\x15"); /* ACK,NAK */ + pCommand[0] = '\x04'; /* EOT */ + pCommand[1] = '0'; /* GID*/ + pCommand[2] = '0'; /* GID*/ + pCommand[3] = '1'; /* UID*/ + pCommand[4] = '1'; /* UID*/ + pCommand[5] = '\x02'; + pCommand[6] = '1'; /* CHAN */ + for(i = 0; i < iLen; i++) + { + pCommand[7+i] = pPar[i]; + } + pPtr = pCommand + 7 + iLen; + sprintf(pNum,pFormat,fVal); + strcpy(pPtr,pNum); + pPtr += strlen(pNum); + *pPtr = '\x03'; + pPtr++; + + /* build the checksum */ + bcc = pCommand[6]; + pPtr2 = &pCommand[7]; + while(pPtr2 != pPtr) + { + bcc = bcc ^ *pPtr2; + pPtr2++; + } + *pPtr = bcc; + pPtr++; + *pPtr = '\0'; + + /* send */ + iRet = SerialSend(pData,pCommand); + if(iRet != 1) + { + return iRet; + } + iRet = SerialReceiveWithTerm(pData,pReply,19,&bcc); +/* + printf("%s\n",pReply); +*/ + if(iRet != 1) + { + return iRet; + } + if(bcc == '\x15') + { + return ERRNAK; + } + if(strstr(pReply,"?TMO")) + { + return EL734__BAD_TMO; + } + + return 1; + } +/*---------------------------------------------------------------------------*/ + static int GetEuroPos(pEVDriver self, float *fPos) + { + pEuroDriv pMe = NULL; + int iRet; + + assert(self); + pMe = (pEuroDriv)self->pPrivate; + assert(pMe); + + iRet = EuroGetParameter(&(pMe->pData),"PV",2,fPos); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*----------------------------------------------------------------------------*/ + static int EuroRun(pEVDriver self, float fVal) + { + pEuroDriv pMe = NULL; + int iRet; + + assert(self); + pMe = (pEuroDriv )self->pPrivate; + assert(pMe); + + iRet = EuroSetParameter(&(pMe->pData),"SL",2,"%4.1f",fVal); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + return 1; + } +/*--------------------------------------------------------------------------*/ + static int EuroError(pEVDriver self, int *iCode, char *error, int iErrLen) + { + pEuroDriv pMe = NULL; + + assert(self); + pMe = (pEuroDriv)self->pPrivate; + assert(pMe); + + *iCode = pMe->iLastError; + switch(pMe->iLastError) + { + case INVALIDANSWER: + strncpy(error,"Unexpected reply from Eurotherm",iErrLen); + break; + case INVALIDNUMBER: + strncpy(error,"No number in Eurotherm answer",iErrLen); + break; + case ERRNAK: + strncpy(error,"Eurothem did NOT acknowledge command",iErrLen); + break; + case NOSEND: + strncpy(error, + "Eurotherm has a bizarre protocoll, sending things is very STUPID",iErrLen); + break; + default: + SerialError(pMe->iLastError,error,iErrLen); + break; + } + + return 1; + } +/*--------------------------------------------------------------------------*/ + static int EuroSend(pEVDriver self, char *pCommand, char *pReply, int iLen) + { + pEuroDriv pMe = NULL; + + assert(self); + pMe = (pEuroDriv)self->pPrivate; + assert(pMe); + + pMe->iLastError = NOSEND; + strncpy(pReply,"ERROR: Eurotherm does not support send functionality", + iLen); + return 0; + } +/*--------------------------------------------------------------------------*/ + static int EuroInit(pEVDriver self) + { + pEuroDriv pMe = NULL; + int iRet; + + assert(self); + pMe = (pEuroDriv )self->pPrivate; + assert(pMe); + + pMe->pData = NULL; + iRet = SerialOpen(&pMe->pData, pMe->pHost, pMe->iPort, pMe->iChannel); + if(iRet != 1) + { + pMe->iLastError = iRet; + return 0; + } + SerialSendTerm(&pMe->pData,""); + return 1; + } +/*--------------------------------------------------------------------------*/ + static int EuroClose(pEVDriver self) + { + pEuroDriv pMe = NULL; + int iRet; + + assert(self); + pMe = (pEuroDriv )self->pPrivate; + assert(pMe); + + SerialClose(&pMe->pData); + return 1; + } +/*---------------------------------------------------------------------------*/ + static int EuroFix(pEVDriver self, int iError) + { + pEuroDriv pMe = NULL; + int iRet; + + assert(self); + pMe = (pEuroDriv )self->pPrivate; + assert(pMe); + + switch(iError) + { + /* network errors */ + case EL734__BAD_FLUSH: + case EL734__BAD_RECV: + case EL734__BAD_RECV_NET: + case EL734__BAD_RECV_UNKN: + case EL734__BAD_RECVLEN: + case EL734__BAD_RECV1: + case EL734__BAD_RECV1_PIPE: + case EL734__BAD_RNG: + case EL734__BAD_SEND: + case EL734__BAD_SEND_PIPE: + case EL734__BAD_SEND_NET: + case EL734__BAD_SEND_UNKN: + case EL734__BAD_SENDLEN: + EuroClose(self); + iRet = EuroInit(self); + if(iRet) + { + return DEVREDO; + } + else + { + return DEVFAULT; + } + break; + /* handable protocoll errors */ + case EL734__BAD_TMO: + return DEVREDO; + break; + case ERRNAK: + case NOSEND: + case INVALIDANSWER: + case INVALIDNUMBER: + return DEVFAULT; + default: + return DEVFAULT; + break; + } + return DEVFAULT; + } + +/*--------------------------------------------------------------------------*/ + static int EuroHalt(pEVDriver *self) + { + assert(self); + + return 1; + } +/*------------------------------------------------------------------------*/ + void KillEuro(void *pData) + { + pEuroDriv pMe = NULL; + + pMe = (pEuroDriv)pData; + assert(pMe); + + if(pMe->pHost) + { + free(pMe->pHost); + } + free(pMe); + } +/*------------------------------------------------------------------------*/ + pEVDriver CreateEURODriv(int argc, char *argv[]) + { + pEVDriver pNew = NULL; + pEuroDriv pSim = NULL; + + /* check for arguments */ + if(argc < 3) + { + return NULL; + } + + pNew = CreateEVDriver(argc,argv); + pSim = (pEuroDriv)malloc(sizeof(EuroDriv)); + memset(pSim,0,sizeof(EuroDriv)); + if(!pNew || !pSim) + { + return NULL; + } + pNew->pPrivate = pSim; + pNew->KillPrivate = KillEuro; + + /* initalise pDILLUDriver */ + pSim->iLastError = 0; + pSim->pHost = strdup(argv[0]); + pSim->iPort = atoi(argv[1]); + pSim->iChannel = atoi(argv[2]); + + /* initialise function pointers */ + pNew->SetValue = EuroRun; + pNew->GetValue = GetEuroPos; + pNew->Send = EuroSend; + pNew->GetError = EuroError; + pNew->TryFixIt = EuroFix; + pNew->Init = EuroInit; + pNew->Close = EuroClose; + + return pNew; + } + + + diff --git a/eurodriv.h b/eurodriv.h new file mode 100644 index 0000000..132856f --- /dev/null +++ b/eurodriv.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------ + E U R O D R I V + + A environment control driver for the SANS Eurotherm temperature + controller. + + Mark Koennecke, May 1999 + + copyright: see copyright.h +---------------------------------------------------------------------------*/ +#ifndef EURODRIV +#define EURODRIV + pEVDriver CreateEURODriv(int argc, char *argv[]); + + /* + these are hooks to implement further functionality which, + I'am sure, Joachim Kohlbrecher will request. + */ + int EuroGetParameter(void **pData, char *pPar, int iLen, float *fVal); + int EuroSetParameter(void **pData, char *pPar, int iLen, + char *pFormat, float fVal); + +#endif diff --git a/frame.c b/frame.c new file mode 100644 index 0000000..20ef729 --- /dev/null +++ b/frame.c @@ -0,0 +1,242 @@ +/*------------------------------------------------------------------------- + A module implementing functionality for reading single time frames + from PSD time-of-flight datasets. This can be done either from + SINQHM histogram memories or from old data files visible from the + SICS server. The result is sent to the demanding client in UUencoded + format. + + copyright: see file COPYRIGHT + + Mark Koennecke, February-March 2003 +---------------------------------------------------------------------------*/ +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "stringdict.h" +#include "counter.h" +#include "HistMem.h" +#include "HistMem.i" +#include "HistDriv.i" +#include "hardsup/sinqhm.h" +#include "sinqhmdriv.i" +#include "nxdict.h" +#include "frame.h" +/*======================================================================*/ +static int readHMFrame(SConnection *pCon, pHistMem pHM, int nFrame){ + HistInt *buffer = NULL; + int iDim[MAXDIM], rank, length, status, i, noTimeBins; + pSINQHM pHist; + SinqHMDriv *pTata; + const float *timeBin; + + /* + find dimensions and allocate data + */ + GetHistDim(pHM,iDim,&rank); + timeBin = GetHistTimeBin(pHM,&noTimeBins); + + if(rank < 2){ + SCWrite(pCon,"ERROR: no PSD data present, cannot send frame",eError); + return 0; + } + length = iDim[0]*iDim[1]; + buffer = (HistInt *)malloc((length + 2)*sizeof(HistInt)); + if(!buffer){ + SCWrite(pCon,"ERROR: out of memory in readHMFrame",eError); + return 0; + } + memset(buffer,0,(length+2)*sizeof(HistInt)); + + /* + first two values are dimensions + */ + buffer[0] = htonl(iDim[0]); + buffer[1] = htonl(iDim[1]); + + if(isSINQHMDriv(pHM->pDriv) && noTimeBins > 2) { + /* + read from HM. The 5 is PROJECT__FRAME in Sinqhm_def.h + Again: be friendly: fix out of range frames + */ + if(nFrame < 0){ + nFrame = 0; + } + if(nFrame >= noTimeBins){ + nFrame = noTimeBins-1; + } + pTata = (SinqHMDriv *)pHM->pDriv->pPriv; + pHist = (pSINQHM)pTata->pMaster; + status = SINQHMProject(pHist, 0x0005, 0, nFrame, + 0, iDim[1], buffer+2,length*sizeof(HistInt)); + if(status != 1){ + SCWrite(pCon,"ERROR: SINQHM refused to deliver frame",eError); + free(buffer); + return 0; + } + } else { + /* + be friendly, just read the 2D data which is there + */ + status = GetHistogram(pHM,pCon,0,0,length,buffer+2,length*sizeof(HistInt)); + if(!status){ + free(buffer); + return status; + } + } + + /* + enforce network byte order + */ + for(i = 0; i < length; i++){ + buffer[i+2] = htonl(buffer[i+2]); + } + + SCWriteUUencoded(pCon,"framedata", buffer,(length+2)*sizeof(HistInt)); + free(buffer); + + return 1; +} +/*=======================================================================*/ +static int readFileFrame(SConnection *pCon, + char *file, char *dictFile, + char *alias, int nFrame){ + int status, iDim[NX_MAXRANK], rank = 0, type = 0; + int iStart[3], iSize[3], length, i; + int *buffer = NULL; + NXhandle fileHandle; + NXdict dictHandle; + char error[512]; + + status = NXopen(file,NXACC_READ,&fileHandle); + if(status != NX_OK){ + sprintf(error,"ERROR: failed to open %s", file); + SCWrite(pCon,error,eError); + return 0; + } + status = NXDinitfromfile(dictFile, &dictHandle); + if(status != NX_OK){ + sprintf(error,"ERROR: failed to open dictionary %s", dictFile); + NXclose(&fileHandle); + SCWrite(pCon,error,eError); + return 0; + } + + status = NXDopenalias(fileHandle,dictHandle,alias); + if(status != NX_OK){ + sprintf(error,"ERROR: failed to open alias %s", alias); + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + SCWrite(pCon,error,eError); + return 0; + } + + status = NXgetinfo(fileHandle,&rank,iDim,&type); + if(type != NX_INT32 && type != NX_UINT32)type = -1; + if(status != NX_OK || rank < 2 || type < 0 ){ + sprintf(error,"ERROR: Dataset does not match!"); + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + SCWrite(pCon,error,eError); + return 0; + } + + /* + allocate space + */ + length = iDim[0]*iDim[1]; + buffer = (int *)malloc((length+2)*sizeof(int)); + if(!buffer){ + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + SCWrite(pCon,"ERROR: out of memory in readFrameFromFile",eError); + return 0; + } + memset(buffer,0,(length+2)*sizeof(int)); + + /* + first two values: dimensions + */ + buffer[0] = htonl(iDim[0]); + buffer[1] = htonl(iDim[1]); + + if(rank == 2){ + /* + be friendly + */ + status = NXgetdata(fileHandle,buffer+2); + } else { + iStart[0] = iStart[1] = 0; + iStart[2] = nFrame; + iSize[0] = iDim[0]; + iSize[1] = iDim[1]; + iSize[2] = 1; + status = NXgetslab(fileHandle,buffer+2,iStart,iSize); + } + if(status != NX_OK){ + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + free(buffer); + SCWrite(pCon,"ERROR: failed to read data",eError); + return 0; + } + + /* + enforce network byte order + */ + for(i = 0; i < length; i++){ + buffer[2+i] = htonl(buffer[2+i]); + } + + SCWriteUUencoded(pCon,"framedata",buffer,(length+2)*sizeof(int)); + NXclose(&fileHandle); + NXDclose(dictHandle,NULL); + free(buffer); + return 1; +} +/*=======================================================================*/ +int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pHistMem pHM; + int nFrame; + + if(argc < 2){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDFrame", + eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"hm") == 0){ + if(argc < 4){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDFrame", + eError); + return 0; + } + pHM = (pHistMem)FindCommandData(pSics,argv[2],"HistMem"); + if(pHM == NULL){ + SCWrite(pCon,"ERROR: Did not find histogram memory",eError); + return 0; + } + nFrame = atoi(argv[3]); + return readHMFrame(pCon,pHM,nFrame); + } else if(strcmp(argv[1],"file") == 0){ + if(argc < 6 ){ + SCWrite(pCon,"ERROR: Insufficient number of arguments to PSDframe file", + eError); + return 0; + } + nFrame = atoi(argv[5]); + return readFileFrame(pCon,argv[2],argv[3],argv[4],nFrame); + } else { + SCWrite(pCon,"ERROR: subcommand to PSDframe not recognised",eError); + return 0; + } +} +/*======================================================================*/ +int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + return AddCommand(pSics,"PSDframe",PSDFrameAction,NULL,NULL); +} + diff --git a/frame.h b/frame.h new file mode 100644 index 0000000..af5a1ef --- /dev/null +++ b/frame.h @@ -0,0 +1,22 @@ + +/*------------------------------------------------------------------------- + A module implementing functionality for reading single time frames + from PSD time-of-flight datasets. This can be done either from + SINQHM histogram memories or from old data files visible from the + SICS server. + + copyright: see file COPYRIGHT + + Mark Koennecke, February-March 2003 +*/ +#ifndef SICSFRAME +#define SICSFRAME + +int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +#endif diff --git a/frame.w b/frame.w new file mode 100644 index 0000000..c2bcfe2 --- /dev/null +++ b/frame.w @@ -0,0 +1,32 @@ +\subsection{Frame} +This module allows to retrieve data frames from a 3D histogram (PSD plus +time dimension). This can be done either from a Sinq histogram memory +and old data files visible from the SICS server. + +This module has no data structure and only implements the usual +interpreter interface functions. + + +@o frame.h @{ +/*------------------------------------------------------------------------- + A module implementing functionality for reading single time frames + from PSD time-of-flight datasets. This can be done either from + SINQHM histogram memories or from old data files visible from the + SICS server. + + copyright: see file COPYRIGHT + + Mark Koennecke, February-March 2003 +*/ +#ifndef SICSFRAME +#define SICSFRAME + +int MakeFrameFunc(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +int PSDFrameAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +#endif +@} \ No newline at end of file diff --git a/hardsup/sinqhm.i b/hardsup/sinqhm.i new file mode 100644 index 0000000..785f1d7 --- /dev/null +++ b/hardsup/sinqhm.i @@ -0,0 +1,54 @@ + +/*--------------------------------------------------------------------------- + + Internal header file for the SINQ histogram memory utility functions. + + David Maden, Mark Koennecke April 1997 +----------------------------------------------------------------------------*/ +#ifndef SINQHMINTERNAL +#define SINQHMINTERNAL +#define MAXBANK 1 + + typedef struct __SBANK { + int iStart; + int iEnd; + int iFlag; + int iEdgeLength; + int iDelay; + unsigned int *iEdges; + } SBank, *pSBank; + + + typedef struct __SINQHM { + char *pHMComputer; + int iMasterPort; + int iMasterSocket; + int iClientPort; + int iClientSocket; + int iBinWidth; + int iLength; + int iRank; + int iPacket; + int iBanks; + int xSize, ySize; + int xOff, xFac; + int yOff, yFac; + SBank pBank[MAXBANK]; + } SINQHM; + +/*---------------------------- Type definitions, machine dependent--------*/ + typedef short int SQint16; /* 16 bit integer */ + typedef int SQint32; /* 32 bit integer */ + + + + static int OpenMasterConnection(pSINQHM self); + static int GetMasterReply(pSINQHM self, struct rply_buff_struct *reply, + int iBufLen); + static int SendDAQCommand(pSINQHM self, int iCommand, int *iDaq); + + + static int SINQHMTimeBin(pSINQHM self, int iMode); + +#endif + diff --git a/make_gen b/make_gen new file mode 100644 index 0000000..ff27176 --- /dev/null +++ b/make_gen @@ -0,0 +1,25 @@ +#------------------------------------------------------------------------- +# common part of the makefile for the PSI specific parts of SICS +# +# Mark Koennecke, June 2003 +#------------------------------------------------------------------------- +.SUFFIXES: +.SUFFIXES: .c .o .f + +OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \ + pipiezo.o sanswave.o faverage.o fowrite.o amor2t.o nxamor.o \ + amorstat.o tasinit.o tasdrive.o tasutil.o tasscan.o swmotor.o \ + polterwrite.o ecb.o frame.o el734driv.o el734dc.o ecbdriv.o \ + ecbcounter.o el737driv.o sinqhmdriv.o tdchm.o velodorn.o \ + velodornier.o docho.o sanscook.o tecsdriv.o itc4driv.o itc4.o\ + bruker.o ltc11.o A1931.o dilludriv.o eurodriv.o slsmagnet.o \ + el755driv.o amorscan.o serial.o scontroller.o + +libpsi.a: $(OBJ) + - rm libpsi.a + ar cr libpsi.a $(OBJ) + ranlib libpsi.a + +clean: + - rm *.a + - rm *.o \ No newline at end of file diff --git a/makefile_alpha b/makefile_alpha new file mode 100644 index 0000000..b54e224 --- /dev/null +++ b/makefile_alpha @@ -0,0 +1,16 @@ +#--------------------------------------------------------------------------- +# Makefile for the PSI specific part of SICS +# machine-dependent part for Tru64 Unix +# +# Mark Koennecke, June 2003 +#-------------------------------------------------------------------------- +# the following line only for fortified version +#DFORTIFY=-DFORTIFY +#========================================================================== + +HDFROOT=/data/lnslib +CC = cc +CFLAGS = -std1 -g $(DFORTIFY) -I.. -I$(HDFROOT)/include -DHDF4 -DHDF5 \ + -Ihardsup + +include make_gen diff --git a/nxsans.c b/nxsans.c new file mode 100644 index 0000000..3cb67a4 --- /dev/null +++ b/nxsans.c @@ -0,0 +1,796 @@ +/*-------------------------------------------------------------------------- + N X S A N S + + a module of utility functions which serve to write Nexus + data files for SANS. + + Mark Koennecke, August 1997 - November 1998 + + Updated to support the larger detector resolution and possible + TOF and stroboscopic modes, Mark Koennecke, February 2001 + + Added additional monitors for stroboscopic gummi mode, + Mark Koennecke, September 2002 + + Copyright: + + Labor fuer Neutronenstreuung + Paul Scherrer Institut + CH-5423 Villigen-PSI + + + The authors hereby grant permission to use, copy, modify, distribute, + and license this software and its documentation for any purpose, provided + that existing copyright notices are retained in all copies and that this + notice is included verbatim in any distributions. No written agreement, + license, or royalty fee is required for any of the authorized uses. + Modifications to this software may be copyrighted by their authors + and need not follow the licensing terms described here, provided that + the new terms are clearly indicated on the first page of each file where + they apply. + + IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY + FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY + DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE + IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE + NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. +----------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "sicsvar.h" +#include "napi.h" +#include "nxdict.h" +#include "modriv.h" +#include "motor.h" +#include "nxutil.h" +#include "nxdata.h" +#include "countdriv.h" +#include "counter.h" +#include "danu.h" +#include "HistMem.h" +#include "velo.h" +#include "sps.h" +#include "udpquieck.h" +#include "mumo.h" +#include "sanswave.h" + + +#define HISTNAME "banana" +#define SAMPLETABLE "sampletable" + +static int gummiFlag = 0; /* a flag indicating stroboscopic, or gummi mode */ + +/*-----------------------------------------------------------------------*/ + static void SNError(void *pData, char *text) + { + SConnection *pCon; + + assert(pData); + pCon = (SConnection *)pData; + SCWrite(pCon,text,eError); + } +/*-------------------------------------------------------------------------*/ + NXhandle SNXStartSANS(SConnection *pCon, SicsInterp *pSics) + { + NXhandle pFile = NULL; + char *filename = NULL; + pSicsVariable pVar = NULL; + int iStat; + char pBueffel[512]; + + /* get a filename */ + filename = SNXMakeFileName(pSics,pCon); + if(!filename) + { + return NULL; + } + + /* create a Nexus file */ + NXopen(filename,NXACC_CREATE,&pFile); + if(!pFile) + { + SCWrite(pCon,"ERROR: cannot create data file ",eError); + return NULL; + } + + /* tell Uwe User what we are doing */ + sprintf(pBueffel,"Writing %s ......",filename); + SCWrite(pCon,pBueffel,eWarning); + + /* store global attributes */ + iStat = NXputattr(pFile,"file_name",filename, + strlen(filename)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing file_name attribute to Nexus file",eError); + } + + /* throw away filename, no longer needed */ + free(filename); + + /* write creation time */ + SNXFormatTime(pBueffel,512); + iStat = NXputattr(pFile,"file_time",pBueffel, + strlen(pBueffel)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing date attribute to Nexus file",eError); + } + pVar = FindVariable(pSics,"instrument"); + if(pVar) + { + iStat = NXputattr(pFile,"instrument",pVar->text, + strlen(pVar->text)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing instrument attribute to Nexus file",eError); + } + } + pVar = NULL; + pVar = FindVariable(pSics,"user"); + if(pVar) + { + iStat = NXputattr(pFile,"owner",pVar->text, + strlen(pVar->text)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing owner attribute to Nexus file",eError); + } + } + + pVar = NULL; + pVar = FindVariable(pSics,"adress"); + if(pVar) + { + iStat = NXputattr(pFile,"owner_adress",pVar->text, + strlen(pVar->text)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing owner_adress attribute to Nexus file",eError); + } + } + pVar = NULL; + pVar = FindVariable(pSics,"phone"); + if(pVar) + { + iStat = NXputattr(pFile,"owner_telephone_number",pVar->text, + strlen(pVar->text)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing owner_telephone_number attribute to Nexus file",eError); + } + } + pVar = NULL; + pVar = FindVariable(pSics,"fax"); + if(pVar) + { + iStat = NXputattr(pFile,"owner_fax_number",pVar->text, + strlen(pVar->text)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing owner_fax_number attribute to Nexus file",eError); + } + } + pVar = NULL; + pVar = FindVariable(pSics,"email"); + if(pVar) + { + iStat = NXputattr(pFile,"owner_email",pVar->text, + strlen(pVar->text)+1,NX_CHAR); + if(iStat == NX_ERROR) + { + SCWrite(pCon,"ERROR: writing owner_email attribute to Nexus file",eError); + } + } + pVar = NULL; + return pFile; + } +/*--------------------------------------------------------------------------*/ + int SNMakeSANS(SConnection *pCon, SicsInterp *pSics, NXdict pDict) + { + NXhandle Nfil = NULL; + char pBueffel[512]; + float fVal; + int iVal, iSet; + int32 iAxis[256]; + int i, iRet; + long lVal; + HistInt *lData = NULL; + const float *fTime = NULL; + CommandList *pCom = NULL; + pHistMem self = NULL; + CounterMode eMode; + pVelSel pVelo = NULL; + pSPS pSiem = NULL; + const char *pNamPos = NULL; + float fRot, fTilt, fLambda; + pDummy pDum; + pIDrivable pDrive; + int iDim[MAXDIM], nDim, histSize,iStart; + + /* start file */ + Nfil = SNXStartSANS(pCon,pSics); + if(!Nfil) + { + return 0; + } + + /* + during all this, no extensive error checking will be done, + just write the error and continue, save at all cost + */ + + /* put all this global information */ + SNXSPutVariable(pSics,pCon,Nfil,pDict,"etitle","title"); + SNXSPutVariable(pSics,pCon,Nfil,pDict,"etime","starttime"); + SNXFormatTime(pBueffel,511); + NXDputalias(Nfil,pDict,"endtime",pBueffel); + strcpy(pBueffel,"SANS at SINQ,PSI"); + NXDputalias(Nfil,pDict,"iname",pBueffel); + strcpy(pBueffel,"SINQ at PSI,Villigen, Switzerland"); + NXDputalias(Nfil,pDict,"sname",pBueffel); + strcpy(pBueffel,"Spallation"); + NXDputalias(Nfil,pDict,"stype",pBueffel); + + /* put the velocity selector data */ + NXDputalias(Nfil,pDict,"vname","Dornier Velocity Selector"); + + fRot = 0.; + fTilt = 0.; + pCom = FindCommand(pSics,"nvs"); + if(pCom) + { + pVelo = (pVelSel)pCom->pData; + if(!pVelo) + { + SCWrite(pCon,"WARNING: Velocity Selctor not found",eWarning); + } + iRet = VSGetRotation(pVelo,&fVal); + if(!iRet) + { + SCWrite(pCon,"WARNING: failed to read velocity selector speed", + eWarning); + } + else + { + fRot = fVal; + NXDputalias(Nfil,pDict,"vrot",&fVal); + } + iRet = VSGetTilt(pVelo,&fTilt); + if(!iRet) + { + SCWrite(pCon,"WARNING: failed to read velocity selector tilt angle",eWarning); + } + } + SNXSPutMotor(pSics,pCon,Nfil,pDict,"vtilt","tilt"); + CalculateLambda(fRot, fTilt, &fLambda); + NXDputalias(Nfil,pDict,"vlambda",&fLambda); + + + /* monitor 1 */ + pCom = FindCommand(pSics,HISTNAME); + if(!pCom) + { + sprintf(pBueffel,"ERROR: histogram memory %s not found",HISTNAME); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self = (pHistMem)pCom->pData; + assert(self); + lVal = GetHistMonitor(self,0,pCon); + iVal = (int32)lVal; + NXDputalias(Nfil,pDict,"m1counts",&iVal); + lVal = GetHistMonitor(self,4,pCon); + iVal = (int32)lVal; + NXDputalias(Nfil,pDict,"pbcounts",&iVal); + + /* the collimator */ + pCom = FindCommand(pSics,"sps2"); + if(!pCom) + { + SCWrite(pCon,"WARNING: sps-unit for reading collimator NOT found", + eWarning); + } + else + { + pSiem = (pSPS)pCom->pData; + if(!pSiem) + { + SCWrite(pCon,"WARNING: sps-unit for reading collimator NOT found", + eWarning); + } + else + { + iRet = SPSGetSANS(pSiem,&fVal); + if(iRet <= 0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + NXDputalias(Nfil,pDict,"colli",&fVal); + } + /* as we got the sps, get the attenuator as well */ + iRet = SPSGetStatus(pSiem,38,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 0; + } + } + iRet = SPSGetStatus(pSiem,39,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 1; + } + } + iRet = SPSGetStatus(pSiem,40,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 2; + } + } + iRet = SPSGetStatus(pSiem,41,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 3; + } + } + iRet = SPSGetStatus(pSiem,42,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 4; + } + } + iRet = SPSGetStatus(pSiem,43,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 5; + } + } + NXDputalias(Nfil,pDict,"atti",&iVal); + } + } + + /* the sample */ + SNXSPutVariable(pSics,pCon,Nfil,pDict,"san","sample"); + SNXSPutVariable(pSics,pCon,Nfil,pDict,"saenv","environment"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"sax","sax"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"say","say"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"saz","saz"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"saxn","sax"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"sayn","say"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"sazn","saz"); + + + /* goniometer */ + SNXSPutMotor(pSics,pCon,Nfil,pDict,"gphi","gphi"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"gtheta","gtheta"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"gphin","gphi"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"gthetan","gtheta"); + + SNXSPutMotor(pSics,pCon,Nfil,pDict,"saom","som"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"saomn","som"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"sapos","spos"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"saposn","spos"); + pCom = FindCommand(pSics,SAMPLETABLE); + if(pCom) + { + if(pCom->pData) + { + pNamPos = FindNamPos((pMulMot)pCom->pData,pCon); + if(pNamPos) + { + NXDputalias(Nfil,pDict,"sanampos",(char *)pNamPos); + } + } + } + /* write sample environment here */ + pCom = FindCommand(pSics,"temperature"); + if(pCom) + { + pDum = (pDummy)pCom->pData; + pDrive = pDum->pDescriptor->GetInterface(pDum,DRIVEID); + if(pDrive) /* a proper environment device */ + { + fVal = pDrive->GetValue(pDum,pCon); + NXDputalias(Nfil,pDict,"satemp",&fVal); + } + } + pCom = FindCommand(pSics,"magnet"); + if(pCom) + { + pDum = (pDummy)pCom->pData; + pDrive = pDum->pDescriptor->GetInterface(pDum,DRIVEID); + if(pDrive) /* a proper environment device */ + { + fVal = pDrive->GetValue(pDum,pCon); + NXDputalias(Nfil,pDict,"samag",&fVal); + } + } + + /* magnet motors. This instrument has motorized magnets crawling + through the hall */ + pCom = FindCommand(pSics,"mom"); + if(pCom) + { + SNXSPutMotor(pSics,pCon,Nfil,pDict,"mom","mom"); + } + pCom = FindCommand(pSics,"mz"); + if(pCom) + { + SNXSPutMotor(pSics,pCon,Nfil,pDict,"mz","mz"); + } + + + /* put Beam Stop */ + /* read beamstop number */ + iVal = 1; + pCom = FindCommand(pSics,"sps1"); + if(!pCom) + { + SCWrite(pCon,"WARNING: sps-unit for reading beamstop NOT found",eWarning); + } + else + { + pSiem = (pSPS)pCom->pData; + if(!pSiem) + { + SCWrite(pCon,"WARNING: sps-unit for reading beamstop NOT found",eWarning); + } + else + { + iRet = SPSGetStatus(pSiem,8,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 2; + } + } + iRet = SPSGetStatus(pSiem,9,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 3; + } + } + iRet = SPSGetStatus(pSiem,10,&iSet); + if(iRet <0) + { + SCWrite(pCon,"WARNING: Failed to read SPS",eWarning); + } + else + { + if(iSet) + { + iVal = 4; + } + } + } + } + NXDputalias(Nfil,pDict,"bst",&iVal); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"vsx","BeamStopX"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"vsy","BeamStopY"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"vsxnull","BeamStopX"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"vsynull","BeamStopY"); + + /* what this is all about: the detector */ + SNXSPutMotor(pSics,pCon,Nfil,pDict,"ddx","DetectorX"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"ddy","DetectorY"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"ddxn","DetectorX"); + SNXSPutMotorNull(pSics,pCon,Nfil,pDict,"ddyn","DetectorY"); + SNXSPutMotor(pSics,pCon,Nfil,pDict,"ddchi","DetectorRotation"); + pCom = FindCommand(pSics,HISTNAME); + if(!pCom) + { + sprintf(pBueffel,"ERROR: histogram memory %s not found",HISTNAME); + SCWrite(pCon,pBueffel,eError); + return 0; + } + self = (pHistMem)pCom->pData; + assert(self); + eMode = GetHistCountMode(self); + if(eMode == eTimer) + { + strcpy(pBueffel,"Timer"); + } + else + { + strcpy(pBueffel,"Monitor"); + } + NXDputalias(Nfil,pDict,"ddm",pBueffel); + fVal = GetHistPreset(self); + NXDputalias(Nfil,pDict,"ddp",&fVal); + lVal = GetHistMonitor(self,1,pCon); + iVal = (int32)lVal; + NXDputalias(Nfil,pDict,"ddmo",&iVal); + fVal = GetHistCountTime(self,pCon); + NXDputalias(Nfil,pDict,"ddtime",&fVal); + + /* + Deal with actual histogram. Due to stroboscopic modes and the + new detector electronics we need to find out about the size + ourselves now. And possibly write time binning information. + */ + GetHistDim(self, iDim,&nDim); + /* + handle time binning + */ + fTime = GetHistTimeBin(self,&iVal); + if(iVal > 2) + { + NXDputalias(Nfil,pDict,"ddtb",(void *)fTime); + nDim = 3; + iDim[2] = iVal; + } + + histSize = 1; + for(i = 0; i < nDim; i++) + { + histSize *= iDim[i]; + } + lData = (HistInt *)malloc(histSize*sizeof(HistInt)); + if(!lData) + { + SCWrite(pCon,"ERROR: out of memory, FAILED to store data, file corrupt", + eError); + NXclose(&Nfil); + return 0; + } + GetHistogram(self,pCon,0,0,histSize,lData,histSize*sizeof(HistInt)); + sprintf(pBueffel," %d ",iDim[0]); + NXDupdate(pDict,"dim1",pBueffel); + sprintf(pBueffel," %d ",iDim[1]); + NXDupdate(pDict,"dim2",pBueffel); + if(nDim == 2) + { + sprintf(pBueffel," -rank 2 -dim {%d,%d} ", iDim[0], iDim[1]); + NXDupdate(pDict,"countdim",pBueffel); + } + else if (nDim == 3) + { + sprintf(pBueffel," -rank 3 -dim {%d,%d,%d} ", iDim[0], iDim[1], + iDim[2]); + NXDupdate(pDict,"countdim",pBueffel); + sprintf(pBueffel," %d ",iDim[2]); + NXDupdate(pDict,"timedim",pBueffel); + } + NXDputalias(Nfil,pDict,"ddcounts",lData); + free(lData); + + /* write x and y axis */ + for(i = 0; i < iDim[0]; i++) + { + iAxis[i] = i; + } + NXDputalias(Nfil,pDict,"ddcx",iAxis); + for(i = 0; i < iDim[1]; i++) + { + iAxis[i] = i; + } + NXDputalias(Nfil,pDict,"ddcy",iAxis); + + + + /* + write gummi monitors when apropriate + */ + if(nDim == 3 && gummiFlag != 0) + { + histSize = 3*iDim[2]; + lData = (HistInt *)malloc(histSize*sizeof(HistInt)); + if(lData == NULL) + { + SCWrite(pCon,"WARNING: failed to allocate memory for monitors", + eWarning); + } else { + memset(lData,0,histSize*sizeof(HistInt)); + iStart = iDim[0]*iDim[1]*iDim[2]; + GetHistogramDirect(self,pCon,0,iStart,iStart+histSize, + lData,histSize*sizeof(HistInt)); + NXDputalias(Nfil,pDict,"gummimon1",lData); + NXDputalias(Nfil,pDict,"gummimon2",lData+iDim[2]); + NXDputalias(Nfil,pDict,"gummimon3",lData+2*iDim[2]); + free(lData); + } + } + + /* + write detector temperature. It is a hot one............ + */ + if(pSiem) + { + iRet = SPSGetADC(pSiem,1,&iVal); + if(iRet) + { + fVal = iVal/269.9; + NXDputalias(Nfil,pDict,"ddtemp",&fVal); + } + } + + /* do the linking in th data vgroup */ + NXDaliaslink(Nfil,pDict,"dan","ddcounts"); + NXDaliaslink(Nfil,pDict,"dan","ddcx"); + NXDaliaslink(Nfil,pDict,"dan","ddcy"); + NXDaliaslink(Nfil,pDict,"dan","ddmo"); + NXDaliaslink(Nfil,pDict,"dan","vlambda"); + if(nDim == 3) + { + NXDaliaslink(Nfil,pDict,"dan","ddtb"); + } + + /* send quieck message for automatic copying*/ + i = 131; + iVal = NX_CHAR; + NXgetattr(Nfil,"file_name",pBueffel,&i,&iVal); + SendQuieck(QUIECK,pBueffel); + /* close this and go ............. */ + NXclose(&Nfil); + return 1; + } +/*------------------- The Mechanics for setting Up ------------------------*/ + typedef struct { + pObjectDescriptor pDes; + NXdict pDict; + } DictStruct, *pDictStruct; +/*-------------------------------------------------------------------------*/ + static pDictStruct MakeDictStruct(char *pFile) + { + pDictStruct pNew = NULL; + int iRet; + + pNew = (pDictStruct)malloc(sizeof(DictStruct)); + if(!pNew) + { + return NULL; + } + memset(pNew,0,sizeof(DictStruct)); + pNew->pDes = CreateDescriptor("StoreData"); + if(!pNew->pDes) + { + free(pNew); + return NULL; + } + + iRet = NXDinitfromfile(pFile,&(pNew->pDict)); + if(iRet != NX_OK) + { + DeleteDescriptor(pNew->pDes); + free(pNew); + return NULL; + } + return pNew; + } +/*--------------------------------------------------------------------------*/ + static void KillDictStruct(void *pData) + { + pDictStruct self = NULL; + + self = (pDictStruct)pData; + assert(self); + + if(self->pDes) + { + DeleteDescriptor(self->pDes); + } + if(self->pDict) + { + NXDclose(self->pDict,NULL); + } + free(self); + } + +/*--------------------------------------------------------------------------*/ + int SNStoreSANS(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, + char *argv[]) + + { + char pBueffel[80]; + pDictStruct self = NULL; + self = (pDictStruct)pData; + + assert(self); + assert(pCon); + assert(pSics); + + if(argc > 1){ + strtolower(argv[1]); + if(strcmp(argv[1],"gummi") == 0){ + if(argc > 2){ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + gummiFlag = atoi(argv[2]); + SCSendOK(pCon); + return 1; + } else + { + sprintf(pBueffel,"%s.gummi = %d",argv[0], gummiFlag); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } + } + + return SNMakeSANS(pCon,pSics,self->pDict); + } +/*--------------------------------------------------------------------------*/ + int InitSANS(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]) + { + pDictStruct pNew = NULL; + char pBueffel[512]; + + if(argc < 2) + { + SCWrite(pCon,"ERROR: not enough arguments for IniSANS",eError); + return 0; + } + + pNew = MakeDictStruct(argv[1]); + if(!pNew) + { + sprintf(pBueffel,"ERROR: failed to initialise NXDDL from file %s", + argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + AddCommand(pSics,"StoreData",SNStoreSANS,KillDictStruct,pNew); + return 1; + } diff --git a/nxsans.h b/nxsans.h new file mode 100644 index 0000000..56ef101 --- /dev/null +++ b/nxsans.h @@ -0,0 +1,17 @@ +/*------------------------------------------------------------------------- + N X S A N S + + Prototypes for some more useful functions from the SANS data writing + module which may ne used in other parts of SICS. + + Mark Koennecke, December 1997 +---------------------------------------------------------------------------*/ +#ifndef NXSANS +#define NXSANS + int InitSANS(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + int SNStoreSANS(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + + +#endif \ No newline at end of file diff --git a/scontroller.c b/scontroller.c new file mode 100644 index 0000000..141a59a --- /dev/null +++ b/scontroller.c @@ -0,0 +1,282 @@ +/*-------------------------------------------------------------------------- + + Some code to connect to a serial port through the SINQ system. + + Just a wrapper around serialsinq derived from David Maden's + EL734 routines. + + You are free to use and modify this software for noncommercial + usage. + + No warranties or liabilities of any kind taken by me or my employer + + Very primitive device to send commands to a motor from Tcl + + Modified version for use within SICS. +----------------------------------------------------------------------------*/ +#include "sinq_prototypes.h" +/* #include */ +#include +#include +#include +#include +#include "rs232c_def.h" +#include "el734_def.h" +#include "psi/hardsup/serialsinq.h" +#include "sics.h" + +#define False 0 +#define True 1 + +/*--------------------------------------------------------------------------- + Tcl has a high niceness level. It deletes a command properly when + exiting, reinitializing etc. I use this facility to kill off the + motor initialised in Controller. +---------------------------------------------------------------------------*/ +EXTERN void SerialMurder(ClientData pData) +{ + /* + NetReadRemoveUserSocket(pServ->pReader, SerialGetSocket(&(pData))); + */ + SerialClose(&(pData)); + free(pData); +} +/*------------------ a forward declaration -----------------------------*/ +EXTERN int SurielSend(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]); + +/*---------------------------------------------------------------------------- + Controller is the main entry point for this stuff. It connects to a motor + and, on success, creates a new command with the name of the motor. + Syntax: + Controller name host port channel +---------------------------------------------------------------------------*/ + +int Controller(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + int iRet; + int iPort, iChannel, iMotor; + char *pErr = NULL; + char pBueffel[80]; + void **pData = NULL; + + /* check arguments */ + if(argc < 5) + { + Tcl_AppendResult(interp, + " Insufficient arguments: Controller name host port channel index" + , (char *) NULL); + return TCL_ERROR; + } + + /* convert arguments */ + iRet = Tcl_GetInt(interp,argv[3],&iPort); + if(iRet == TCL_ERROR) + { + Tcl_AppendResult(interp,"Need integer value for port", + (char *)NULL); + return iRet; + } + + iRet = Tcl_GetInt(interp,argv[4],&iChannel); + if(iRet == TCL_ERROR) + { + Tcl_AppendResult(interp,"Need integer value for channel", + (char *)NULL); + return iRet; + } + + iMotor = 1; + + + /* make a new pointer, initialise EL734st */ + pData = malloc(sizeof(void *)); + if(pData ==NULL) + { + Tcl_AppendResult(interp,"No memory in SerialSinq",NULL); + return TCL_ERROR; + } + + /* check for optional force flag */ + if(argc > 5) + { + iRet = SerialForceOpen(pData, argv[2],iPort,iChannel); + } + + /* open the motor, finally */ + iRet = SerialOpen(pData, argv[2],iPort,iChannel); + if(iRet == 1) /* success */ + { + /* handle TCL, create new command: the serial line */ + Tcl_CreateCommand(interp,strdup(argv[1]),SurielSend, + *pData,SerialMurder); + strcpy(pBueffel,argv[1]); + Tcl_AppendResult(interp,strdup(argv[1]),(char *)NULL); + if(pServ->pReader != NULL) + { + NetReadRegisterUserSocket(pServ->pReader, + SerialGetSocket(pData)); + } + return TCL_OK; + } + else + { + SerialError(iRet,pBueffel,79); + Tcl_AppendResult(interp,pBueffel,(char *) NULL); + SerialClose(pData); + free(pData); + return TCL_ERROR; + } +} +/*-------------------------------------------------------------------------- + Now, this interprets some commands: + -tmo val + will set a timeout value for the connection. Everything + else will be concatenated and sent to the device. + -sendterm text + defines the terminator which will be appended automatically + to each command. + -replyterm text + sets the expected reply terminator from the Macintosh + Serial Port server. + +----------------------------------------------------------------------------*/ +EXTERN int SurielSend(ClientData clientData, Tcl_Interp *interp, + int argc, char *argv[]) +{ + char pBueffel[256]; + char pAnswer[256]; + char *pErr = NULL; + int iRet, iMSR; + int i; + void *pData; + + pData = clientData; + + if(argc >= 2) + { + if(strcmp(argv[1],"-tmo") == 0) + { + if(argc >= 3) + { + iRet = Tcl_GetInt(interp,argv[2],&iMSR); + if(iRet != TCL_OK) + { + sprintf(pBueffel,"%s is not a valid number",argv[2]); + Tcl_AppendResult(interp,pBueffel,NULL); + return TCL_ERROR; + } + SerialConfig(&(pData),iMSR); + return TCL_OK; + } + else + { + Tcl_AppendResult(interp, "Expected parameter after -tmo",NULL); + return TCL_ERROR; + } + } + else if(strcmp(argv[1],"-sendterm") == 0) + { + if(argc < 3) + { + Tcl_AppendResult(interp, "Expected parameter after -tmo",NULL); + return TCL_ERROR; + } + iRet = SerialSendTerm(&(pData),argv[2]); + if(iRet != 1) + { + Tcl_AppendResult(interp,"To many characters for terminator",NULL); + return TCL_ERROR; + } + return TCL_OK; + } + else if(strcmp(argv[1],"-replyterm") == 0) + { + if(argc < 3) + { + Tcl_AppendResult(interp, "Expected parameter after -tmo",NULL); + return TCL_ERROR; + } + iRet = SerialATerm(&(pData),argv[2]); + if(!iRet) + { + Tcl_AppendResult(interp,"To many characters for terminator",NULL); + return TCL_ERROR; + } + return TCL_OK; + } + else if(strcmp(argv[1],"-put") == 0) + { + NetReadResetUser(pServ->pReader,SerialGetSocket(&(pData))); + if(argc > 2) + { + strcpy(pBueffel,argv[2]); + } + for(i = 3; i < argc; i++) + { + strcat(pBueffel," "); + strcat(pBueffel,argv[i]); + } + iRet = SerialSend(&(pData),pBueffel); + if(iRet != 1) + { + Tcl_AppendResult(interp,pAnswer,NULL); + return TCL_ERROR; + } + return TCL_OK; + } + else if(strcmp(argv[1],"-readable") == 0) + { + iRet = NetReadReadable(pServ->pReader,SerialGetSocket(&(pData))); + if(iRet) + { + Tcl_AppendResult(interp,"1",NULL); + return TCL_OK; + } + else + { + Tcl_AppendResult(interp,"0",NULL); + return TCL_OK; + } + } + else if(strcmp(argv[1],"-get") == 0) + { + if(NetReadReadable(pServ->pReader,SerialGetSocket(&(pData)))) + { + iRet = SerialReceive(&(pData),pAnswer, 255); + Tcl_AppendResult(interp,pAnswer,NULL); + if(iRet == 1) + { + return TCL_OK; + } + else + { + return TCL_ERROR; + } + } + Tcl_AppendResult(interp,"Not Readable",NULL); + return TCL_ERROR; + } + } + + + if(argc >= 2) + { + strcpy(pBueffel,argv[1]); + } + for(i = 2; i < argc; i++) + { + strcat(pBueffel," "); + strcat(pBueffel,argv[i]); + } + i = strlen(pBueffel); + iRet = SerialWriteRead(&(pData),pBueffel,pAnswer,254); + if(iRet != 1) + { + Tcl_AppendResult(interp,pAnswer,NULL); + return TCL_ERROR; + } + Tcl_AppendResult(interp,pAnswer,NULL); + return TCL_OK; +}