Files
sicspsi/swmotor.c
koennecke 3eed3432cb - Added some hipadab array math
- Added missing cnvrt files, stolen from Markus
- Debugged the new sinqhttpopt driver for SINQ HTTP HM
- Debugged the driver for the new S7 Siemens SPS
- Added handling of hexadecimal terminators to ascon.c
- Increased the write buffer size in asynnet again
- Fixed  a core dump in lld.c
- Added writing of second gen HM to nxscript.c
- Added doubletime command to SICS
- Fixed a core dump issue in sicshdbadapter.c on dimension changes
- Modified sicsobj to look for lower case keys too
2011-04-08 14:18:43 +00:00

530 lines
16 KiB
C

/*--------------------------------------------------------------------------
TOPSI switched motors implementation module. Three motors share a common
EL734 motor. The actual motor is selected through a SPS. More information in
file switchedmotor.tex or with Jochen Stahn.
copyright: see file copyright.h
Mark Koennecke, May 2001
Reworked a bit to work with second generation motors
Mark Koennecke, February 2011
--------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <tcl.h>
#include <fortify.h>
#include <sics.h>
#include <SCinter.h>
#include <splitter.h>
#include "hardsup/sinq_prototypes.h"
#include "hardsup/rs232c_def.h"
#include "hardsup/el734_def.h"
#include "hardsup/el734fix.h"
#include <modriv.h>
#include "macro.h"
#include "swmotor.h"
#include "swmotor.i"
typedef struct __MoDriv {
/* 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);
/* EL-734 specific fields */
int iPort;
char *hostname;
int iChannel;
int iMotor;
void *EL734struct;
int iMSR;
} EL734Driv;
/*========================================================================
We start of by implementing the interface functions for the various
interfaces this module has to implement.
==========================================================================*/
static int SWHalt(void *pData)
{
pSWmot self = (pSWmot) pData;
assert(self);
return self->pMaster->pDrivInt->Halt(self->pMaster);
}
/*--------------------------------------------------------------------*/
static int SWCheckLimits(void *pData, float fVal, char *error, int iErrLen)
{
pSWmot self = (pSWmot) pData;
assert(self);
return self->pMaster->pDrivInt->CheckLimits(self->pMaster,
fVal, error, iErrLen);
}
/*--------------------------------------------------------------------*/
static int SWCheckStatus(void *pData, SConnection * pCon)
{
pSWmot self = (pSWmot) pData;
assert(self);
return self->pMaster->pDrivInt->CheckStatus(self->pMaster, pCon);
}
/*---------------------------------------------------------------------*/
static int SWSaveStatus(void *pData, char *name, FILE * fd)
{
pSWmot self = (pSWmot) pData;
assert(self);
fprintf(fd, "%s savedValue = %f\n", name,
self->positions[self->myNumber]);
return 1;
}
/*-----------------------------------------------------------------------*/
static void *SWGetInterface(void *pData, int ID)
{
pSWmot self = (pSWmot) pData;
assert(self);
if (ID == DRIVEID) {
return self->pDriv;
}
return NULL;
}
/*----------------------------------------------------------------------*/
static float SWGetValue(void *pData, SConnection * pCon)
{
pSWmot self = (pSWmot) pData;
float fVal;
assert(self);
/*
we are not selected: return stored data:
*/
if (self->myNumber != self->selectedMotor[0]) {
SCWrite(pCon, "WARNING: motor not activem returning stored value",
eWarning);
return self->positions[self->myNumber];
} else {
fVal = self->pMaster->pDrivInt->GetValue(self->pMaster, pCon);
self->positions[self->myNumber] = fVal;
return fVal;
}
}
/*-----------------------------------------------------------------------*/
static long SWSetValue(void *pData, SConnection * pCon, float fVal)
{
pSWmot self = (pSWmot) pData;
char pCommand[256], pError[132];
int status;
EL734Driv *pElli;
Tcl_Interp *pTcl;
assert(self);
self->errCode = 1;
/*
first case: we are already selected
*/
if (self->myNumber == self->selectedMotor[0]) {
return self->pMaster->pDrivInt->SetValue(self->pMaster, pCon, fVal);
} else {
/*
second case: switch to the requested motor, do a reference run
and then execute Set command
*/
sprintf(pCommand, "Switching to motor number %d", self->myNumber);
SCWrite(pCon, pCommand, eWarning);
sprintf(pCommand, "%s %d", self->switchFunc, self->myNumber);
pTcl = (Tcl_Interp *) pServ->pSics->pTcl;
status = Tcl_Eval(pTcl, pCommand);
strlcpy(pError, pTcl->result, 131);
if (status != TCL_OK || strstr(pError, "OK") == NULL) {
sprintf(pCommand, "ERROR: %s while switching motor", pError);
SCWrite(pCon, pCommand, eError);
self->errCode = -1001;
return HWFault;
}
self->selectedMotor[0] = self->myNumber;
/*
switch done! Start a reference run
*/
SicsWait(10);
SCWrite(pCon, "Standby, starting reference run... ", eWarning);
pElli = (EL734Driv *) self->pMaster->pDriver;
sprintf(pCommand, "R %d\r", pElli->iMotor);
status = EL734_SendCmnd(&(pElli->EL734struct), pCommand, pError, 131);
if (status != 1) {
sprintf(pCommand, "ERROR: %s while trying to start reference run",
pError);
SCWrite(pCon, pCommand, eError);
self->errCode = -1002;
return HWFault;
}
/*
now loop forever until reference run is done. This is either when the
motors stops being busy or when the user interrupts.
*/
sprintf(pCommand, "SS %d\r", pElli->iMotor);
for (;;) {
status = EL734_SendCmnd(&(pElli->EL734struct),
pCommand, pError, 131);
if (status != 1) {
sprintf(pCommand, "ERROR: %s during reference run", pError);
SCWrite(pCon, pCommand, eError);
self->errCode = -1003;
return HWFault;
}
if (strstr(pError, "?BSY") == NULL)
break;
if (SCGetInterrupt(pCon) != eContinue) {
self->errCode = -1004;
SCWrite(pCon, "ERROR: user interrupted reference run", eError);
return HWFault;
}
SicsWait(2);
}
/*
now this is finished. We can really start driving the motor
*/
SCWrite(pCon, "Reference run completed, starting to drive motor..",
eWarning);
return self->pMaster->pDrivInt->SetValue(self->pMaster, pCon, fVal);
}
}
/*----------------------------------------------------------------------*/
static void KillSWFull(void *pData)
{
pSWmot self = (pSWmot) pData;
if (self == NULL)
return;
if (self->pDriv)
free(self->pDriv);
if (self->pDes)
DeleteDescriptor(self->pDes);
if (self->selectedMotor)
free(self->selectedMotor);
if (self->switchFunc)
free(self->switchFunc);
free(self);
}
/*---------------------------------------------------------------------*/
static void KillSWHalf(void *pData)
{
pSWmot self = (pSWmot) pData;
if (self)
free(self);
}
/*----------------------------------------------------------------------
Alright, now the interpreter functions follow
Usage:
MakeSWMotor master switchFunc slave1 slave2 slave3
-----------------------------------------------------------------------*/
int MakeSWMotor(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pSWmot sw1, sw2, sw3;
char pBueffel[256];
int i, status;
/*
check that we have enough arguments
*/
if (argc < 6) {
SCWrite(pCon, "ERROR: insufficient number of arguments to MakeSWMotor",
eError);
return 0;
}
/*
allocate a new data structure
*/
sw1 = (pSWmot) malloc(sizeof(SWmot));
if (sw1 == NULL) {
SCWrite(pCon, "ERROR: out of memory in MakeSWMotor", eError);
return 0;
}
memset(sw1, 0, sizeof(SWmot));
/*
fill it up with stuff
*/
sw1->pDes = CreateDescriptor("Sparbroetchen");
sw1->pDriv = CreateDrivableInterface();
sw1->selectedMotor = (int *) malloc(sizeof(int));
if (!sw1->pDes || !sw1->pDriv || !sw1->selectedMotor) {
SCWrite(pCon, "ERROR: out of memory in MakeSWMotor", eError);
return 0;
}
sw1->selectedMotor[0] = -1;
sw1->pMaster = FindMotor(pSics, argv[1]);
if (!sw1->pMaster) {
sprintf(pBueffel, "ERROR: cannot find master motor %s", argv[1]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
sw1->switchFunc = strdup(argv[2]);
for (i = 0; i < 3; i++) {
strcpy(sw1->slaves[i], argv[3 + i]);
}
/*
initialize function pointers
*/
sw1->pDes->SaveStatus = SWSaveStatus;
sw1->pDes->GetInterface = SWGetInterface;
sw1->pDriv->GetValue = SWGetValue;
sw1->pDriv->SetValue = SWSetValue;
sw1->pDriv->Halt = SWHalt;
sw1->pDriv->CheckStatus = SWCheckStatus;
sw1->pDriv->CheckLimits = SWCheckLimits;
/*
create clones of the new data structure ofr the other slaves
*/
sw2 = (pSWmot) malloc(sizeof(SWmot));
sw3 = (pSWmot) malloc(sizeof(SWmot));
if (!sw2 || !sw2) {
SCWrite(pCon, "ERROR: out of memory in MakeSWMotor", eError);
return 0;
}
memcpy(sw2, sw1, sizeof(SWmot));
sw2->myNumber = 1;
memcpy(sw3, sw1, sizeof(SWmot));
sw3->myNumber = 2;
/*
install commands
*/
status = AddCommand(pSics, argv[3], SWMotorAction, KillSWFull, sw1);
if (!status) {
sprintf(pBueffel, "ERROR: command %s already exists!", argv[3]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
status = AddCommand(pSics, argv[4], SWMotorAction, KillSWHalf, sw2);
if (!status) {
sprintf(pBueffel, "ERROR: command %s already exists!", argv[4]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
status = AddCommand(pSics, argv[5], SWMotorAction, KillSWHalf, sw3);
if (!status) {
sprintf(pBueffel, "ERROR: command %s already exists!", argv[3]);
SCWrite(pCon, pBueffel, eError);
return 0;
}
return 1;
}
/*-------------------------------------------------------------------
some prototypes from functions implemented in motor.c
--------------------------------------------------------------------*/
void MotorListLL(pMotor self, SConnection * pCon);
void MotorReset(pMotor pM);
/*---------------------------------------------------------------------*/
int SWMotorAction(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
char pBueffel[512];
TokenList *pList = NULL;
TokenList *pCurrent;
TokenList *pName;
int iRet;
pSWmot self = NULL;
float fValue;
long lID;
assert(pCon);
assert(pSics);
assert(pData);
self = (pSWmot) pData;
/* create Tokenlist */
argtolower(argc, argv);
pList = SplitArguments(argc, argv);
if (!pList) {
SCWrite(pCon, "Error parsing argument list in SWMotorAction", eError);
return 0;
}
/* first argument can be one of list, reset or parameter name */
pCurrent = pList->pNext;
if (!pCurrent) { /* no argument, print value */
fValue = self->pDriv->GetValue(self, pCon);
if (fValue < -990.) {
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) {
snprintf(pBueffel,sizeof(pBueffel),"%s list", self->pMaster->name);
MacroPush(pCon);
iRet = Tcl_Eval(InterpGetTcl(pSics),pBueffel);
MacroPop();
SCWrite(pCon,(char *)Tcl_GetStringResult(InterpGetTcl(pSics)), eValue);
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;
}
snprintf(pBueffel,sizeof(pBueffel),"%s reset", self->pMaster->name);
MacroPush(pCon);
iRet = Tcl_Eval(InterpGetTcl(pSics),pBueffel);
MacroPop();
SCWrite(pCon,(char *)Tcl_GetStringResult(InterpGetTcl(pSics)), eValue);
DeleteTokenList(pList);
SCSendOK(pCon);
return 1;
} else if (strcmp(pCurrent->text, "savedValue") == 0) {
pCurrent = pCurrent->pNext;
if (!pCurrent) {
/*
print Value
*/
sprintf(pBueffel, "%s.savedValue = %f", argv[0],
self->positions[self->myNumber]);
SCWrite(pCon, pBueffel, eValue);
DeleteTokenList(pList);
return 1;
} else {
/*
set saveValue, must be a numeric parameter
*/
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 ",
argv[0], "saveValue");
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return 0;
}
self->positions[self->myNumber] = fValue;
SCSendOK(pCon);
return 1;
}
} else if (strcmp(pCurrent->text, "selected") == 0) {
pCurrent = pCurrent->pNext;
if (!pCurrent) {
/*
print Value
*/
sprintf(pBueffel, "%s.selected = %d", argv[0],
self->selectedMotor[0]);
SCWrite(pCon, pBueffel, eValue);
DeleteTokenList(pList);
return 1;
} else {
/*
set selected, must be a numeric parameter
*/
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 ",
argv[0], "selected");
SCWrite(pCon, pBueffel, eError);
DeleteTokenList(pList);
return 0;
}
self->selectedMotor[0] = (int) fValue;
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) {
fValue = self->pDriv->GetValue(self, pCon);
if (fValue < 999.) {
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;
}
iRet = MotorGetPar(self->pMaster, 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", argv[0], 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->pMaster, pCon, pName->text, fValue);
DeleteTokenList(pList);
if (iRet)
SCSendOK(pCon);
return iRet;
}
}
return 0;
}