/*-------------------------------------------------------------------------- P I M O T O R This file contains the implementation of a motor driver for the Physik Instrumente Piezo Controller E-255. It is handled as a motor though it is a Piezo device. This gets a preset voltage in millivolts and that determines it's elongation and that is it. Mark Koennecke, February 1999 ----------------------------------------------------------------------------*/ #include #include #include "fortify.h" #include "sics.h" #include #include "hardsup/serialsinq.h" #include "hardsup/el734_def.h" #include "hardsup/el734fix.h" #include "motor.h" /*================== The Driver data structure ============================*/ typedef struct __PIPiezo { /* 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); void (*KillPrivate) (void *self); /* PiPiezo specific fields */ int iPort; char *hostname; int iChannel; int iMotor; void *pSerial; int iLastError; int iLastVolt; } PiPiezo, *pPiPiezo; #define PITMO -845 #define PICOMERR -846 /*--------------------------------------------------------------------------*/ static int PIPosition(void *pData, float *fPos) { pPiPiezo self = NULL; int iRet; char pCommand[20]; char pReply[80]; char *pPtr; self = (pPiPiezo) pData; assert(self); /* format command */ sprintf(pCommand, "%1.1dTO\r", self->iMotor); /* send command */ iRet = SerialWriteRead(&self->pSerial, pCommand, pReply, 79); if (iRet != 1) { self->iLastError = iRet; *fPos = -99999; return HWFault; } /* catch TMO or bad reply */ if (strstr(pReply, "TMO") != NULL) { self->iLastError = PITMO; *fPos = -9999; return HWFault; } if (strstr(pReply, "?") != NULL) { self->iLastError = PICOMERR; *fPos = -9999; return HWFault; } /* read value */ pPtr = pReply + 3; *fPos = atof(pPtr); return OKOK; } /*-------------------------------------------------------------------------*/ static int PIRun(void *pData, float fVal) { pPiPiezo self = NULL; int iRet; char pCommand[20]; char pReply[80]; int iTmo; self = (pPiPiezo) pData; assert(self); /* format command */ sprintf(pCommand, "%1.1dSO%5.5d\r", self->iMotor, (int) fVal); /* send command */ iRet = SerialWriteRead(&self->pSerial, pCommand, pReply, 79); if (iRet != 1) { self->iLastError = iRet; return HWFault; } self->iLastVolt = (int) fVal; return OKOK; } /*---------------------------------------------------------------------------*/ static void PIError(void *pData, int *iCode, char *pError, int iErrLen) { pPiPiezo self = NULL; self = (pPiPiezo) pData; assert(self); *iCode = self->iLastError; if (*iCode == PITMO) { strlcpy(pError, "Timeout at serial line", iErrLen); return; } if (*iCode == PICOMERR) { strlcpy(pError, "E-255 Command Error", iErrLen); return; } /* wait a little to give this thing a reaction time, otherwise trouble reading responses */ SicsWait(2); SerialError(self->iLastError, pError, iErrLen); return; } /*--------------------------------------------------------------------------*/ static int PIFixError(void *pData, int iError, float fNew) { pPiPiezo self = NULL; int iRet; self = (pPiPiezo) pData; assert(self); switch (iError) { /* network errors */ case NOCONNECTION: 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: SerialClose(&self->pSerial); iRet = SerialOpen(&self->pSerial, self->hostname, self->iPort, self->iChannel); if (iRet != 1) { return MOTREDO; } else { return MOTFAIL; } break; /* handable protocoll errors */ case EL734__BAD_TMO: case PITMO: case TIMEOUT: return MOTREDO; break; case PICOMERR: return MOTFAIL; break; default: return MOTFAIL; break; } return MOTFAIL; } /*---------------------------------------------------------------------------*/ static int PIHalt(void *pData) { /* just drive to 0 volt */ PIRun(pData, 0.0); return 1; } #define ABS(x) (x < 0 ? -(x) : (x)) /*-------------------------------------------------------------------------*/ static int PIStatus(void *pData) { pPiPiezo self = NULL; char pCommand[20], pReply[80], *pPtr; int iRet; float fSpeed; int iSpeed, iDiff; self = (pPiPiezo) pData; assert(self); /* read actual velocity: should be 0 when done */ sprintf(pCommand, "%1.1dTO", self->iMotor); iRet = SerialWriteRead(&self->pSerial, pCommand, pReply, 79); if (iRet != 1) { self->iLastError = iRet; return HWFault; } /* check reply */ if (strstr(pReply, "TMO") != NULL) { self->iLastError = PITMO; return HWFault; } if (strstr(pReply, "?") != NULL) { self->iLastError = PICOMERR; return HWFault; } pPtr = pReply + 3; iSpeed = atoi(pPtr); iDiff = iSpeed - self->iLastVolt; if (ABS(iDiff) > 5) { return HWBusy; } return HWIdle; } /*------------------------------------------------------------------------*/ void KillPiPiezo(void *pData) { pPiPiezo self = (pPiPiezo) pData; if (!self) return; if (self->hostname) { free(self->hostname); } if (self->pSerial) { SerialClose(&self->pSerial); } } /*-------------------------------------------------------------------------- * 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 * returned in the Tcl-interpreter. */ MotorDriver *MakePiPiezo(Tcl_Interp * pTcl, char *pArray) { pPiPiezo pNew = NULL; int iRet, iVal, iTmo; double dVal; char *pPar = NULL; char pCommand[20], pReply[40]; /* allocate space: the final frontier */ pNew = (pPiPiezo) malloc(sizeof(PiPiezo)); if (!pNew) { Tcl_SetResult(pTcl, "Out of memory for PiPiezo Driver", NULL); return NULL; } memset(pNew, 0, sizeof(PiPiezo)); /* connection parameters */ pPar = (char *) Tcl_GetVar2(pTcl, pArray, "Computer", TCL_GLOBAL_ONLY); if (!pPar) { Tcl_SetResult(pTcl, "Failed to find serial port server host name", NULL); KillPiPiezo(pNew); return NULL; } pNew->hostname = strdup(pPar); pPar = NULL; pPar = (char *) Tcl_GetVar2(pTcl, pArray, "port", TCL_GLOBAL_ONLY); if (!pPar) { Tcl_SetResult(pTcl, "Failed to find serial port server port adress", NULL); KillPiPiezo(pNew); return NULL; } iRet = Tcl_GetInt(pTcl, pPar, &iVal); if (iRet != TCL_OK) { Tcl_SetResult(pTcl, " Failed to convert port adress to integer", NULL); KillPiPiezo(pNew); return NULL; } pNew->iPort = iVal; pPar = NULL; pPar = (char *) Tcl_GetVar2(pTcl, pArray, "channel", TCL_GLOBAL_ONLY); if (!pPar) { Tcl_SetResult(pTcl, "Failed to find serial port server channel adress", NULL); KillPiPiezo(pNew); return NULL; } iRet = Tcl_GetInt(pTcl, pPar, &iVal); if (iRet != TCL_OK) { Tcl_SetResult(pTcl, " Failed to convert channel number to integer", NULL); KillPiPiezo(pNew); return NULL; } pNew->iChannel = iVal; pPar = NULL; pPar = (char *) Tcl_GetVar2(pTcl, pArray, "motor", TCL_GLOBAL_ONLY); if (!pPar) { Tcl_SetResult(pTcl, "Failed to find motor number", NULL); KillPiPiezo(pNew); return NULL; } iRet = Tcl_GetInt(pTcl, pPar, &iVal); if (iRet != TCL_OK) { Tcl_SetResult(pTcl, " Failed to convert motor number to integer", NULL); KillPiPiezo(pNew); return NULL; } pNew->iMotor = iVal; pNew->fUpper = 12000.; pNew->fLower = -2000.; /* open the serialport connection */ iRet = SerialOpen(&pNew->pSerial, pNew->hostname, pNew->iPort, pNew->iChannel); if (iRet != 1) { Tcl_SetResult(pTcl, "Failed to open connection to serial port server", NULL); KillPiPiezo(pNew); return NULL; } /* configure the connection */ SerialATerm(&pNew->pSerial, "1\x03"); SerialSendTerm(&pNew->pSerial, "\r"); /* configure the function pointers */ pNew->GetPosition = PIPosition; pNew->RunTo = PIRun; pNew->GetStatus = PIStatus; pNew->GetError = PIError; pNew->TryAndFixIt = PIFixError; pNew->Halt = PIHalt; pNew->KillPrivate = KillPiPiezo; /* success */ return (MotorDriver *) pNew; }