
- 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
530 lines
16 KiB
C
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;
|
|
}
|