diff --git a/Makefile b/Makefile index 73c7d18e..929a3d63 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,8 @@ SOBJ = network.o ifile.o conman.o SCinter.o splitter.o passwd.o \ tasdrive.o tasscan.o synchronize.o definealias.o swmotor.o t_update.o \ hmcontrol.o userscan.o slsmagnet.o rs232controller.o lomax.o \ polterwrite.o fourlib.o motreg.o motreglist.o anticollider.o \ - s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) ecb.o ecbdriv.o + s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) ecb.o ecbdriv.o \ + ecbcounter.o MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o COUNTEROBJ = countdriv.o simcter.o counter.o diff --git a/countdriv.c b/countdriv.c index bdd6b8d4..bf421fa0 100644 --- a/countdriv.c +++ b/countdriv.c @@ -565,7 +565,7 @@ return COTERM; } /*-------------------------------------------------------------------------*/ - static int EL737Set(struct __COUNTER *self, int iCode, int iCter, + static int EL737Set(struct __COUNTER *self, char *name, int iCter, float fVal) { int iRet; @@ -576,7 +576,7 @@ pEL737 = (EL737st *)self->pData; assert(pEL737); - if(iCode == PARTHRESHOLD) + if(strcmp(name,"threshold") == 0) { sprintf(pCommand,"DL %1.1d %f\r",iCter,fVal); iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79); @@ -615,7 +615,7 @@ } } /*-------------------------------------------------------------------------*/ - static int EL737Get(struct __COUNTER *self, int iCode, int iCter, + static int EL737Get(struct __COUNTER *self, char *name, int iCter, float *fVal) { int iRet; @@ -626,7 +626,7 @@ pEL737 = (EL737st *)self->pData; assert(pEL737); - if(iCode == PARTHRESHOLD) + if(strcmp(name,"threshold") == 0) { sprintf(pCommand,"DL %1.1d\r",iCter); iRet = EL737_SendCmnd(&pEL737->pData,pCommand,pReply,79); diff --git a/countdriv.h b/countdriv.h index 55e4305a..9b0a05e3 100644 --- a/countdriv.h +++ b/countdriv.h @@ -55,9 +55,9 @@ int (*GetError)(struct __COUNTER *self, int *iCode, char *error, int iErrLen); int (*TryAndFixIt)(struct __COUNTER *self, int iCode); - int (*Set)(struct __COUNTER *self,int iCode, + int (*Set)(struct __COUNTER *self,char *name, int iCter, float fVal); - int (*Get)(struct __COUNTER *self,int iCode, + int (*Get)(struct __COUNTER *self,char *name, int iCter, float *fVal); int (*Send)(struct __COUNTER *self, char *pText, char *pReply, int iReplyLen); diff --git a/counter.c b/counter.c index 24f8ed9e..b84e41a1 100644 --- a/counter.c +++ b/counter.c @@ -50,6 +50,7 @@ #include "fupa.h" #include "status.h" #include "splitter.h" +#include "ecbcounter.h" /*-------------------------------------------------------------------------*/ /* The monitor callback data structure @@ -419,6 +420,10 @@ { KillSIMCounter(self->pDriv); } + else if(strcmp(self->pDriv->type,"ecb") == 0) + { + KillECBCounter(self->pDriv); + } else { assert(0); @@ -486,6 +491,7 @@ } /*-------------------------------------------------------------------------*/ + int MakeCounter(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { @@ -497,7 +503,8 @@ FuPaResult pParse; FuncTemplate MakeTemplate[] = { {"el737",3,{FUPATEXT,FUPAINT,FUPAINT}}, - {"sim",1,{FUPAFLOAT}} + {"sim",1,{FUPAFLOAT}}, + {"ecb",1,{FUPATEXT}} }; assert(pCon); @@ -506,7 +513,7 @@ argtolower(argc,argv); /* parse function template */ argx = &argv[2]; /* 0 = MakeCounter, 1 = counter name */ - iRet = EvaluateFuPa((pFuncTemplate)&MakeTemplate,2,argc-2,argx,&pParse); + iRet = EvaluateFuPa((pFuncTemplate)&MakeTemplate,3,argc-2,argx,&pParse); if(iRet < 0) /* I/O error */ { sprintf(pBueffel,"%s",pParse.pError); @@ -524,6 +531,9 @@ case 1: /* SIM */ pDriv = NewSIMCounter(argv[1],pParse.Arg[0].fVal); break; + case 2: /* ecb */ + pDriv = MakeECBCounter(pParse.Arg[0].text); + break; default: assert(0); /* internal error */ } @@ -743,7 +753,9 @@ {"stop",0,{0,0}}, {"mode",1,{FUPAOPT}}, {"preset",1,{FUPAOPT}}, - {"send",0,{0,0}} + {"send",0,{0,0}}, + {"setpar",3,{FUPATEXT,FUPAINT,FUPAFLOAT}}, + {"getpar",2,{FUPATEXT,FUPAOPT}} }; char *pMode[] = { "timer", @@ -759,7 +771,7 @@ /* parse function args */ argtolower(argc,argv); argx = &argv[1]; - iRet = EvaluateFuPa((pFuncTemplate)&ActionTemplate,20,argc-1,argx,&PaRes); + iRet = EvaluateFuPa((pFuncTemplate)&ActionTemplate,22,argc-1,argx,&PaRes); if(iRet < 0) { sprintf(pBueffel,"%s",PaRes.pError); @@ -903,7 +915,7 @@ break; case 14: /* get threshold value */ - iRet = self->pDriv->Get(self->pDriv,PARTHRESHOLD, + iRet = self->pDriv->Get(self->pDriv,"threshold", PaRes.Arg[0].iVal,&fVal); if(iRet <= 0) { @@ -936,7 +948,7 @@ return 0; } /* set threshold value */ - iRet = self->pDriv->Set(self->pDriv,PARTHRESHOLD, + iRet = self->pDriv->Set(self->pDriv,"threshold", PaRes.Arg[0].iVal,PaRes.Arg[1].fVal); if(iRet <= 0) { @@ -1048,6 +1060,46 @@ return 0; } break; + case 20: /* setpar*/ + if(!SCMatchRights(pCon,usMugger)) + { + return 0; + } + iRet = self->pDriv->Set(self->pDriv,PaRes.Arg[0].text, + PaRes.Arg[1].iVal, PaRes.Arg[2].fVal); + if(iRet == 1) + { + SCSendOK(pCon); + return 1; + } + else + { + self->pDriv->GetError(self->pDriv,&iRet,pError,79); + SCWrite(pCon,pError,eError); + return 0; + } + break; + case 21: /* getpar*/ + if(!SCMatchRights(pCon,usMugger)) + { + return 0; + } + iRet = self->pDriv->Get(self->pDriv,PaRes.Arg[0].text, + PaRes.Arg[1].iVal, &fVal); + if(iRet == 1) + { + sprintf(pBueffel,"%s.%s %d = %f",argv[0],PaRes.Arg[0].text, + PaRes.Arg[1].iVal, fVal); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + else + { + self->pDriv->GetError(self->pDriv,&iRet,pError,79); + SCWrite(pCon,pError,eError); + return 0; + } + break; default: assert(0); /* internal error */ } diff --git a/ecb.i b/ecb.i new file mode 100644 index 00000000..6853f58f --- /dev/null +++ b/ecb.i @@ -0,0 +1,23 @@ + +/*----------------------------------------------------------------------- + The ECB is a rack controller from Risoe based on a Z80 processor. + This module provides some functions for communicating with such a + device. This is an internal data structure definition file. + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2002, with some bits taken out of the + original tascom code. +------------------------------------------------------------------------*/ + + struct __ECB { + pObjectDescriptor pDes; + pGPIB gpib; + int boardNumber; + int ecbAddress; + int ecbDeviceID; + int lastError; + int encoder[3]; + int encoderDirty; + }ECB; + diff --git a/ecbcounter.c b/ecbcounter.c new file mode 100644 index 00000000..5eabad60 --- /dev/null +++ b/ecbcounter.c @@ -0,0 +1,520 @@ +/*---------------------------------------------------------------------------- + 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 "fortify.h" +#include "sics.h" +#include "ecb.h" +#include "countdriv.h" + +/*------------------ 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 */ +}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 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 ECBGetStatus(struct __COUNTER *self, float *fControl){ + pECBCounter pPriv = (pECBCounter)self->pData; + int status, result, scaler; + Z80_reg in, out; + int count; + + assert(pPriv); + + /* + read status bit + */ + status = ecbExecute(pPriv->ecb,STFRD,in,&out); + if(status != 1){ + self->iErrorCode = COMMERROR; + return HWFault; + } + if(out.d == 0){ + result = HWIdle; + } 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 stopScalers(pECBCounter self){ + int status; + Z80_reg in, out; + + status = ecbExecute(self->ecb,STOPS,in,&out); + if(status != 1){ + return COMMERROR; + } + return 1; +} +/*----------------------------------------------------------------------*/ +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; + } + + return OKOK; +} +/*======================================================================== + 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 ECBHalt(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 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->pData = pPriv; + return self; +} +/*=====================================================================*/ +void KillECBCounter(struct __COUNTER *self){ + DeleteCounterDriver(self); +} diff --git a/ecbcounter.h b/ecbcounter.h new file mode 100644 index 00000000..eb12145d --- /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/sicsstat.tcl b/sicsstat.tcl index b8c39bf0..e8ac652a 100644 --- a/sicsstat.tcl +++ b/sicsstat.tcl @@ -1,3 +1,6 @@ +# Counter counter +counter SetPreset 60.000000 +counter SetMode Timer # Motor a77 a77 sign 1.000000 a77 SoftZero 0.000000 diff --git a/simcter.c b/simcter.c index 608d504a..92a3442b 100644 --- a/simcter.c +++ b/simcter.c @@ -292,12 +292,12 @@ static float FAILRATE; return COREDO; } /*--------------------------------------------------------------------------*/ - static int SIMSet(struct __COUNTER *self, int iCode, int iCter, float FVal) + static int SIMSet(struct __COUNTER *self, char *name, int iCter, float FVal) { return 1; } /*--------------------------------------------------------------------------*/ - static int SIMGet(struct __COUNTER *self, int iCode, int iCter, float *fVal) + static int SIMGet(struct __COUNTER *self, char *name, int iCter, float *fVal) { *fVal = 25.999; return 1;