diff --git a/Makefile b/Makefile index ff7c8a84..d385b538 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,14 @@ FORTIFYOBJ = #--------------------------------------------------------------------------- +#========================================================================== +# assign if the National Instrument GPIB driver is available +NI= -DHAVENI +NIOBJ= nigpib.o +NILIB=-lgpibenet +#NI= +#NIOBJ= +#NILIB= #----- comment or uncomment if a difrac version is required # Do not forget to remove or add comments to ofac.c as well if changes @@ -50,7 +58,7 @@ 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 + s_rnge.o sig_die.o gpibcontroller.o $(NIOBJ) ecb.o ecbdriv.o MOTOROBJ = motor.o el734driv.o simdriv.o el734dc.o pipiezo.o pimotor.o COUNTEROBJ = countdriv.o simcter.o counter.o @@ -63,18 +71,18 @@ VELOOBJ = velo.o velosim.o velodorn.o velodornier.o #----- comment or uncomment the following according to operating system #------------- for Digital Unix -BINTARGET = bin -HDFROOT=/data/lnslib -CC=cc -EXTRA= -CFLAGS = -I$(HDFROOT)/include -Ihardsup -DHDF4 -DHDF5 -I. -std1 \ - -g -warnprotos -c +#BINTARGET = bin +#HDFROOT=/data/lnslib +#CC=cc +#EXTRA= +#CFLAGS = -I$(HDFROOT)/include -Ihardsup -DHDF4 -DHDF5 -I. -std1 \ +# -g -warnprotos -c #CFLAGS = -I$(HDFROOT)/include -DFORTIFY -DHDF4 -DHDF5 -Ihardsup -g \ # -std1 -warnprotos -c -LIBS = -L$(HDFROOT)/lib -Lhardsup -lhlib -Lmatrix -lmatrix -Ltecs \ - -ltecsl -ltcl8.0 -lfor $(HDFROOT)/lib/libhdf5.a \ - $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ - $(HDFROOT)/lib/libjpeg.a -lz -lm -ll -lc +#LIBS = -L$(HDFROOT)/lib -Lhardsup -lhlib -Lmatrix -lmatrix -Ltecs \ +# -ltecsl -ltcl8.0 -lfor $(HDFROOT)/lib/libhdf5.a \ +# $(HDFROOT)/lib/libmfhdf.a $(HDFROOT)/lib/libdf.a \ +# $(HDFROOT)/lib/libjpeg.a -lz -lm -ll -lc #------- for cygnus #HDFROOT=../HDF411 @@ -85,16 +93,16 @@ LIBS = -L$(HDFROOT)/lib -Lhardsup -lhlib -Lmatrix -lmatrix -Ltecs \ # -lmfhdf -ldf -ljpeg -lz -lm #---------- for linux -#BINTARGET=../bin -#HDFROOT=/usr/local -#CC=gcc -#CFLAGS = -I$(HDFROOT)/include -DHDF4 -Ihardsup -fwritable-strings \ -# -DCYGNUS -DNONINTF -g -c +BINTARGET=../../bin +HDFROOT=$(SINQDIR)/linux +CC=gcc +CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -Ihardsup \ + -fwritable-strings -DCYGNUS -DNONINTF -g -c #CFLAGS = -I$(HDFROOT)/include -Ihardsup -fwritable-strings -DFORTIFY \ # -DCYGNUS -DNONINTF -g -c -#LIBS= -L$(HDFROOT)/lib -Lhardsup -Ltecs -ltecsl -Lmatrix -lmatrix -lhlib \ -# -ltcl8.0 -lmfhdf -ldf -ljpeg -lz -lm -lg2c -ldl -#EXTRA=nintf.o +LIBS= -L$(HDFROOT)/lib -Lhardsup -Ltecs -ltecsl -Lmatrix -lmatrix -lhlib \ + $(NILIB) -ltcl -lhdf5 -lmfhdf -ldf -ljpeg -lz -lm -lg2c -ldl +EXTRA=nintf.o #--------------------------------- .c.o: diff --git a/Scommon.h b/Scommon.h index 6217f979..c5b25368 100644 --- a/Scommon.h +++ b/Scommon.h @@ -69,6 +69,7 @@ typedef enum { #define HWNoBeam 8 #define HWPause 9 #define HWWarn 10 +#define HWRedo 11 /* Sics uses some server options for some server configuration parameters. diff --git a/anticollider.c b/anticollider.c index 7f590847..70c58f94 100644 --- a/anticollider.c +++ b/anticollider.c @@ -1,6 +1,6 @@ /*---------------------------------------------------------------------- This is the implementation file for the AntiCollider, a complex movements - control module for SICS. See anticoliider.tex for more information. + control module for SICS. See anticollider.tex for more information. copyright: see file copyright @@ -18,7 +18,7 @@ /*--------------------------------------------------------------------- As there should be only one AntiCollider in a system, I use a static pointer to the AntiCollider here in order to facilitate access. - Otherwise more complex mechanisms must be divised in order to pass this + Otherwise more complex mechanisms must be devised in order to pass this pointer into ColliderSetValue and ColliderCheckStatus ----------------------------------------------------------------------*/ static pAntiCollider myCollider = NULL; diff --git a/ecb.c b/ecb.c new file mode 100644 index 00000000..31ee4ad0 --- /dev/null +++ b/ecb.c @@ -0,0 +1,413 @@ +/*----------------------------------------------------------------------- + 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 the implementation file. + + WARNING: This contains code which may be endian dependent! + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2002, with some bits taken from the original + tascom code. + -------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "ecb.h" +#include "ecb.i" +/*------------- private defines and error codes ------------------------*/ +#define ACKN ('\6') /* Acknowledge character */ +#define READ_BYTES 3 +#define WRITE_BYTES 4 +#define ECB_BYTES 65536L + +typedef union /* Used to swap bytes in 'address' and 'byte_count' */ + { + unsigned short word; + struct + { + unsigned char msb; /* Most significant byte */ + unsigned char lsb; /* Least significant byte */ + }b; + }Swap; +/* ------- error codes */ +#define ECBILLEGALFUNC -100 +#define ECBOVERFLOW -101 + +/*----------------------------------------------------------------------*/ +static int ecbSendFunc(pECB self, int func){ + unsigned char function, response; + int count, status; + + /* + send function code + */ + function = (unsigned char)func; + count = 1; + status = GPIBsend(self->gpib,self->ecbDeviceID,&function,count); + if(status < 0){ + self->lastError = status; + return 0; + } + + /* + read acknowledge byte + */ + status = GPIBread(self->gpib,self->ecbDeviceID,&response,count); + if(status < 0){ + self->lastError = status; + return 0; + } + if(response != ACKN){ + self->lastError = ECBILLEGALFUNC; + return 0; + } + return 1; +} +/*-----------------------------------------------------------------------*/ +int ecbExecute(pECB self, int func, Z80_reg in, Z80_reg *out){ + int count, status; + + assert(self != NULL); + assert(self->gpib != NULL); + self->lastError = 0; + + /* + send function code + */ + status = ecbSendFunc(self,func); + if(status <= 0){ + return status; + } + + /* + send input register + */ + count = 4; + status = GPIBsend(self->gpib,self->ecbDeviceID, &in, count); + if(status < 0){ + self->lastError = status; + return 0; + } + + /* + read result register + */ + status = GPIBread(self->gpib,self->ecbDeviceID, out, count); + if(status < 0){ + self->lastError = status; + return 0; + } + + return 1; +} +/*----------------------------------------------------------------------*/ +static int ecbPrepareIO(pECB self, int func, unsigned short address, + unsigned short byteCount){ + Swap save, adr, count; + int status, bytes; + + if(byteCount > ECB_BYTES){ + self->lastError = ECBOVERFLOW; + return 0; + } + + /* + Swap address and byteCount?? This may be a portability issue! + This may not be necessary on some platforms + */ + save.word = address; /* Swap address bytes */ + adr.b.lsb = save.b.msb; + adr.b.msb = save.b.lsb; + save.word = byteCount; /* Swap byte count bytes */ + count.b.lsb = save.b.msb; + count.b.msb = save.b.lsb; + + status = ecbSendFunc(self,func); + if(status <= 0){ + return status; + } + + /* + send address + */ + bytes = 2; + status = GPIBsend(self->gpib,self->ecbDeviceID,&adr,bytes); + if(status < 0){ + self->lastError = status; + return 0; + } + + /* + send byte count + */ + status = GPIBsend(self->gpib,self->ecbDeviceID,&count,bytes); + if(status < 0){ + self->lastError = status; + return 0; + } + + return 1; +} +/*-----------------------------------------------------------------------*/ +int ecbRead(pECB self, unsigned short address, + void *buffer, int byteCount){ + + int status, count; + + assert(self != NULL); + assert(self->gpib != NULL); + self->lastError = 0; + + status = ecbPrepareIO(self,READ_BYTES,address,(unsigned short)byteCount); + if(status <= 0){ + return 0; + } + + /* + actual read + */ + status = GPIBread(self->gpib,self->ecbDeviceID, buffer, byteCount); + if(status < 0){ + self->lastError = status; + return 0; + } + + return 1; +} +/*----------------------------------------------------------------------*/ +int ecbWrite(pECB self, unsigned short address, + void *buffer, int byteCount){ + + int status, count; + + assert(self != NULL); + assert(self->gpib != NULL); + self->lastError = 0; + + status = ecbPrepareIO(self,WRITE_BYTES,address,(unsigned short)byteCount); + if(status <= 0){ + return 0; + } + + /* + actual read + */ + status = GPIBsend(self->gpib,self->ecbDeviceID, buffer, byteCount); + if(status < 0){ + self->lastError = status; + return 0; + } + + return 1; +} +/*-----------------------------------------------------------------------*/ +void ecbErrorDescription(pECB self, char *buffer, int maxBuffer){ + int positive; + + switch(self->lastError){ + case ECBILLEGALFUNC: + strncpy(buffer,"Illegal ECB function called",maxBuffer); + return; + case ECBOVERFLOW: + strncpy(buffer, + "You tried to copy more then 64K onto the poor ECB, REFUSED!", + maxBuffer); + return; + } + + /* + GPIB error codes + */ + GPIBerrorDescription(self->gpib,self->lastError,buffer, maxBuffer); +} +/*----------------------------------------------------------------------*/ +void ecbClear(pECB self){ + GPIBclear(self->gpib, self->ecbDeviceID); +} +/*-----------------------------------------------------------------------*/ +int fixECBError(pECB self){ + int pos; + + switch(self->lastError){ + case ECBILLEGALFUNC: + case ECBOVERFLOW: + return HWFault; + } + + /* + GPIB error + */ + pos = -self->lastError; + switch(pos){ + case GPIBEABO: + return HWRedo; + default: + return HWFault; + } +} +/*------------------------------------------------------------------------*/ +int ECBAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pECB self = (pECB)pData; + Z80_reg in, out; + char pBuffer[80], pError[132]; + int status, iVal, func; + + assert(self != NULL); + + /* + Only managers will be allowed to wrestle directly with ECB + controllers. + */ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + if(argc < 2){ + SCWrite(pCon,"ERROR: keyword required for ECB",eError); + return 0; + } + + strtolower(argv[1]); + if(strcmp(argv[1],"func") == 0){ + if(argc < 7){ + SCWrite(pCon,"ERROR: require function code and four register values", + eError); + return 0; + } + status = Tcl_GetInt(pSics->pTcl, argv[2],&func); + if(status != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to int",eError); + return 0; + } + status = Tcl_GetInt(pSics->pTcl, argv[3],&iVal); + if(status != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to int",eError); + return 0; + } + in.d = (unsigned char)iVal; + status = Tcl_GetInt(pSics->pTcl, argv[4],&iVal); + if(status != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to int",eError); + return 0; + } + in.e = (unsigned char)iVal; + status = Tcl_GetInt(pSics->pTcl, argv[5],&iVal); + if(status != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to int",eError); + return 0; + } + in.b = (unsigned char)iVal; + status = Tcl_GetInt(pSics->pTcl, argv[6],&iVal); + if(status != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert argument to int",eError); + return 0; + } + in.c = (unsigned char)iVal; + + status = ecbExecute(self,func,in,&out); + if(status != 1){ + ecbErrorDescription(self,pBuffer,79); + sprintf(pError,"ERROR: %s", pBuffer); + SCWrite(pCon,pError,eError); + return 0; + } + sprintf(pBuffer,"%x %x %x %x", + out.d, out.e, out.c, out.c); + SCWrite(pCon,pBuffer,eValue); + return 1; + } else { + SCWrite(pCon,"ERROR: ECB does not understand keyword", eError); + return 0; + } +} +/*-----------------------------------------------------------------------*/ +void ECBKill(void *pData){ + pECB self = (pECB)pData; + + if(self == NULL){ + return; + } + + /* + Detaching here may be dangerous: If the GPIB has been deleted first, + this makes a core dump. Best is the GPIB keeps a list of attached + things and cleans them itself. + + GPIBdetach(self->gpib,self->ecbDeviceID); + */ + if(self->pDes){ + DeleteDescriptor(self->pDes); + } + free(self); +} +/*----------------------------------------------------------------------*/ +int MakeECB(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pECB self = NULL; + int address, status, boardNo; + pGPIB gpib = NULL; + char pError[132]; + + /* + we need a name, the GPIB controller and an address on the GPIB bus for + the ECB as arguments + */ + if(argc < 5){ + SCWrite(pCon,"ERROR: insufficient arguments to MakeECB",eError); + return 0; + } + gpib = FindCommandData(pSics,argv[2],"GPIB"); + if(gpib == NULL){ + sprintf(pError,"ERROR: no GPIB controller %s found", argv[2]); + SCWrite(pCon,pError,eError); + return 0; + } + status = Tcl_GetInt(pSics->pTcl,argv[3], &boardNo); + if(status != TCL_OK){ + sprintf(pError,"ERROR: failed to convert %s to integer",argv[3]); + SCWrite(pCon,pError,eError); + return 0; + } + status = Tcl_GetInt(pSics->pTcl,argv[4], &address); + if(status != TCL_OK){ + sprintf(pError,"ERROR: failed to convert %s to integer",argv[4]); + SCWrite(pCon,pError,eError); + return 0; + } + if(address < 0 || address > 30){ + SCWrite(pCon,"ERROR: invalid GPIB address specified",eError); + return 0; + } + + self = (pECB)malloc(sizeof(ECB)); + if(self == NULL){ + SCWrite(pCon,"ERROR: no memory to allocate ECB",eError); + return 0; + } + memset(self,0,sizeof(ECB)); + self->pDes = CreateDescriptor("ECB"); + if(self->pDes == NULL){ + SCWrite(pCon,"ERROR: no memory to allocate ECB",eError); + return 0; + } + self->gpib = gpib; + self->boardNumber = boardNo; + self->ecbAddress = address; + self->ecbDeviceID =GPIBattach(self->gpib,self->boardNumber, + self->ecbAddress,0, + 13,0,1); + if(self->ecbDeviceID <= 0){ + SCWrite(pCon,"ERROR: failed to initialize ECB connection", + eError); + ECBKill(self); + return 0; + } + AddCommand(pSics,argv[1],ECBAction,ECBKill,self); + return 1; +} + diff --git a/ecb.h b/ecb.h new file mode 100644 index 00000000..641767f7 --- /dev/null +++ b/ecb.h @@ -0,0 +1,61 @@ + +/*----------------------------------------------------------------------- + The ECB is a rack controller from Risoe based on a Z80 processor. + This module provides some functions for communicating with such a + device. + + WARNING: This contains code which may be endian dependent! + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2002, with some bits taken out of the + original tascom code. +------------------------------------------------------------------------*/ +#ifndef ECBCON +#define ECBCON +#include "gpibcontroller.h" + + +typedef struct { + unsigned char d; /* D register in Z80 */ + unsigned char e; /* E register in Z80 */ + unsigned char b; /* B register in Z80 */ + unsigned char c; /* C register in Z80 */ + } Z80_reg; + +/*-----------------------------------------------------------------------*/ + + typedef struct __ECB *pECB; + + int ecbExecute(pECB self, int func, Z80_reg in, Z80_reg *out); + int ecbRead(pECB self, unsigned short address, + void *buffer, int byteCount); + int ecbWrite(pECB self, unsigned short address, + void *buffer, int byteCount); + void ecbClear(pECB self); + int fixECBError(pECB self); + void ecbErrorDescription(pECB self, char *buffer, int maxBytes); + + +/*-----------------------------------------------------------------------*/ + + int MakeECB(SConnection *pCon, SicsInterp *pSics, + void *pData, + int ragc, char *argv[]); + + +/*---------------------------------------------------------------------- + for byte packing. result must be an 32 bit integer +----------------------------------------------------------------------*/ +typedef union /* Used to extract and load data to Z80 regs. */{ + unsigned int result; + struct + { + unsigned char byt0; /* Least significant byte */ + unsigned char byt1; + unsigned char byt2; + unsigned char byt3; /* Most significant byte */ + }b; +}Ecb_pack; + +#endif diff --git a/ecb.w b/ecb.w new file mode 100644 index 00000000..5acaf9f8 --- /dev/null +++ b/ecb.w @@ -0,0 +1,149 @@ +\subsection{The ECB Controller} +The ECB Controller is an electronic device created by the Risoe +neutron scattering institute. At its base is a Z80 8-bit +processor. This Z80 processor can perform certain functions such as +controlling count operations, running a motor etc. To this purpose +further electronic widgets are connected to the Z80's backplane. At +the other end is a GPIB controller which allows to discuss with the +Z80. + +This module now implements three basic functionalities of the ECB: +\begin{itemize} +\item Execute a function +\item Read some memory +\item Write some memory +\end{itemize} + +WARNING: this module contains code which may be endian dependend! + +In order to do this we need the following data structure: +@d ecbdat @{ + struct __ECB { + pObjectDescriptor pDes; + pGPIB gpib; + int boardNumber; + int ecbAddress; + int ecbDeviceID; + int lastError; + }ECB; +@} +The fields: +\begin{description} +\item[pDes] The standard SICS object descriptor. +\item[gpib] The GPIB controller used for accessing the ECB. +\item[boardNumber] The GPIB board number in the NI driver. +\item[ecbAddress] The GPIB address of the ECB controller. +\item[ecbDeviceID] The device ID assigned to the ECB when the ECB has +been attached to. +\item[lastError] The last error which occurred. +\end{description} + +A function in the ECB is executed by sending a function number first, +followed by the content of the Z80 4 registers. In order to do this a +data structure is required for these registers: + +@d z80 @{ +typedef struct { + unsigned char d; /* D register in Z80 */ + unsigned char e; /* E register in Z80 */ + unsigned char b; /* B register in Z80 */ + unsigned char c; /* C register in Z80 */ + } Z80_reg; +@} + +The function interface then looks like: + +@d ecbfunc @{ + typedef struct __ECB *pECB; + + int ecbExecute(pECB self, int func, Z80_reg in, Z80_reg *out); + int ecbRead(pECB self, unsigned short address, + void *buffer, int byteCount); + int ecbWrite(pECB self, unsigned short address, + void *buffer, int byteCount); + void ecbClear(pECB self); + int fixECBError(pECB self); + void ecbErrorDescription(pECB self, char *buffer, int maxBytes); + +@} +\begin{description} +\item[ecbExecute] tries to execute the ECB function func. The input register +content is in in, on success the outpt registers are stored in out. +\item[ecbRead] reads byteCount bytes from the ECB address address into +buffer. Please note that address in this contest is an address in the +ECB's memory space and not the GPIB address. +\item[ecbWrite] writes byteCount bytes from buffer to the ECB address +address. Please note that address in this contest is an address in the +ECB's memory space and not the GPIB address. +\item[ecbClear] tries to clear the ECB interface. +\item[fixECBError] tries to fix the last ECB error. +\item[ecbErrorDescription] retrieves a text description of the last +ECB problem. Max maxBytes of description are copied into buffer. +\end{description} + + +There is also an interface to the SICS interpreter for the ECB. This +can be useful for debugging and testing and as a tool for scripting +auxiliary equipment controlled through the ECB. The interface to the +SICS interpreter for the ECB is represented through the ECB Factory +function: +@d ecbint @{ + int MakeECB(SConnection *pCon, SicsInterp *pSics, + void *pData, + int ragc, char *argv[]); +@} + +@o ecb.h @{ +/*----------------------------------------------------------------------- + The ECB is a rack controller from Risoe based on a Z80 processor. + This module provides some functions for communicating with such a + device. + + WARNING: This contains code which may be endian dependent! + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2002, with some bits taken out of the + original tascom code. +------------------------------------------------------------------------*/ +#ifndef ECBCON +#define ECBCON +#include "gpibcontroller.h" + +@ +/*-----------------------------------------------------------------------*/ +@ +/*-----------------------------------------------------------------------*/ +@ + +/*---------------------------------------------------------------------- + for byte packing. result must be an 32 bit integer +----------------------------------------------------------------------*/ +typedef union /* Used to extract and load data to Z80 regs. */{ + unsigned int result; + struct + { + unsigned char byt0; /* Least significant byte */ + unsigned char byt1; + unsigned char byt2; + unsigned char byt3; /* Most significant byte */ + }b; +}Ecb_pack; + +#endif +@} + +@o ecb.i @{ +/*----------------------------------------------------------------------- + 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. +------------------------------------------------------------------------*/ +@ +@} + diff --git a/ecbdriv.c b/ecbdriv.c new file mode 100644 index 00000000..9823f1c3 --- /dev/null +++ b/ecbdriv.c @@ -0,0 +1,695 @@ +/*------------------------------------------------------------------------ + This is a motor driver for the Risoe motor controllers within the + ECB system. The motor is controlled through functions invoked in the + Z80 processor of the ECB system which is connected through a GPIB + bus to the wider world. This driver has to do a lot of extra things: + - it has to convert from physical values to motor steps. + - Quite a few parameters, such as ramping parameters, + have to be downloaded to the ECB + - Risoe motors may have a virtual encoder or a real encoder. + + This driver support only P2048a motor controllers, as these are the + only ones which seem to have arrived at PSI. The P1648 and Tridynamic + things are not supported. + + Multiplexed motors: Originally the ECB supported 24 motors. This did + prove to be not enough. Therefore another device called P2234e was + introduced which allowed to run 8 motors from one controller port. In this + case the motor parameters have to be copied to the ECB before + driving the motor. Multiplexing is selected through the parameter MULT. + MULT 0 means no multiplexing, MULT > 0 makes MULT the number of the + motor in the multiplexer. MULT is now also used to flag a download of + parameters to the ECB. In such a case MULT is -1. + + + Some of this code was taken from the tascom driver for the ECB. + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2003 + +--------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "motor.h" +#include "obpar.h" +#include "ecb.h" + +/*------------------------------------------------------------------------ +Parameter indexes in ObPar array and meanings +-------------------------------------------------------------------------*/ +#define ENCODER 0 /* encoder number, 0 if no encoder */ +#define CONTROL 1 /* control signals, > 1 means required. */ +#define RANGE 2 /* 0 = slow, 1 = fast */ +#define MULT 3 /* 0 = not multiplexed, > 0 multiplex motor number*/ +#define MULTCHAN 16 /* multiplexer channel */ +#define ACCTIME 4 /* acceleration time: 500, 1000 or 2000 milSecs */ +#define ROTDIR 5 /* rotation direction */ +#define STARTSPEED 6 /* start speed: 100-500 steps/s */ +#define MAXSPEED 7 /* maximum speed: 100-2000 steps/sec */ +#define SLOWAUTO 8 /* slow speed in auto mode */ +#define SLOWMAN 9 /* slow speed in manual mode */ +#define DELAY 10 /* start delay 0 - 2500 millSecs */ +#define OFFSET 11 /* encoder offset */ +#define TOLERANCE 12 /* tolerance in steps */ +#define STEPS2DEG 13 /* conversion factor motor steps to Degree */ +#define DEG2STEP 14 /* conversion factor from degree to encoder digits */ +#define BACKLASH 15 /* motor backlash */ + +#define MAXPAR 18 /* 1 extra for the sentinel, do not forget to initialize! */ + +/*------------------------------ ECB defines -------------------------*/ +#define MAX_ENCODER 40 +#define FENCOR 167 /* read encoder */ +#define MOREAD 145 /* read motor steps */ +#define MOPARA 140 /* motor parameter */ +#define MOCLOA 146 +#define ABS(x) (x < 0 ? -(x) : (x)) +#define MOSTEP 141 +#define MOSTAT 144 + +/********************* t-error codes *************************************/ +#define COMMERROR -300 +#define ECBMANUELL -301 +#define ECBINUSE -302 +#define UNIDENTIFIED -303 +#define ECBINHIBIT -304 +#define ECBRUNNING -305 +#define ECBSTART -306 +#define ECBLIMIT -307 +/*================== The Driver data structure ============================*/ + typedef struct __ECBMotorDriv { + /* general motor driver interface + fields. REQUIRED! + */ + float fUpper; /* upper limit */ + float fLower; /* lower limit */ + char *name; + int (*GetPosition)(void *self,float *fPos); + int (*RunTo)(void *self, float fNewVal); + int (*GetStatus)(void *self); + void (*GetError)(void *self, int *iCode, + char *buffer, int iBufLen); + int (*TryAndFixIt)(void *self,int iError, + float fNew); + int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); + + + /* ECB specific fields */ + pECB ecb; /* ECB controller for everything */ + int ecbIndex; /* motor index in ECB */ + long targetInSteps; + int errorCode; + ObPar driverPar[MAXPAR]; + } ECBMOTDriv, *pECBMotDriv; +/*======================================================================= + Reading the motor position means reading the encoder if such a thing + is present or the counted motor steps (Pseudo Encoder) if not. + If the ECB answers us, the value has to be converted to physical + values. + ----------------------------------------------------------------------*/ +static int readEncoder(pECBMotDriv self, long *digits){ + int status; + Z80_reg in, out; + Ecb_pack data; + + in.c = (unsigned char)ObVal(self->driverPar,ENCODER) + MAX_ENCODER; + status = ecbExecute(self->ecb,FENCOR,in,&out); + if(!status){ + self->errorCode = COMMERROR; + return status; + } + + /* pack bytes */ + data.b.byt3 = 0; + data.b.byt2 = out.b; + data.b.byt1 = out.b; + data.b.byt0 = out.e; + if(out.c != 1){ + *digits = -data.result; + } else { + *digits = data.result; + } + return OKOK; +} +/*---------------------------------------------------------------------*/ +static int readPseudoEncoder(pECBMotDriv self, long *digits){ + int status; + Z80_reg in, out; + Ecb_pack data; + + in.c = (unsigned char)self->ecbIndex; + status = ecbExecute(self->ecb,MOREAD,in,&out); + if(!status){ + self->errorCode = COMMERROR; + return status; + } + + /* pack bytes */ + data.b.byt3 = 0; + data.b.byt2 = out.b; + data.b.byt1 = out.b; + data.b.byt0 = out.e; + if(out.c != 1){ + *digits = -data.result; + } else { + *digits = data.result; + } + return OKOK; +} +/*----------------------------------------------------------------------*/ +int ECBMOTGetPos(void *pData, float *fPos){ + pECBMotDriv self = (pECBMotDriv)pData; + long digits = 0; + int status; + double step2degree; + + assert(self); + self->errorCode = 0; + + if((int)ObVal(self->driverPar,ENCODER) > 0){ + status = readEncoder(self, &digits); + } else { + status = readPseudoEncoder(self, &digits); + } + step2degree = ObVal(self->driverPar,STEPS2DEG); + if(step2degree == 0.0){ + step2degree = 1.; + } + *fPos = (float)( (double)digits/step2degree); + + return status; +} +/*======================================================================== +In order to start a motor we need to do a couple of steps: + - check if the motors parameters have been changed or it is a multiplexed + motor. In each case download the motor parameters. + - the direction of the motor has to be determined, the speed to be + selected etc. + - Then the motor can be started. + ------------------------------------------------------------------------*/ +static int mustDownload(pECBMotDriv self){ + int multi; + + multi = (int)nintf(ObVal(self->driverPar,MULT)); + if(multi > 0 || multi < 0) { + return 1; + } else { + return 0; + } +} +/*--------------------------------------------------------------------*/ +static int checkMotorResult(pECBMotDriv self, Z80_reg out){ + /* + checks the return values from a motor function invocation + and sets error codes in case of problems. + */ + if(out.c == '\0'){ + switch(out.b){ + case 128: + self->errorCode = ECBMANUELL; + break; + case 64: + self->errorCode = ECBINHIBIT; + break; + case 32: + self->errorCode = ECBRUNNING; + break; + case 1: + self->errorCode = ECBSTART; + break; + case 16: + self->errorCode = ECBLIMIT; + break; + case 4: + self->errorCode = ECBINUSE; + break; + default: + self->errorCode = UNIDENTIFIED; + break; + } + return 0; + } else { + return 1; + } +} +/*---------------------------------------------------------------------*/ +static int loadAcceleration(pECBMotDriv self){ + unsigned char parameter; + Z80_reg in, out; + int accel, status; + + accel = (int)nintf(ObVal(self->driverPar,ACCTIME)); + if(accel == 500){ + parameter = 1; + }else if(accel == 1000){ + parameter = 2; + }else if(accel == 2000){ + parameter = 3; + } else { + parameter = 0; + } + /* + apply rotation direction mask + */ + if(ObVal(self->driverPar,ROTDIR) < 0){ + parameter += 128; + } + in.c = (unsigned char)self->ecbIndex; + in.b = 7; + in.e = parameter; + status = ecbExecute(self->ecb,MOPARA,in,&out); + if(!status){ + self->errorCode = COMMERROR; + return 0; + } + + if(!checkMotorResult(self, out)){ + return 0; + } + + return 1; +} +/*--------------------------- speed tables ------------------------------*/ +#define SPEED_TAB3 64 /* Size of speed table */ +const unsigned int low_2048[SPEED_TAB3] = { + 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, + 16, 20, 24, 28, 32, 36, 40, 44, 48, 56, + 64, 72, 80, 88, 96,104,112,120,128,136, + 144,152,160,168,176,184,192,200,208,216, + 224,236,248,260,272,284,296,308,320,332, + 344,356,368,380,392,404,416,428,440,452, + 464,476,488,500 }; + +#define SPEED_TAB4 96 /* Size of speed table */ +const unsigned int high_2048[SPEED_TAB4] = { + 11, 15, 20, 27, 36, 47, 59, 74, + 93, 107, 124, 143, 165, 190, 213, 239, + 268, 298, 331, 368, 405, 446, 491, 536, + 585, 632, 683, 731, 783, 827, 873, 922, + 974, 1028, 1085, 1146, 1211, 1278, 1349, 1424, + 1503, 1587, 1675, 1720, 1820, 1913, 2014, 2123, + 2237, 2360, 2483, 2620, 2755, 2905, 3058, 3221, + 3384, 3575, 3756, 3945, 4150, 4370, 4600, 4800, + 5000, 5250, 5533, 5822, 6120, 6440, 6770, 7090, + 7450, 7800, 8130, 8500, 8900, 9320, 9730, 10200, + 10700, 11200, 11700, 12200, 12800, 13300, 13900, 14500, + 15100, 15800, 16700, 17300, 18000, 18600, 19300, 20000 }; +/*---------------------------------------------------------------------*/ +static unsigned char getSpeedIndex(pECBMotDriv self, int value){ + unsigned char index; + const unsigned int *table; + int range, length; + + range = (int)nintf(ObVal(self->driverPar,RANGE)); + if(range == 0){ + table = low_2048; + length = SPEED_TAB3; + } else { + table = high_2048; + length = SPEED_TAB4; + } + + for(index = 0; index < length-1; index++){ + if(table[index] <= value){ + break; + } + } + return index; +} +/*--------------------------------------------------------------------*/ +static int loadSpeed(pECBMotDriv self, float value, int code){ + unsigned char parameter; + Z80_reg in, out; + int accel, status; + + parameter = getSpeedIndex(self,value); + + in.c = (unsigned char)self->ecbIndex; + in.b = code; + in.e = parameter; + status = ecbExecute(self->ecb,MOPARA,in,&out); + if(!status){ + self->errorCode = COMMERROR; + return 0; + } + if(!checkMotorResult(self, out)){ + return 0; + } + return 1; +} +/*-------------------------------------------------------------------*/ +static int loadDelay(pECBMotDriv self){ + int parameter; + Z80_reg in, out; + int accel, status; + unsigned char control; + + parameter = (int)nintf(ObVal(self->driverPar,DELAY)); + control = (unsigned char)nintf(ObVal(self->driverPar,CONTROL)); + if(control & 3){ + parameter = 5; + } else{ + parameter/= 10; + } + in.c = (unsigned char)self->ecbIndex; + in.b = 8; + in.e = parameter; + status = ecbExecute(self->ecb,MOPARA,in,&out); + if(!status){ + self->errorCode = COMMERROR; + return 0; + } + + if(!checkMotorResult(self, out)){ + return 0; + } + + return 1; +} +/*---------------------------------------------------------------------*/ +static int loadMulti(pECBMotDriv self){ + unsigned char multi, mult_chan; + Z80_reg in, out; + int status; + + multi = nintf(ObVal(self->driverPar,MULT)); + if(multi <= 0){ + return 1; /* not multiplexed */ + } + + mult_chan = (unsigned char)nintf(ObVal(self->driverPar,MULTCHAN)); + in.b = -1; /* SET_PORT */ + in.d = (unsigned char)(multi + (mult_chan << 4)); + in.e = self->ecbIndex; + status = ecbExecute(self->ecb,MOPARA,in,&out); + if(status != 1){ + self->errorCode = COMMERROR; + return 0; + } + return 1; +} +/*----------------------------------------------------------------------*/ +static int downloadECBParam(pECBMotDriv self){ + int status, parameter; + unsigned char func_code; + Z80_reg in, out; + + /* + We assume that all parameters have useful values. It is the task of + SetDriverPar to ensure just that! + */ + if(status = loadAcceleration(self) <= 0){ + return 0; + } + + if(status = loadSpeed(self,ObVal(self->driverPar,STARTSPEED),6) <= 0){ + return 0; + } + + if(status = loadSpeed(self,ObVal(self->driverPar,MAXSPEED),5) <= 0){ + return 0; + } + + if(status = loadSpeed(self,ObVal(self->driverPar,SLOWAUTO),4) <= 0){ + return 0; + } + + if(status = loadSpeed(self,ObVal(self->driverPar,SLOWMAN),10) <= 0){ + return 0; + } + + if(status = loadDelay(self) <= 0){ + return 0; + } + + if(status = loadMulti(self) <= 0){ + return 0; + } + + /* + It would be good practice to read the parameters written back + in order to check them. This does not seem to be supported with the + ECB system though. + */ + if(ObVal(self->driverPar,MULT) < 0.){ + self->driverPar[MULT].fVal = .0; + } + + return 1; +} +/*--------------------------------------------------------------------*/ +int degree2Step(pECBMotDriv self, float degree) +{ + double steps; + + steps = degree*ObVal(self->driverPar,STEPS2DEG); + if (ObVal(self->driverPar,ENCODER) > .0) + steps = steps*ObVal(self->driverPar,DEG2STEP); + if(degree < 0){ + steps = - steps; + } + return ((int) steps); +} +/*-----------------------------------------------------------------------*/ +static int ECBRunTo(void *pData, float newPosition){ + pECBMotDriv self = (pECBMotDriv)pData; + long digits = 0; + int status; + float oldValue, diff, steps2degree, backlash; + Ecb_pack data; + Z80_reg in, out; + + assert(self); + + if(mustDownload(self)){ + status = downloadECBParam(self); + if(!status){ + return 0; + } + } + + /* + read old position + */ + status = ECBMOTGetPos(self,&oldValue); + if(status != 1){ + return status; + } + + /* + do not start if there + */ + diff = newPosition - oldValue; + steps2degree= ObVal(self->driverPar,STEPS2DEG); + if(ABS(diff) <= .5/steps2degree + ObVal(self->driverPar,TOLERANCE)){ + return OKOK; + } + + /* + write control data + */ + in.d = 0; + if(diff > .0){ + in.d |= 32; /* positive direction */ + } + in.d |= 16; /* interrupts */ + if(nintf(ObVal(self->driverPar,RANGE)) == 1.){ + in.d |= 64; /* fast speed */ + } + in.c = (unsigned char)self->ecbIndex; + status = ecbExecute(self->ecb,MOCLOA,in,&out); + if(status != 1){ + self->errorCode = COMMERROR; + return 0; + } + + /* + calculate steps + */ + backlash = ObVal(self->driverPar,BACKLASH); + if(diff < 0){ + diff = -diff; + if(backlash > 0){ + diff += backlash; + } + } else { + if(backlash < 0){ + diff -= backlash; + } + } + data.result = degree2Step(self,diff); + + /* + finally start the motor + */ + in.b = data.b.byt2; + in.d = data.b.byt1; + in.e = data.b.byt0; + in.c = (unsigned char)self->ecbIndex; + status = ecbExecute(self->ecb,MOSTEP,in,&out); + if(status != 1){ + self->errorCode = COMMERROR; + return 0; + } + + if(!checkMotorResult(self, out)){ + return 0; + } + + return OKOK; +} +/*=======================================================================*/ +static int ECBGetStatus(void *pData){ + pECBMotDriv self = (pECBMotDriv)pData; + Z80_reg in, out; + int status; + + assert(self); + + in.c = (unsigned char)self->ecbIndex; + in.b = 12; + status = ecbExecute(self->ecb,MOSTAT,in,&out); + if(status != 1){ + self->errorCode = COMMERROR; + return HWFault; + } + + status = checkMotorResult(self,out); + if(status == 0){ + if(self->errorCode == ECBRUNNING){ + self->errorCode = 0; + return HWBusy; + } else { + return HWFault; + } + } else { + return HWIdle; + } +} +/*======================================================================*/ +static void ECBGetError(void *pData, int *iCode, char *buffer, int bufferlen){ + pECBMotDriv self = (pECBMotDriv)pData; + char pBueffel[132]; + + assert(self); + + *iCode = self->errorCode; + switch(self->errorCode){ + case COMMERROR: + strncpy(buffer,"communication problem with ECB",bufferlen); + break; + case ECBMANUELL: + strncpy(buffer,"ECB is in manual mode, trying to switch...",bufferlen); + break; + case ECBINUSE: + strncpy(buffer,"Power supply is in use",bufferlen); + break; + case ECBINHIBIT: + strncpy(buffer,"motor is inhibited",bufferlen); + break; + case ECBRUNNING: + strncpy(buffer,"motor is running",bufferlen); + break; + case ECBSTART: + strncpy(buffer,"failed to start motor",bufferlen); + break; + case ECBLIMIT: + strncpy(buffer,"hit limit switch",bufferlen); + break; + default: + strncpy(buffer,"unidentified error code",bufferlen); + break; + } +} +/*=======================================================================*/ +static int ECBTryAndFixIt(void *pData, int iCode, float fNew){ + pECBMotDriv self = (pECBMotDriv)pData; + int result; + Z80_reg in, out; + + assert(self); + + switch(iCode){ + case ECBMANUELL: + in.d =1 ; + ecbExecute(self->ecb,162,in,&out); + result = MOTREDO; + break; + case COMMERROR: + ecbClear(self->ecb); + result = MOTREDO; + break; + default: + result = MOTFAIL; + break; + } + return result; +} +/*========================================================================*/ +static int ECBHalt(void *pData){ + pECBMotDriv self = (pECBMotDriv)pData; + Z80_reg in, out; + unsigned char par = 2; + + assert(self); + + if(nintf(ObVal(self->driverPar,RANGE)) == 1){ + par |= 64; + } + + in.b = 9; + in.e = par; + ecbExecute(self->ecb,MOPARA,in,&out); + return 1; +} +/*=======================================================================*/ +static int ECBGetDriverPar(void *pData,char *name, float *value){ + pECBMotDriv self = (pECBMotDriv)pData; + ObPar *par = NULL; + + assert(self); + + par = ObParFind(self->driverPar,name); + if(par != NULL){ + *value = par->fVal; + return 1; + } else { + return 0; + } +} +/*=====================================================================*/ +static int ECBSetDriverPar(void *pData, SConnection *pCon, char *name, + float newValue){ + pECBMotDriv self = (pECBMotDriv)pData; + int parNumber; + char pBueffel[256]; + float correctedValue; + + parNumber = ObParIndex(self->driverPar,name); + if(parNumber < 0){ + return 0; + } + + /* + only managers shall edit these parameters.... + */ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + + + assert(self); + return 1; +} diff --git a/el734dc.c b/el734dc.c index 0f138dfd..c5677963 100644 --- a/el734dc.c +++ b/el734dc.c @@ -498,6 +498,7 @@ { return NULL; } + memset(pDriv,0,sizeof(EL734Driv)); /* fill in some of the data entered */ pDriv->hostname = strdup(hostname); @@ -527,7 +528,6 @@ pDriv->GetError = GetErr; pDriv->GetStatus = GetStat; pDriv->Halt = Halt; - pDriv->ContinueAfterWarn = MoDrivXXXContinue; pDriv->TryAndFixIt = FixError; diff --git a/el734driv.c b/el734driv.c index 52aede0a..10835d86 100644 --- a/el734driv.c +++ b/el734driv.c @@ -65,11 +65,6 @@ #define MSROK -47 #define MSRREF -48 #define MSRFAULT -49 -/*------------------------------------------------------------------------*/ - int MoDrivXXXContinue(void *pData) - { - return 0; - } /* --------------------------------------------------------------------------*/ static int GetPos(void *self, float *fData) { @@ -502,6 +497,7 @@ { return NULL; } + memset(pDriv,0,sizeof(EL734Driv)); /* fill in some of the data entered */ pDriv->hostname = strdup(hostname); @@ -531,7 +527,6 @@ pDriv->GetError = GetErr; pDriv->GetStatus = GetStat; pDriv->Halt = Halt; - pDriv->ContinueAfterWarn = MoDrivXXXContinue; pDriv->TryAndFixIt = FixError; diff --git a/fourlib.c b/fourlib.c index 63809e98..da99e2a5 100644 --- a/fourlib.c +++ b/fourlib.c @@ -188,8 +188,8 @@ void pol2det(psdDescription *psd, double gamma, double nu, int *x, int *y){ g = psd->distance*(1. + tn*tn +tn*tn*td*td); zobs = psd->distance*(atan(tn*e) + asin(f/g)); xobs = td*(psd->distance*cos(zobs/psd->distance)); - *y = (int)nint(psd->yZero + zobs/psd->yScale); - *x = (int)nint(psd->xZero + xobs/psd->xScale); + *y = (int)rint(psd->yZero + zobs/psd->yScale); + *x = (int)rint(psd->xZero + xobs/psd->xScale); } /*--------------- bisecting geometry code -----------------------------*/ diff --git a/gpib.w b/gpib.w new file mode 100644 index 00000000..0328f1b3 --- /dev/null +++ b/gpib.w @@ -0,0 +1,123 @@ +\subsection{GPIB Controller} +GPIB (or IEEE-488) is a 8 bit bus system. The system contains a +controller and up to 30 devices. GPIB will be used at PSI in the Risoe +instruments. And possibly others. The main stay GPIB controller will +be the National Instruments ENET-100 GPIB/TCPIP bridge. But several +drivers will be needed: +\begin{itemize} +\item A simulation +\item The original NI driver +\item Possibly a direct board level NI driver (not for ENET, but PCI) +\item Possibly a reverse engineered TCP/IP only driver. +\end{itemize} +For this reason the controller is made in a polymorphic fashion. + +This requires the following data structure: +@d gpibdat @{ + struct __GPIB { + pObjectDescriptor pDes; + int (*attach)(int boardNo, int address, + int secondaryAddress, + int tmo, int eot, int eos); + int (*detach)(int devID); + int (*send)(int devID, void *buffer, + int count); + int (*read)(int devID, void *buffer, + int count); + int (*clear)(int devID); + void (*getErrorDescription)(int code, + char *buffer, int maxCount); + }GPIB; +@} + +The interface for this controller: +@d gpibint @{ + typedef struct __GPIB *pGPIB; + + int GPIBattach(pGPIB self, int boardNo, + int address, int secondaryAddress, + int tmo, int eot, int eos); + int GPIBdetach(pGPIB self, int devID); + int GPIBsend(pGPIB self, int devID, void *buffer, int bytesToWrite); + int GPIBread(pGPIB self, int devID, void *buffer, int bytesToRead); + void GPIBclear(pGPIB self, int devID); + void GPIBerrorDescription(pGPIB self, int code, + char *buffer, int maxBuffer); +@} + +All functions return a negative value on failure. All functions takes +as their first argument a pointer to a GPIB structure. +\begin{description} +\item[GPIBattach] initialises the connection to a specific device on +the GPIB bus. The parameters: +\begin{description} +\item[boardNo] The NI board number +\item[address] The address of the device on the bus. +\item[secondaryAddress] The secondary address of th device. +\item[tmo] The timeout for this device. +\item[eot] termination thing I do not understand. +\item[eos] another termination thing. +\end{description} +This call retuns an integer devID which has to be used in calls to the +other functions. +\item[GPIBdetach] closes the connection to the device devID. +\item[GPIBsend] sends bytesToWrite bytes from buffer to the device +identified through devID. +\item[GPIBread] reads bytesToRead bytes from the device +identified through devID into buffer. buffer has to be large enough to +accomodate bytesToRead bytes. +\item[GPIBclear] tries to clear the GPIB device. +\item[GPIBerrorDescription] copies at max MaxBuffer bytes or error +description for code into buffer. +\end{description} + + +There is also an interpreter interface to the GPIB controller: + +@d gpibsics @{ + int MakeGPIB(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + int GPIBAction(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + +@} + +@o gpibcontroller.h @{ +/*---------------------------------------------------------------------- + Interface to a GPIB controller. + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2003 +------------------------------------------------------------------------*/ +#ifndef GPIBCONTROLLER +#define GPIBCONTROLLER + +/* + error codes +*/ +#define GPIBARG 4 +#define GPIBEDVR 0 +#define GPIBENEB 7 +#define GPIBEABO 6 +#define GPIBEADR 3 +#define GPIBEBUS 14 +#define GPIBENOL 2 + +@ + +@ + +#endif +@} + +@o gpibcontroller.i @{ +/*----------------------------------------------------------------------- + GPIBcontroller structure. Automatically generated file, modify in + gpib.w and run nuweb. +-----------------------------------------------------------------------*/ + +@ +@} \ No newline at end of file diff --git a/gpibcontroller.c b/gpibcontroller.c new file mode 100644 index 00000000..583b1a1c --- /dev/null +++ b/gpibcontroller.c @@ -0,0 +1,257 @@ +/*---------------------------------------------------------------------- + Interface to a GPIB controller. This is the implementation file. + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2003 +------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include "splitter.h" +#include "gpibcontroller.h" +#include "gpibcontroller.i" +/*----------------------------------------------------------------------*/ +int GPIBattach(pGPIB self, int boardNo, int address, + int secondaryAddress, int tmo, int eot, int eos){ + return self->attach(boardNo,address,secondaryAddress,tmo,eot,eos); +} +/*---------------------------------------------------------------------*/ +int GPIBdetach(pGPIB self, int devID){ + return self->detach(devID); +} +/*----------------------------------------------------------------------*/ +int GPIBsend(pGPIB self, int devID, void *buffer, int bytesToWrite){ + return self->send(devID, buffer,bytesToWrite); +} +/*--------------------------------------------------------------------*/ +int GPIBread(pGPIB self, int devID, void *buffer, int bytesToRead){ + return self->read(devID, buffer,bytesToRead); +} +/*--------------------------------------------------------------------*/ +void GPIBclear(pGPIB self, int devID){ + return self->clear(devID); +} +/*--------------------------------------------------------------------*/ +void GPIBerrorDescription(pGPIB self, int code, char *buffer, int maxBuf){ + return self->getErrorDescription(code, buffer,maxBuf); +} +/*------------------------------------------------------------------- + These are void implementations of the functions for simulation + purposes + ----------------------------------------------------------------------*/ +static int SIMattach(int boardNo, int address, int secondaryAddress, + int tmo, int eoi, int eot){ + return 1; +} +/*----------------------------------------------------------------------*/ +static int SIMdetach(int devID){ + return 1; +} +/*---------------------------------------------------------------------*/ +static int SIMsend(int devID, void *buffer, int bytesToWrite){ + return 1; +} +/*--------------------------------------------------------------------*/ +static int SIMread(int devID, void *buffer, int bytesToRead){ + return 1; +} +/*--------------------------------------------------------------------*/ +static int SIMclear(int devID){ + return; +} +/*---------------------------------------------------------------------*/ +static void SIMerror(int code, char *buffer, int maxBuf){ + strncpy(buffer,"Unknown simulated error",maxBuf); +} +/*---------------------------------------------------------------------*/ +void GPIBKill(void *pData){ + pGPIB self = NULL; + if(pData != NULL){ + self = (pGPIB)pData; + if(self->pDes){ + DeleteDescriptor(self->pDes); + } + free(pData); + } +} +/*---------------------------------------------------------------------*/ +int GPIBAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pGPIB self = (pGPIB)pData; + int boardID, devID, tmo, count, eoi, eot, address, + secondaryAddress, status; + char pBuffer[1024]; + + assert(self != NULL); + + /* + Only managers will be allowed to wrestle directly with GPIB + controllers. + */ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + + if(argc > 1){ + strtolower(argv[1]); + if(strcmp(argv[1],"attach") == 0){ + /* the attach command */ + if(argc < 8){ + SCWrite(pCon,"ERROR: insufficient number of arguments to attach", + eError); + return 0; + } + count = 0; + count += Tcl_GetInt(pSics->pTcl,argv[2],&boardID); + count += Tcl_GetInt(pSics->pTcl,argv[3],&address); + count += Tcl_GetInt(pSics->pTcl,argv[4],&secondaryAddress); + count += Tcl_GetInt(pSics->pTcl,argv[5],&tmo); + count += Tcl_GetInt(pSics->pTcl,argv[6],&eot); + count += Tcl_GetInt(pSics->pTcl,argv[7],&eoi); + if(count != 6*TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert arguments to integer", + eError); + return 0; + } + status = GPIBattach(self,boardID, address, secondaryAddress, + tmo,eot,eoi); + if(status > 0){ + sprintf(pBuffer,"%d",status); + SCWrite(pCon,pBuffer,eValue); + return 1; + } else { + sprintf(pBuffer,"ERROR: error %d on attach", status); + SCWrite(pCon,pBuffer,eError); + return 0; + } + } else if(strcmp(argv[1],"detach") == 0){ + /* + detach command + */ + if(argc < 2){ + SCWrite(pCon,"ERROR: insufficient number of arguments to dettach", + eError); + return 0; + } + if(Tcl_GetInt(pSics->pTcl,argv[2],&devID) != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert arguments to integer", + eError); + return 0; + } + status = GPIBdetach(self,devID); + if(status > 0){ + SCSendOK(pCon); + return 1; + } else { + sprintf(pBuffer,"ERROR: error %d on dettach", status); + SCWrite(pCon,pBuffer,eError); + return 0; + } + } else if(strcmp(argv[1],"send") == 0){ + /* + send command + */ + if(argc < 2){ + SCWrite(pCon,"ERROR: insufficient number of arguments to send", + eError); + return 0; + } + if(Tcl_GetInt(pSics->pTcl,argv[2],&devID) != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert arguments to integer", + eError); + return 0; + } + Arg2Text(argc-2,argv+2,pBuffer,1023); + status = GPIBsend(self,devID,pBuffer, strlen(pBuffer)); + if(status > 0){ + SCSendOK(pCon); + return 1; + } else { + sprintf(pBuffer,"ERROR: error %d on send", status); + SCWrite(pCon,pBuffer,eError); + return 0; + } + } else if(strcmp(argv[1],"read") == 0){ + /* + read command + */ + if(argc < 2){ + SCWrite(pCon,"ERROR: insufficient number of arguments to read", + eError); + return 0; + } + if(Tcl_GetInt(pSics->pTcl,argv[2],&devID) != TCL_OK){ + SCWrite(pCon,"ERROR: failed to convert arguments to integer", + eError); + return 0; + } + status = GPIBread(self,devID,pBuffer, 1023); + if(status > 0){ + SCWrite(pCon,pBuffer,eValue); + return 1; + } else { + sprintf(pBuffer,"ERROR: error %d on send", status); + SCWrite(pCon,pBuffer,eError); + return 0; + } + } else { + SCWrite(pCon,"ERROR: command not recognized",eError); + return 0; + } + } else { + SCWrite(pCon,"ERROR: no command given to GPIB",eError); + return 0; + } +} + +/*--------------------------------------------------------------------*/ +#ifdef HAVENI +extern void NIassign(pGPIB self); +#endif + +int MakeGPIB(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pGPIB self = NULL; + + if(argc < 3){ + SCWrite(pCon,"ERROR: insufficient number of arguments to MakeGPIB", + eError); + return 0; + } + + self = (pGPIB)malloc(sizeof(GPIB)); + if(self == NULL){ + SCWrite(pCon,"ERROR: cannot allocate memory in MakeGPIB",eError); + return 0; + } + memset(self,0,sizeof(GPIB)); + + self->pDes = CreateDescriptor("GPIB"); + strtolower(argv[2]); + if(strcmp(argv[2],"sim") == 0){ + self->attach = SIMattach; + self->detach = SIMdetach; + self->send = SIMsend; + self->read = SIMread; + self->clear = SIMclear; + self->getErrorDescription = SIMerror; +#ifdef HAVENI + } else if(strcmp(argv[2],"ni") == 0){ + NIassign(self); +#endif + } else { + SCWrite(pCon,"ERROR: GPIB driver not recognised",eError); + return 0; + } + + return AddCommand(pSics,argv[1],GPIBAction,GPIBKill,self); +} + + + + + diff --git a/gpibcontroller.h b/gpibcontroller.h new file mode 100644 index 00000000..943c22a8 --- /dev/null +++ b/gpibcontroller.h @@ -0,0 +1,47 @@ + +/*---------------------------------------------------------------------- + Interface to a GPIB controller. + + copyright: see file COPYRIGHT + + Mark Koennecke, January 2003 +------------------------------------------------------------------------*/ +#ifndef GPIBCONTROLLER +#define GPIBCONTROLLER + +/* + error codes +*/ +#define GPIBARG 4 +#define GPIBEDVR 0 +#define GPIBENEB 7 +#define GPIBEABO 6 +#define GPIBEADR 3 +#define GPIBEBUS 14 +#define GPIBENOL 2 + + + typedef struct __GPIB *pGPIB; + + int GPIBattach(pGPIB self, int boardNo, + int address, int secondaryAddress, + int tmo, int eot, int eos); + int GPIBdetach(pGPIB self, int devID); + int GPIBsend(pGPIB self, int devID, void *buffer, int bytesToWrite); + int GPIBread(pGPIB self, int devID, void *buffer, int bytesToRead); + void GPIBclear(pGPIB self, int devID); + void GPIBerrorDescription(pGPIB self, int code, + char *buffer, int maxBuffer); + + + + int MakeGPIB(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + int GPIBAction(SConnection *pCon, SicsInterp *pSics, + void *pData, + int argc, char *argv[]); + + + +#endif diff --git a/gpibcontroller.i b/gpibcontroller.i new file mode 100644 index 00000000..766fffe7 --- /dev/null +++ b/gpibcontroller.i @@ -0,0 +1,22 @@ + +/*----------------------------------------------------------------------- + GPIBcontroller structure. Automatically generated file, modify in + gpib.w and run nuweb. +-----------------------------------------------------------------------*/ + + + struct __GPIB { + pObjectDescriptor pDes; + int (*attach)(int boardNo, int address, + int secondaryAddress, + int tmo, int eot, int eos); + int (*detach)(int devID); + int (*send)(int devID, void *buffer, + int count); + int (*read)(int devID, void *buffer, + int count); + int (*clear)(int devID); + void (*getErrorDescription)(int code, + char *buffer, int maxCount); + }GPIB; + diff --git a/hardsup/Makefile b/hardsup/Makefile index a773cbc2..887d6a69 100644 --- a/hardsup/Makefile +++ b/hardsup/Makefile @@ -11,11 +11,11 @@ OBJ= el734_utility.o asynsrv_utility.o stredit.o \ makeprint.o StrMatch.o #---------- for Redhat linux -#CC= gcc -#CFLAGS= -I/usr/local/include -I. -I../ -DLINUX -g -c +CC= gcc +CFLAGS= -I$SINQDIR/linux/include -I. -I../ -DLINUX -g -c #------------ for DigitalUnix -CC=cc -CFLAGS= -I. -I../ -std1 -g -c +#CC=cc +#CFLAGS= -I. -I../ -std1 -g -c #CFLAGS= -I/data/koenneck/include -I. -I../ -std1 -g -c #------------ for DigitalUnix with Fortify ## CC=cc @@ -36,3 +36,9 @@ hlib: $(OBJ) clean: rm -f *.o rm -f *.a + + + + + + diff --git a/modriv.h b/modriv.h index ed91ac92..cfd746c8 100644 --- a/modriv.h +++ b/modriv.h @@ -27,10 +27,14 @@ int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self, int iError,float fNew); - int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); - } - MotorDriver; + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); + } MotorDriver; /* the first fields above HAVE to be IDENTICAL to those below */ @@ -46,8 +50,13 @@ int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self,int iError, float fNew); - int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); /* EL-734 specific fields */ @@ -71,8 +80,13 @@ int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self,int iError, float fNew); - int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); /* Simulation specific fields */ float fFailure; /* percent random failures*/ @@ -90,8 +104,5 @@ /* ----------------------- Simulation -----------------------------------*/ MotorDriver *CreateSIM(SConnection *pCon, int argc, char *argv[]); void KillSIM(void *pData); - -/*------------------------ Default ContinueAfterWarn -----------------*/ - int MoDrivXXXContinue(void *pData); #endif diff --git a/motor.c b/motor.c index f951adeb..bebcff2e 100644 --- a/motor.c +++ b/motor.c @@ -10,6 +10,7 @@ revised: Mark Koennecke, June 1997 callback added: Mark Koennecke, August 1997 endscript facility added: Mark Koennecke, August 2002 + Modified to support driver parameters, Mark Koennecke, January 2003 Copyright: @@ -34,7 +35,6 @@ DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - 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 @@ -333,16 +333,7 @@ self->pDriver->GetError(self->pDriver,&iCode,pError,131); sprintf(pBueffel,"WARNING: %s on %s",pError,self->name); SCWrite(pCon,pBueffel,eStatus); - if(self->pDriver->ContinueAfterWarn(self->pDriver)) - { - iRetry = 0; - return HWBusy; - } - else - { - iRetry = 0; - return HWIdle; - } + return HWIdle; } iRetry = 0; return iRet; @@ -514,7 +505,17 @@ extern void KillPiPiezo(void *pData); } else { - return 0; + /* + check for a driver parameter + */ + if(self->pDriver->GetDriverPar != NULL) + { + return self->pDriver->GetDriverPar(self->pDriver,name,fVal); + } + else + { + return 0; + } } } } @@ -553,10 +554,6 @@ extern void KillPiPiezo(void *pData); } iRet = ObParSet(self->ParArray,self->name,name,fVal,pCon); - if(!iRet) - { - return iRet; - } if(strcmp(name,"sign") == 0) { if((absf(fVal)-1.0) > 0.01) @@ -573,6 +570,17 @@ extern void KillPiPiezo(void *pData); ObParInit(self->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser); } } + + /* + try set driver parameters + */ + if(iRet == 0) + { + if(self->pDriver->SetDriverPar != NULL) + { + iRet = self->pDriver->SetDriverPar(self->pDriver,pCon,name,fVal); + } + } return iRet; } /*--------------------------------------------------------------------------- @@ -988,6 +996,13 @@ extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray); sprintf(pBueffel,"%s.TargetPosition = %f\n", self->name,self->fTarget); SCWrite(pCon,pBueffel,eStatus); + /* + list driver parameters when appropriate + */ + if(self->pDriver->ListDriverPar != NULL) + { + self->pDriver->ListDriverPar(self->pDriver,self->name, pCon); + } } /*--------------------------------------------------------------------------*/ void MotorReset(pMotor pM) diff --git a/nigpib.c b/nigpib.c new file mode 100644 index 00000000..81e1df6b --- /dev/null +++ b/nigpib.c @@ -0,0 +1,106 @@ +/* + This is an implementation of a GPIB driver based on the drivers + provided by National Instruments. The driver has been tested + with the ENET-100 GPIB-TCP/IP bridge but should also work with + NI GPIB boards plugged into the composter. + + copright: see file COPYRIGHT + + Mark Koennecke, January 2002 +*/ + +#include +#include +#include +#include +#include "fortify.h" +#include "sics.h" +#include +#include "gpibcontroller.i" + +typedef struct __GPIB *pGPIB; +/*--------------------------------------------------------------------------*/ +static int NIattach(int boardNo, int address, int secondaryAddress, + int tmo, int eot, int eos){ + int devID; + + devID = ibdev(boardNo, address, secondaryAddress, tmo, eot, eos); + if(devID < 0){ + return -iberr; + } else { + return devID; + } +} +/*---------------------------------------------------------------------*/ +static int NIdetach(int devID){ + int status; + + status = ibonl(devID, 0); + if(status & ERR){ + return -iberr; + } else { + return 1; + } +} +/*-------------------------------------------------------------------*/ +static int NIwrite(int devID, void *buffer, int bytesToWrite){ + int status; + + status = ibwrt(devID,buffer,bytesToWrite); + if(status & ERR){ + return - iberr; + } else { + return 1; + } +} +/*-------------------------------------------------------------------*/ +static int NIread(int devID, void *buffer, int bytesToRead){ + int status; + + status = ibrd(devID,buffer,bytesToRead); + if(status & ERR){ + return - iberr; + } else { + return 1; + } +} +/*--------------------------------------------------------------------*/ +static void NIclear(int devID){ + ibclr(devID); +} +/*-----------------------------------------------------------------*/ +static void NIerror(int code, char *buffer, int maxBuffer){ + int flag = - code; + + switch(flag){ + case EDVR: + case ENEB: + case ECIC: + strncpy(buffer,"NI-GPIB not correctly installed or bad address", + maxBuffer); + return; + case EABO: + strncpy(buffer,"Timeout on data transfer",maxBuffer); + return; + case EBUS: + strncpy(buffer,"No device connected to GPIB or address errror", + maxBuffer); + return; + case ENOL: + strncpy(buffer,"No listeners on bus. Perhaps address error?", + maxBuffer); + return; + default: + strncpy(buffer,"Unrecognised error code, fix nigpib.c", + maxBuffer); + break; + } +} +/*------------------------------------------------------------------*/ +void NIassign(pGPIB self){ + self->attach = NIattach; + self->detach = NIdetach; + self->send = NIwrite; + self->read = NIread; + self->getErrorDescription = NIerror; +} diff --git a/obpar.c b/obpar.c index ad24d09d..ee1564fd 100644 --- a/obpar.c +++ b/obpar.c @@ -122,6 +122,23 @@ return NULL; } +/*---------------------------------------------------------------------------*/ + int ObParIndex(ObPar *self, char *name) + { + int i; + + assert(self); + + for(i = 0; self[i].iCode != -100; i++) + { + if(strcmp(name,self[i].name) == 0) + { + return i; + } + } + + return -1; + } /*---------------------------------------------------------------------------*/ int ObParInit(ObPar *self, int i, char *name, float fVal, int iCode) { diff --git a/obpar.h b/obpar.h index 30504876..f0a7be55 100644 --- a/obpar.h +++ b/obpar.h @@ -42,7 +42,11 @@ /* finds a ObPar struct for a name, return NULL if none */ - + int ObParIndex(ObPar *self, char *name); + /* + finds an index for name in self. Returns -1 on failure + */ + int ObParInit(ObPar *self,int i, char *name, float fVal, int iCode); /* sets a ObPar entry. self is a pointer to the array diff --git a/ofac.c b/ofac.c index e5d37508..25168d3e 100644 --- a/ofac.c +++ b/ofac.c @@ -108,6 +108,8 @@ #include "lomax.h" #include "polterwrite.h" #include "anticollider.h" +#include "gpibcontroller.h" +#include "ecb.h" /*----------------------- Server options creation -------------------------*/ static int IFServerOption(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) @@ -291,6 +293,8 @@ AddCommand(pInter,"MakeMaxDetector",LoMaxFactory,NULL,NULL); AddCommand(pInter,"PolterInstall",PolterInstall,NULL,NULL); AddCommand(pInter,"AntiCollisionInstall",AntiColliderFactory,NULL,NULL); + AddCommand(pInter,"MakeGPIB",MakeGPIB,NULL,NULL); + AddCommand(pInter,"MakeECB",MakeECB,NULL,NULL); } /*---------------------------------------------------------------------------*/ static void KillIniCommands(SicsInterp *pSics) @@ -351,6 +355,8 @@ RemoveCommand(pSics,"MakeMaxDetector"); RemoveCommand(pSics,"PolterInstall"); RemoveCommand(pSics,"AntiColliderInstall"); + RemoveCommand(pSics,"MakeGPIB"); + RemoveCommand(pSics,"MakeECB"); } diff --git a/pimotor.c b/pimotor.c index 76c951f0..ab9541b5 100644 --- a/pimotor.c +++ b/pimotor.c @@ -33,8 +33,13 @@ int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self,int iError, float fNew); - int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); /* C-804 specific fields */ @@ -281,11 +286,6 @@ } free(self); } -/*------------------------------------------------------------------------*/ - static int PIContinue(void *self) - { - return 0; - } /*-------------------------------------------------------------------------- * The data necessary for initialising the C804 motor is contained in a * Tcl-Array given as pArray parameter. In case of an error the error is @@ -433,7 +433,6 @@ pNew->GetStatus = PIStatus; pNew->GetError = PIError; pNew->TryAndFixIt = PIFixError; - pNew->ContinueAfterWarn = PIContinue; pNew->Halt = PIHalt; /* success */ diff --git a/pipiezo.c b/pipiezo.c index 1d8b6f52..b623bb3e 100644 --- a/pipiezo.c +++ b/pipiezo.c @@ -33,8 +33,13 @@ int (*GetStatus)(void *self); void (*GetError)(void *self, int *iCode, char *buffer, int iBufLen); int (*TryAndFixIt)(void *self,int iError, float fNew); - int (*ContinueAfterWarn)(void *self); int (*Halt)(void *self); + int (*GetDriverPar)(void *self, char *name, + float *value); + int (*SetDriverPar)(void *self,SConnection *pCon, + char *name, float newValue); + void (*ListDriverPar)(void *self, char *motorName, + SConnection *pCon); /* PiPiezo specific fields */ @@ -271,11 +276,6 @@ } free(self); } -/*------------------------------------------------------------------------*/ - static int PIContinue(void *self) - { - return 0; - } /*-------------------------------------------------------------------------- * The data necessary for initialising the PiPiezo motor is contained in a * Tcl-Array given as pArray parameter. In case of an error the error is @@ -383,7 +383,6 @@ pNew->GetStatus = PIStatus; pNew->GetError = PIError; pNew->TryAndFixIt = PIFixError; - pNew->ContinueAfterWarn = PIContinue; pNew->Halt = PIHalt; /* success */ diff --git a/sicsstat.tcl b/sicsstat.tcl index 29a305d4..bb1269e5 100644 --- a/sicsstat.tcl +++ b/sicsstat.tcl @@ -1,8 +1,20 @@ -# Motor gurke -gurke SoftZero 0.000000 -gurke SoftLowerLim -20.000000 -gurke SoftUpperLim 20.000000 -gurke Fixed -1.000000 -gurke sign 1.000000 -gurke InterruptMode 0.000000 -gurke AccessCode 2.000000 +# Motor a77 +a77 sign 1.000000 +a77 SoftZero 0.000000 +a77 SoftLowerLim -30.000000 +a77 SoftUpperLim 30.000000 +a77 Fixed -1.000000 +a77 InterruptMode 0.000000 +a77 AccessCode 2.000000 +samplename KohlSulfid +samplename setAccess 2 +comment UNKNOWN +comment setAccess 2 +environment UNKNOWN +environment setAccess 2 +subtitle UNKNOWN +subtitle setAccess 2 +user Albert von Villigen +user setAccess 2 +title UNKNOWN +title setAccess 2 diff --git a/simdriv.c b/simdriv.c index aebae817..23e28ae8 100644 --- a/simdriv.c +++ b/simdriv.c @@ -264,6 +264,7 @@ DeleteTokenList(pList); return NULL; } + memset(pDriv,0,sizeof(SIMDriv)); /* check and enter args, first lowerLimit */ pCurrent = pList; @@ -329,7 +330,6 @@ pDriv->GetError = SimError; pDriv->TryAndFixIt = SimFix; pDriv->Halt = SimHalt; - pDriv->ContinueAfterWarn = MoDrivXXXContinue; pDriv->fSpeed = .01; pDriv->iTime = 0; diff --git a/task.h b/task.h index f0605360..80183be8 100644 --- a/task.h +++ b/task.h @@ -117,5 +117,4 @@ /*-------------------------------------------------------------------------*/ #endif - - \ No newline at end of file + diff --git a/tecs/makefile b/tecs/makefile index 22db50cb..ddbcfb7b 100644 --- a/tecs/makefile +++ b/tecs/makefile @@ -3,6 +3,7 @@ # # Markus Zolliker, March 2000 # may now be used on different systems without change M.Z.01.2002 +# This only works with tcsh, not with bash under Linux M.K.01.2003 #-------------------------------------------------------------------------- #------------ for DigitalUnix (add -DFORTIFY to CC_... for fortified version) CC_alpha_osf1=cc -std1 -g -warnprotos -I../ -I. -I../hardsup