Files
sics/motor.c
cvs f3853c20f0 - Fixed bug with ECB not stopping when no beam
- Fixed synchronisation issues
- Fixed hsitogram memory writing from nxscript
- Started module for writing SICS interfaces in Tcl
- Fixed a bug in scan, which allowed to corrupt files
- Fixed memory problems in napi5
2003-05-23 15:06:47 +00:00

1325 lines
38 KiB
C

/*------------------------------------------------------------------------
M O T O R S
This file implements the SICS motor handling. This is the logical
level, the nitty gritty hardware interface is in the driver.
Mark Koennecke, November 1996
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
TODO: currently motor drivers have to be installed in MakeMotor
and remembered in KillMotor. Sort this some day!
Copyright:
Labor fuer Neutronenstreuung
Paul Scherrer Institut
CH-5423 Villigen-PSI
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
-----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <tcl.h>
#include "fortify.h"
#include "sics.h"
#include "devexec.h"
#include "motor.h"
#include "splitter.h"
#include "status.h"
#include "servlog.h"
#include "ecbdriv.h"
/*-------------------------------------------------------------------------
some lokal defines
*/
#define ZEROINACTIVE 0
#define INTCONT 0.
#define INTSCAN 1.
#define INTBATCH 2.
#define INTHALT 3.
#define HLOW 0
#define HUPP 1
#define SLOW 2
#define SUPP 3
#define SZERO 4
#define FIX 5
#define INT 6
#define PREC 7
#define USRIGHTS 8
#define SPEED 9
#define SIGN 10
#define ECOUNT 11
/*------------------------------------------------------------------------
a tiny structure used in CallBack work
*/
typedef struct {
float fVal;
char *pName;
} MotCallback;
/*-------------------------------------------------------------------------*/
static void *MotorGetInterface(void *pData, int iID)
{
pMotor self = NULL;
self = (pMotor)pData;
assert(self);
if(iID == DRIVEID)
{
return self->pDrivInt;
}
else if(iID == CALLBACKINTERFACE)
{
return self->pCall;
}
return NULL;
}
/*------------------------------------------------------------------------*/
static int MotorHalt(void *sulf)
{
pMotor self;
assert(sulf);
self = (pMotor)sulf;
/* reduce the error count by 1. This is because the driver is
expected to return an error when the motor had been stopped.
However, a stop is usually a consequence of a user intervention
or program logic. This prevents to a false motor alarm when the
motor was repeatedly stopped for other reasons.
*/
self->pDrivInt->iErrorCount--;
if(self->pDrivInt->iErrorCount < 0)
self->pDrivInt->iErrorCount = 0;
return self->pDriver->Halt((void *)self->pDriver);
}
/*--------------------------------------------------------------------------*/
static int MotorLimits(void *sulf, float fVal, char *error, int iErrLen)
{
float fHard;
pMotor self;
assert(sulf);
self = (pMotor)sulf;
return MotorCheckBoundary(self,fVal,&fHard,error,iErrLen);
}
/*---------------------------------------------------------------------------*/
static float MotorGetValue(void *pData, SConnection *pCon)
{
int iRet;
float fVal = 0.;
assert(pData);
iRet = MotorGetHardPosition((pMotor)pData,pCon,&fVal);
if(iRet != OKOK)
{
fVal = -9999999.99;
}
return fVal;
}
/*------------------------------------------------------------------------*/
static int MotorSaveStatus(void *pData, char *name, FILE *fd)
{
pMotor self = NULL;
char pBueffel[512];
assert(pData);
assert(fd);
self= (pMotor)pData;
fprintf(fd,"# Motor %s\n",name);
sprintf(pBueffel,"%s sign %f\n",name,ObVal(self->ParArray,SIGN));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s SoftZero %f\n",name,ObVal(self->ParArray,SZERO));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s SoftLowerLim %f\n",name,ObVal(self->ParArray,SLOW));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s SoftUpperLim %f\n",name,ObVal(self->ParArray,SUPP));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s Fixed %f\n",name,ObVal(self->ParArray,FIX));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s InterruptMode %f\n",name,ObVal(self->ParArray,INT));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s precision %f\n",name,ObVal(self->ParArray,PREC));
fputs(pBueffel,fd);
sprintf(pBueffel,"%s AccessCode %f\n",name,ObVal(self->ParArray,USRIGHTS));
fputs(pBueffel,fd);
return 1;
}
/*-------------------------------------------------------------------------*/
static float absf(float f)
{
if(f < 0.)
{
return -f;
}
else
{
return f;
}
}
/*-------------------------------------------------------------------------*/
static void MotorInterrupt(SConnection *pCon, int iVal)
{
if(SCGetInterrupt(pCon) < iVal)
{
SCSetInterrupt(pCon,iVal);
}
}
/*--------------------------------------------------------------------------
Refactor
--------------------------------------------------------------------------*/
static int MotorStatus(void *sulf, SConnection *pCon)
{
float fHard;
pMotor self;
int iRet,i, iCode;
static int iRetry = 0;
char pError[132];
char pBueffel[256];
static int iPosFault = 0;
MotCallback sCall;
assert(sulf);
self = (pMotor)sulf;
iRet = self->pDriver->GetStatus(self->pDriver);
fHard = MotorGetValue((void *)self,pCon);
if(fHard < -9999990)
{
self->pDriver->GetError(self->pDriver,&iCode, pError,131);
iRet = self->pDriver->TryAndFixIt(self->pDriver,iCode, self->fTarget);
if(iRet == MOTFAIL)
{
sprintf(pBueffel,"WARNING: %s on %s",pError,self->name);
SCWrite(pCon,pBueffel,eError);
MotorInterrupt(pCon,ObVal(self->ParArray,INT));
iRetry = 0;
return HWFault;
}
else if(iRet == MOTREDO)
{
iRetry++;
if(iRetry >= 3)
{
iRetry = 0;
return HWFault;
}
}
else
{
iRetry = 0;
return HWBusy;
}
}
/* invoke callback */
sCall.fVal = fHard;
sCall.pName = self->name;
InvokeCallBack(self->pCall, MOTDRIVE, &sCall);
/* motor thinks he is done */
if( (iRet == OKOK) || (iRet == HWIdle))
{
MotorGetSoftPosition(self,pCon,&sCall.fVal);
InvokeCallBack(self->pCall, MOTEND, &sCall);
self->fPosition = fHard;
if(absf(fHard - self->fTarget) > ObVal(self->ParArray,PREC))
{
sprintf(pBueffel,"WARNING: %s off position by %f",
self->name, absf(fHard - self->fTarget));
SCWrite(pCon,pBueffel, eWarning);
MotorInterrupt(pCon,ObVal(self->ParArray,INT));
iRetry = 0;
return HWPosFault;
}
iRetry = 0;
return HWIdle;
}
/* motor suggests a fault */
else if(iRet == HWFault)
{
self->pDriver->GetError(self->pDriver,&iCode, pError,131);
iRet = self->pDriver->TryAndFixIt(self->pDriver,iCode, self->fTarget);
if(iRet == MOTFAIL)
{
sprintf(pBueffel,"ERROR: %s on %s",pError,self->name);
SCWrite(pCon,pBueffel,eError);
MotorInterrupt(pCon,ObVal(self->ParArray,INT));
iRetry = 0;
return HWFault;
}
else if(iRet == MOTREDO)
{
self->pDriver->RunTo(self->pDriver,self->fTarget);
iRetry++;
if(iRetry >= 3)
{
iRetry = 0;
return HWFault;
}
return HWBusy;
}
else
{
iRetry = 0;
return HWBusy;
}
}
/* a positioning fault */
else if(iRet == HWPosFault)
{
self->pDriver->GetError(self->pDriver,&iCode, pError,131);
iRet = self->pDriver->TryAndFixIt(self->pDriver,iCode, self->fTarget);
if(iRet == MOTFAIL)
{
sprintf(pBueffel,"ERROR: %s on %s",pError,self->name);
SCWrite(pCon,pBueffel,eError);
MotorInterrupt(pCon,ObVal(self->ParArray,INT));
iRetry = 0;
return HWFault;
}
else if(iRet == MOTREDO)
{
iPosFault++;
if(iPosFault == 2)
{
iPosFault = 0;
iRetry = 0;
return HWPosFault;
}
self->pDriver->RunTo(self->pDriver,self->fTarget);
return HWBusy;
}
else
{
return HWBusy;
}
}
else if(iRet == HWWarn)
{
self->pDriver->GetError(self->pDriver,&iCode,pError,131);
sprintf(pBueffel,"WARNING: %s on %s",pError,self->name);
SCWrite(pCon,pBueffel,eStatus);
return HWIdle;
}
iRetry = 0;
return iRet;
}
/*---------------------------------------------------------------------------*/ pMotor MotorInit(char *drivername, char *name, MotorDriver *pDriv)
{
pMotor pM = NULL;
assert(drivername);
assert(pDriv);
assert(name);
/* get memory */
pM = (pMotor)malloc(sizeof(Motor));
if(!pM)
{
return NULL;
}
/* create and initialize parameters */
pM->ParArray = ObParCreate(12);
if(!pM->ParArray)
{
free(pM);
return NULL;
}
ObParInit(pM->ParArray,HLOW,"hardlowerlim",pDriv->fLower,usInternal);
ObParInit(pM->ParArray,HUPP,"hardupperlim",pDriv->fUpper,usInternal);
ObParInit(pM->ParArray,SLOW,"softlowerlim",pDriv->fLower,usUser);
ObParInit(pM->ParArray,SUPP,"softupperlim",pDriv->fUpper,usUser);
ObParInit(pM->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser);
ObParInit(pM->ParArray,FIX,"fixed",-1,usUser);
ObParInit(pM->ParArray,INT,"interruptmode",INTCONT,usMugger);
ObParInit(pM->ParArray,PREC,"precision",0.01,usMugger);
ObParInit(pM->ParArray,USRIGHTS,"accesscode",(float)usUser,usMugger);
ObParInit(pM->ParArray,SPEED,"speed",0.02,usInternal);
ObParInit(pM->ParArray,SIGN,"sign",1.0,usMugger);
ObParInit(pM->ParArray,ECOUNT,"failafter",3.0,usMugger);
pDriv->GetPosition(pDriv,&(pM->fPosition));
pM->fTarget = pM->fPosition;
pM->endScriptID = 0;
/* copy arguments */
pM->pDriver = pDriv;
pM->drivername = strdup(drivername);
pM->name = strdup(name);
/* initialise object descriptor */
pM->pDescriptor = CreateDescriptor("Motor");
if(!pM->pDescriptor)
{
ObParDelete(pM->ParArray);
free(pM);
return NULL;
}
pM->pDescriptor->GetInterface = MotorGetInterface;
pM->pDescriptor->SaveStatus = MotorSaveStatus;
/* initialise Drivable interface */
pM->pDrivInt = CreateDrivableInterface();
if(!pM->pDrivInt)
{
DeleteDescriptor(pM->pDescriptor);
ObParDelete(pM->ParArray);
free(pM);
return NULL;
}
pM->pDrivInt->SetValue = MotorRun;
pM->pDrivInt->CheckLimits = MotorLimits;
pM->pDrivInt->CheckStatus = MotorStatus;
pM->pDrivInt->GetValue = MotorGetValue;
pM->pDrivInt->Halt = MotorHalt;
/* initialise callback interface */
pM->pCall = CreateCallBackInterface();
if(!pM->pCall)
{
MotorKill(pM);
return NULL;
}
/* done */
return pM;
}
/*--------------------------------------------------------------------------*/
extern void KillPiPiezo(void *pData);
void MotorKill(void *self)
{
pMotor pM;
assert(self);
pM = (pMotor)self;
if(pM->name)
free(pM->name);
if(pM->pDrivInt)
{
free(pM->pDrivInt);
}
if(pM->pCall)
{
DeleteCallBackInterface(pM->pCall);
}
/* kill driver */
if(pM->drivername)
{ /* edit here to include more drivers */
if(strcmp(pM->drivername,"EL734") == 0)
{
KillEL734((void *)pM->pDriver);
}
else if(strcmp(pM->drivername,"EL734DC") == 0)
{
KillEL734((void *)pM->pDriver);
}
else if(strcmp(pM->drivername,"SIM") == 0)
{
KillSIM((void *)pM->pDriver);
}
else if(strcmp(pM->drivername,"PIPIEZO") == 0)
{
KillPiPiezo((void *)pM->pDriver);
}
else if(strcmp(pM->drivername,"ECB") == 0)
{
KillECBMotor( (void *)pM->pDriver);
}
free(pM->drivername);
}
/* get rid of parameter space */
if(pM->ParArray)
{
ObParDelete(pM->ParArray);
}
/* kill Descriptor */
DeleteDescriptor(pM->pDescriptor);
free(pM);
}
/*--------------------------------------------------------------------------*/
int MotorGetPar(pMotor self, char *name, float *fVal)
{
ObPar *pPar = NULL;
assert(self);
pPar = ObParFind(self->ParArray,name);
if(pPar)
{
*fVal = pPar->fVal;
return 1;
}
else
{
/* can still be position */
if(strcmp(name,"position") == 0)
{
*fVal = self->fPosition;
return 1;
}
else if(strcmp(name,"target") == 0)
{
*fVal = self->fTarget;
return 1;
}
else
{
/*
check for a driver parameter
*/
if(self->pDriver->GetDriverPar != NULL)
{
return self->pDriver->GetDriverPar(self->pDriver,name,fVal);
}
else
{
return 0;
}
}
}
}
/*---------------------------------------------------------------------------*/
int MotorSetPar(pMotor self, SConnection *pCon, char *name, float fVal)
{
ObPar *pPar = NULL;
char pBueffel[512];
int iRet;
float fLimit, fOld, fChange;
assert(self);
assert(pCon);
/*
try set driver parameters
*/
if(self->pDriver->SetDriverPar != NULL)
{
iRet = self->pDriver->SetDriverPar(self->pDriver,pCon,name,fVal);
if(iRet == 1)
{
SCparChange(pCon);
return iRet;
}
}
if(strcmp(name,"softzero") == 0)
{
/* set it first, this also tests the necessary privileges */
fOld = ObVal(self->ParArray,SZERO);
iRet = ObParSet(self->ParArray,self->name,name,fVal,pCon);
if(!iRet)
{
return iRet;
}
/* shift the limits by the difference between old and new */
fChange = fVal - fOld;
/* upper limit */
fLimit = ObVal(self->ParArray,SUPP);
fLimit -= fChange;
ObParSet(self->ParArray,self->name,"softupperlim",fLimit,pCon);
/* lower limit */
fLimit = ObVal(self->ParArray,SLOW);
fLimit -= fChange;
ObParSet(self->ParArray,self->name,"softlowerlim",fLimit,pCon);
SCparChange(pCon);
return 1;
}
iRet = ObParSet(self->ParArray,self->name,name,fVal,pCon);
if(strcmp(name,"sign") == 0)
{
if((absf(fVal)-1.0) > 0.01)
{
SCWrite(pCon,"ERROR: Invalid Sign Value",eError);
return 0;
}
if(fVal < 0.0)
{
ObParInit(self->ParArray,SLOW,"softlowerlim",
self->pDriver->fUpper*fVal,usUser);
ObParInit(self->ParArray,SUPP,"softupperlim",
self->pDriver->fLower*fVal,usUser);
ObParInit(self->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser);
}
}
SCparChange(pCon);
return iRet;
}
/*---------------------------------------------------------------------------
MotorCheckBoundary checks for violation of boundary conditions and
transforms from SoftCoordinates to hard coordinates.
*/
int MotorCheckBoundary(pMotor self, float fVal, float *fNew,
char *pError, int iErrLen)
{
float fHard;
float fZero;
char pBueffel[512];
assert(self);
/* check for fixed */
if(ObVal(self->ParArray,FIX) >= 0)
{
sprintf(pBueffel,"Motor %s is Fixed",self->name);
strncpy(pError,pBueffel,iErrLen);
return 0; /* is this an error? */
}
/* check against software boundaries */
if(fVal > ObVal(self->ParArray,SUPP))
{
sprintf(pBueffel,"%f violates upper software limit %f on %s",
fVal, ObVal(self->ParArray,SUPP),self->name);
strncpy(pError,pBueffel,iErrLen);
return 0;
}
if(fVal < ObVal(self->ParArray,SLOW))
{
sprintf(pBueffel,"%f violates lower software limit %f on %s",
fVal,ObVal(self->ParArray,SLOW),self->name );
strncpy(pError,pBueffel,iErrLen);
return 0;
}
/* correct for zero point */
fZero = ObVal(self->ParArray,SZERO);
fZero = -fZero;
fHard = fVal - fZero;
/* apply sign */
fHard = fHard*ObVal(self->ParArray,SIGN);
/* check for hardware limits */
if(fHard > ObVal(self->ParArray,HUPP))
{
sprintf(pBueffel,"%f violates upper hardware limit %f on %s",
fVal,ObVal(self->ParArray,HUPP),self->name);
strncpy(pError,pBueffel,iErrLen);
return 0;
}
if(fHard < ObVal(self->ParArray,HLOW))
{
sprintf(pBueffel,"%f violates lower hardware limit %f on %s",
fVal,ObVal(self->ParArray,HLOW),self->name);
strncpy(pError,pBueffel,iErrLen);
return 0;
}
*fNew = fHard;
return 1;
}
/*---------------------------------------------------------------------------*/
long MotorRun(void *sulf, SConnection *pCon, float fNew)
{
float fHard;
int i, iRet, iCode;
char pBueffel[512];
char pError[132];
pMotor self;
long lTime;
float fDelta;
self = (pMotor)(sulf);
assert(self);
assert(pCon);
/* check if I'am allowed to move this motor */
if(!SCMatchRights(pCon,(int)ObVal(self->ParArray,USRIGHTS)))
{
sprintf(pBueffel,"ERROR: You are not authorised to move motor %s",
self->name);
SCWrite(pCon,pBueffel,eError);
SCSetInterrupt(pCon,eAbortBatch);
return 0;
}
/* check boundaries first */
iRet = MotorCheckBoundary(self,fNew,&fHard,pBueffel,511);
if(!iRet)
{
SCWrite(pCon,pBueffel,eStatus);
SCSetInterrupt(pCon,eAbortOperation);
return 0;
}
/* check our error count and interrupt if to much */
iCode = (int)ObVal(self->ParArray,ECOUNT);
if(self->pDrivInt->iErrorCount > iCode)
{
/* big alarm */
ServerWriteGlobal("ERROR: !!! MOTOR ALARM !!! MOTOR ALARM !!!",eError);
sprintf(pBueffel,
"ERROR: too many position errors counted at motor %s",
self->name);
ServerWriteGlobal(pBueffel,eError);
SCSetInterrupt(pCon,eAbortBatch);
self->pDrivInt->iErrorCount = 0;
return 0;
}
/* Boundaries OK, send command */
self->fTarget = fHard;
iRet = self->pDriver->RunTo(self->pDriver,fHard);
if(iRet != OKOK)
{ /* try three times to fix it */
for(i = 0; (i < 3) && (iRet != OKOK); i++)
{
self->pDriver->GetError(self->pDriver,&iCode, pError,131);
sprintf(pBueffel,"WARNING: Trying to fix: %s",pError);
SCWrite(pCon,pBueffel,eWarning);
iRet = self->pDriver->TryAndFixIt(self->pDriver,iCode, fHard);
switch(iRet)
{
case MOTFAIL:
SCWrite(pCon,pError,eError);
SCWrite(pCon,"\n",eError);
SCSetInterrupt(pCon,(int)ObVal(self->ParArray,INT));
return HWFault;
case MOTREDO:
iRet = self->pDriver->RunTo(self->pDriver,fHard);
if(iRet == OKOK)
{
return OKOK;
}
break;
case MOTOK:
return OKOK;
break;
}
}
/* tried three times, refuses to work */
SCWrite(pCon,pError,eError);
SCWrite(pCon,"\n",eError);
SCSetInterrupt(pCon,(int)ObVal(self->ParArray,INT));
return HWFault;
}
return OKOK;
}
/*------------------------------------------------------------------------*/
int MotorGetHardPosition(pMotor self,SConnection *pCon, float *fHard)
{
int iRet, iCode;
float fVal;
char pBueffel[512],pError[256];
assert(self);
assert(pCon);
iRet = self->pDriver->GetPosition(self->pDriver,&fVal);
if(iRet == OKOK) /* all went well, the exception */
{
*fHard = fVal;
return 1;
}
else /* a problem, the usual case: try fix the problem */
{ /* no point in trying this three times */
self->pDriver->GetError(self->pDriver,&iCode, pError,255);
iRet = self->pDriver->TryAndFixIt(self->pDriver,iCode, fVal);
sprintf(pBueffel,"WARNING: Trying to fix %s",pError);
SCWrite(pCon,pBueffel,eWarning);
switch(iRet)
{
case MOTFAIL:
sprintf(pBueffel,"ERROR: cannot fix motor %s",
self->name);
SCWrite(pCon,pBueffel,eError);
SCSetInterrupt(pCon,(int)ObVal(self->ParArray,INT));
*fHard = fVal;
return 0;
case MOTOK:
case MOTREDO:
iRet = self->pDriver->GetPosition(self->pDriver,&fVal);
if(iRet)
{
*fHard = fVal*ObVal(self->ParArray,SIGN);
return 1;
}
else
{
sprintf(pBueffel,"ERROR: cannot fix motor %s",
self->name);
SCSetInterrupt(pCon,(int)ObVal(self->ParArray,INT));
SCWrite(pCon,pBueffel,eError);
*fHard = fVal;
return 0;
}
}
}
*fHard = fVal*ObVal(self->ParArray,SIGN);
return 0;
}
/* ------------------------------------------------------------------------*/
int MotorGetSoftPosition(pMotor self, SConnection *pCon, float *fVal)
{
int iRet;
float fValue;
assert(self);
assert(pCon);
/* get the hard position */
iRet = MotorGetHardPosition(self,pCon,&fValue);
if(!iRet)
{
*fVal = fValue;
return 0;
}
/* apply zeropoint */
if(ObVal(self->ParArray,SIGN) < 0.)
{
fValue += ObVal(self->ParArray,SZERO);
}
else
{
fValue -= ObVal(self->ParArray,SZERO);
}
*fVal = fValue;
/* apply sign */
*fVal = fValue*ObVal(self->ParArray,SIGN);
return 1;
}
/*---------------------------------------------------------------------------*/
int MotorCheckPosition(void *sulf, SConnection *pCon)
{
float fHard;
int i, iRet, iCode;
char pBueffel[512];
pMotor self;
self = (pMotor)sulf;
assert(self);
assert(pCon);
/* try to find current position */
iRet = MotorGetHardPosition(self,pCon,&fHard);
if(iRet)
{
if(absf(fHard - self->fTarget) < ObVal(self->ParArray,PREC))
{
self->fPosition = fHard;
return 1;
}
else
{
/* Oooopppsss error */
return 0;
}
}
else /* error getting hold of position, MotorGetHard already tried to
solve the problem and FAILED, the fucking bastard
even messaged the connection accordingly */
{
return -1;
}
}
/* --------------------------------------------------------------------------
The Factory function for creating a motor. Usage:
MotorCreate name DriverName.
Drivernames currently understood are:
EL734 SINQ EL734 stepper motor
EL734DC SINQ EL734 DC motor
PiPiezo Physik-Instrumente E-255 Piezo Controller
SIM simulated motor
*/
extern MotorDriver *MakePiPiezo(Tcl_Interp *pTcl, char *pArray);
int MotorCreate(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
pMotor pNew = NULL;
MotorDriver *pDriver = NULL;
char pBueffel[512];
int iD, iRet;
Tcl_Interp *pTcl = (Tcl_Interp *)pSics->pTcl;
assert(pCon);
assert(pSics);
/* a first check */
if(argc < 3)
{
SCWrite(pCon,"Insufficient arguments for motor creation",eError);
return 0;
}
/* create the driver */
strtolower(argv[2]);
strtolower(argv[1]);
if(strcmp(argv[2],"el734") == 0)
{
iD = argc - 3;
pDriver = CreateEL734(pCon,iD,&argv[3]);
if(!pDriver)
{
return 0;
}
/* create the motor */
pNew = MotorInit("EL734",argv[1],pDriver);
if(!pNew)
{
sprintf(pBueffel,"Failure to create motor %s",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
else if(strcmp(argv[2],"ecb") == 0)
{
iD = argc - 3;
pDriver = CreateECBMotor(pCon,iD,&argv[3]);
if(!pDriver)
{
return 0;
}
/* create the motor */
pNew = MotorInit("ECB",argv[1],pDriver);
if(!pNew)
{
sprintf(pBueffel,"Failure to create motor %s",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
else if(strcmp(argv[2],"el734dc") == 0)
{
iD = argc - 3;
pDriver = CreateEL734DC(pCon,iD,&argv[3]);
if(!pDriver)
{
return 0;
}
/* create the motor */
pNew = MotorInit("EL734DC",argv[1],pDriver);
if(!pNew)
{
sprintf(pBueffel,"Failure to create motor %s",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
else if (strcmp(argv[2],"sim") == 0)
{
iD = argc - 3;
pDriver = CreateSIM(pCon,iD,&argv[3]);
if(!pDriver)
{
return 0;
}
/* create the motor */
pNew = MotorInit("SIM",argv[1],pDriver);
if(!pNew)
{
sprintf(pBueffel,"Failure to create motor %s",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
pNew->ParArray[HLOW].iCode = usUser;
pNew->ParArray[HUPP].iCode = usUser;
}
else if (strcmp(argv[2],"pipiezo") == 0)
{
pDriver = MakePiPiezo(pSics->pTcl,argv[3]);
if(!pDriver)
{
SCWrite(pCon,pTcl->result,eError);
return 0;
}
/* create the motor */
pNew = MotorInit("PIPIEZO",argv[1],pDriver);
if(!pNew)
{
sprintf(pBueffel,"Failure to create motor %s",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
}
else
{
sprintf(pBueffel,"Motor Type %s not recognized for motor %s",
argv[2],argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
/* create the interpreter command */
iRet = AddCommand(pSics,argv[1],MotorAction,MotorKill,pNew);
if(!iRet)
{
sprintf(pBueffel,"ERROR: duplicate command %s not created",argv[1]);
SCWrite(pCon,pBueffel,eError);
return 0;
}
return 1;
}
/* ----------------- some private functions used in MotorAction -------------*/
void MotorListLL(pMotor self, SConnection *pCon)
{
char pBueffel[512];
int i, iLen;
iLen = ObParLength(self->ParArray);
sprintf(pBueffel,"Parameter Listing for motor %s\n",self->name);
SCWrite(pCon,pBueffel,eStatus);
for(i = 0; i < iLen; i++)
{
sprintf(pBueffel,"%s.%s = %f\n",self->name,
self->ParArray[i].name,self->ParArray[i].fVal);
SCWrite(pCon,pBueffel,eStatus);
}
sprintf(pBueffel,"%s.Position = %f\n", self->name,self->fPosition);
SCWrite(pCon,pBueffel,eStatus);
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)
{
ObParInit(pM->ParArray,SLOW,"softlowerlim",pM->pDriver->fLower,usUser);
ObParInit(pM->ParArray,SUPP,"softupperlim",pM->pDriver->fUpper,usUser);
ObParInit(pM->ParArray,SZERO,"softzero",ZEROINACTIVE,usUser);
ObParInit(pM->ParArray,FIX,"fixed",-1,usUser);
}
/*------------------------------------------------------------------------*/
typedef struct {
char *pName;
SConnection *pCon;
} MotInfo, *pMotInfo;
/*-----------------------------------------------------------------------*/
static void KillInfo(void *pData)
{
pMotInfo self = NULL;
assert(pData);
self = (pMotInfo)pData;
if(self->pName)
{
free(self->pName);
}
free(self);
}
/*------------------- The CallBack function for interest ------------------*/
static int InterestCallback(int iEvent, void *pEvent, void *pUser)
{
pMotInfo pInfo = NULL;
char pBueffel[80];
MotCallback *psCall;
assert(pEvent);
assert(pUser);
psCall = (MotCallback *)pEvent;
pInfo = (MotInfo *)pUser;
sprintf(pBueffel,"%s.position = %f ", pInfo->pName, psCall->fVal);
SCWrite(pInfo->pCon,pBueffel,eValue);
return 1;
}
/*------------------------------------------------------------------------*/
static void KillScript(void *pData)
{
if(pData != NULL)
{
free(pData);
}
}
/*------------------------ The endscript callback function ----------------*/
static int EndScriptCallback(int iEvent, void *pEvent, void *pUser)
{
char *pScript = NULL;
MotCallback *psCall;
char pCommand[1024];
int iRet;
assert(pEvent);
assert(pUser);
psCall = (MotCallback *)pEvent;
pScript = (char *)pUser;
sprintf(pCommand,"%s %f",pScript,psCall->fVal);
iRet = Tcl_Eval(pServ->pSics->pTcl,pCommand);
return iRet;
}
/*----------------------------------------------------------------------------
The wrapper function for a motor. Commands currently supported are:
motorname parametername newval : sets a parameter
motorname parametername : gets the value for a par
motorname list : lists all parameters
motorname reset : puts softlimits to default
motorname interest : starts sending automatic
notifications when driving
motorname endscript : script to call when motor
finishes driving
-----------------------------------------------------------------------------*/
int MotorAction(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[512];
TokenList *pList = NULL;
TokenList *pCurrent;
TokenList *pName;
int iRet;
pMotor self;
float fValue;
long lID;
pMotInfo pMoti = NULL;
assert(pCon);
assert(pSics);
assert(pData);
self = (pMotor)pData;
/* create Tokenlist */
argtolower(argc,argv);
pList = SplitArguments(argc,argv);
if(!pList)
{
SCWrite(pCon,"Error parsing argument list in MotorAction",eError);
return 0;
}
/* first argument can be one of list, reset or parameter name */
pCurrent = pList->pNext;
if(!pCurrent) /* no argument, print value */
{
iRet = MotorGetSoftPosition(self,pCon,&fValue);
if(!iRet)
{
sprintf(pBueffel,"Error obtaining position for %s",argv[0]);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 0;
}
sprintf(pBueffel,"%s = %f",argv[0],fValue);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 1;
}
/* check for list */
if(strcmp(pCurrent->text,"list") == 0)
{
MotorListLL(self,pCon);
DeleteTokenList(pList);
return 1;
} /* check for reset */
else if(strcmp(pCurrent->text,"reset") == 0)
{
if(!SCMatchRights(pCon,usUser))
{
sprintf(pBueffel,"Insufficient privilege to reset %s",
argv[0]);
SCWrite(pCon,pBueffel,eError);
DeleteTokenList(pList);
return 0;
}
MotorReset(self);
DeleteTokenList(pList);
SCSendOK(pCon);
return 1;
}
else if(strcmp(pCurrent->text,"interest") == 0) /* interest */
{
pMoti = (pMotInfo)malloc(sizeof(MotInfo));
if(!pMoti)
{
SCWrite(pCon,"ERROR: out of memory in motor.c",eError);
return 0;
}
pMoti->pName = strdup(argv[0]);
pMoti->pCon = pCon;
lID = RegisterCallback(self->pCall, MOTDRIVE, InterestCallback,
pMoti, KillInfo);
SCRegister(pCon,pSics, self->pCall,lID);
DeleteTokenList(pList);
SCSendOK(pCon);
return 1;
}
else if(strcmp(pCurrent->text,"uninterest") == 0)
{
RemoveCallback2(self->pCall,pCon);
SCSendOK(pCon);
DeleteTokenList(pList);
return 1;
}
else if(strcmp(pCurrent->text,"endscript") == 0) /* endscript */
{
if(!SCMatchRights(pCon,usMugger))
{
return 0;
}
if(self->endScriptID != 0)
{
RemoveCallback(self->pCall, self->endScriptID);
self->endScriptID = 0;
}
pCurrent = pCurrent->pNext;
if(!pCurrent)
{
SCWrite(pCon,"ERROR: scriptname argument missing",eError);
return 0;
}
self->endScriptID =
RegisterCallback(self->pCall, MOTEND, EndScriptCallback,
strdup(pCurrent->text), KillScript);
SCRegister(pCon,pSics, self->pCall,self->endScriptID);
DeleteTokenList(pList);
SCSendOK(pCon);
return 1;
}
else /* one of the parameter commands or error left now */
{
pName = pCurrent;
pCurrent = pCurrent->pNext;
if(!pCurrent) /* no third par: print val */
{
/* deal with position first */
if(strcmp(pName->text,"position") == 0)
{
iRet = MotorGetSoftPosition(self,pCon,&fValue);
if(!iRet)
{
sprintf(pBueffel,"Error obtaining position for %s",argv[0]);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 0;
}
sprintf(pBueffel,"%s.SoftPosition = %f",argv[0],fValue);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 1;
}
else if(strcmp(pName->text,"hardposition") == 0)
{
iRet = MotorGetHardPosition(self,pCon,&fValue);
if(!iRet) {
sprintf(pBueffel,"Error obtaining position for %s",argv[0]);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 0;
}
sprintf(pBueffel,"%s.HardPosition = %f",argv[0],fValue);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 1;
}
iRet = MotorGetPar(self,pName->text,&fValue);
if(!iRet)
{
sprintf(pBueffel,"Parameter %s not found ",pName->text);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 0;
}
else
{
sprintf(pBueffel, " %s.%s = %f",self->name,pName->text,fValue);
SCWrite(pCon,pBueffel,eValue);
DeleteTokenList(pList);
return 1;
}
}
else /* set */
{ /* set command */
/* parameter must be numerical value */
if(pCurrent->Type == eInt)
{
fValue = (float)pCurrent->iVal;
}
else if(pCurrent->Type == eFloat)
{
fValue = pCurrent->fVal;
}
else
{
sprintf(pBueffel,"Wrong argument type for %s %s set",
argv[0],pName->text);
SCWrite(pCon,pBueffel,eError);
DeleteTokenList(pList);
return 0;
}
iRet = MotorSetPar(self,pCon,pName->text,fValue);
DeleteTokenList(pList);
if(iRet)
SCSendOK(pCon);
return iRet;
}
}
return 0;
}