
a server hangs up diretcly after a message. - Some output was suppressed while tracing, fixed - Make ready to compile both with Ubuntu 32 and 64 or /usr/local based ON in general. Just in psi/makefile_linux the top include has to be adapted - Removed epics drivers from SICS. Still in source to be reenabled when needed - Added FindMotor - Added sput, sappend and slab to nxscript using the new sicsget module - Fix to sget to fix the "mot softzero" problem SKIPPED: psi/make_gen psi/psi.c psi/sinqhttpopt.c psi/spss7.c
329 lines
9.2 KiB
C
329 lines
9.2 KiB
C
/*---------------------------------------------------------------------------
|
|
|
|
M U L T I P L E M O T O R S
|
|
|
|
Code for maintaining a group of motors. This suuports
|
|
- aliases for motors
|
|
- named positions for motors
|
|
- a position history implemented as the special named position
|
|
back.
|
|
|
|
This code implements the configuration command for the Multimotor.
|
|
|
|
|
|
Mark Koennecke, December 1996
|
|
|
|
heavily reworked and simplified, Mark Koennecke, June 1997
|
|
|
|
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.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
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 <ctype.h>
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "devexec.h"
|
|
#include "motor.h"
|
|
#include "splitter.h"
|
|
#include "stringdict.h"
|
|
#include "mumo.h"
|
|
#include "mumo.i"
|
|
|
|
/*--------------------------------------------------------------------------
|
|
Once again, the demands for command evaluation are high. Therefore a
|
|
recursice descent parser.
|
|
*/
|
|
|
|
typedef struct __MYTOKEN {
|
|
char *pCommand;
|
|
char *pPtr;
|
|
int iCurrentToken;
|
|
char Token[80];
|
|
} sParser, *psParser;
|
|
|
|
/* define Token Types */
|
|
#define UNKNOWN 0
|
|
#define END 1
|
|
#define ALIAS 2
|
|
#define POS 3
|
|
#define SYMBOL 4
|
|
#define EQUALITY 5
|
|
#define NUMBER 6
|
|
#define ENDCONFIG 7
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int GetNextToken(psParser self)
|
|
{
|
|
char *pPtr;
|
|
int i;
|
|
|
|
pPtr = self->pPtr;
|
|
|
|
/* skip whitespace */
|
|
while ((*pPtr == ' ') || (*pPtr == '\t')) {
|
|
pPtr++;
|
|
}
|
|
|
|
/* check for end */
|
|
if ((*pPtr == '\n') || (*pPtr == '\0') || (*pPtr == '\r')) {
|
|
self->pPtr = pPtr;
|
|
self->Token[0] = *pPtr;
|
|
self->Token[1] = '\0';
|
|
self->iCurrentToken = END;
|
|
return END;
|
|
}
|
|
|
|
|
|
|
|
/* check equaL SIGN */
|
|
if (*pPtr == '=') {
|
|
strcpy(self->Token, "=");
|
|
self->iCurrentToken = EQUALITY;
|
|
self->pPtr = pPtr + 1;
|
|
return EQUALITY;
|
|
}
|
|
|
|
/* number */
|
|
if ((isdigit((int) *pPtr)) || (*pPtr == '.')
|
|
|| (*pPtr == '+') || (*pPtr == '-')) {
|
|
i = 0;
|
|
while (isdigit((int) *pPtr) || (*pPtr == '.')
|
|
|| (*pPtr == '+') || (*pPtr == '-')) {
|
|
self->Token[i] = *pPtr;
|
|
i++;
|
|
pPtr++;
|
|
}
|
|
self->Token[i] = '\0';
|
|
self->iCurrentToken = NUMBER;
|
|
self->pPtr = pPtr;
|
|
return NUMBER;
|
|
}
|
|
|
|
/* a Symbol ? */
|
|
if (isalnum((int) *pPtr)) {
|
|
i = 0;
|
|
while ((!isspace((int) *pPtr)) && (*pPtr != '=')
|
|
&& (*pPtr != '+') && (*pPtr != '-')
|
|
&& (*pPtr != '\0') && (*pPtr != '\n')) {
|
|
self->Token[i] = *pPtr;
|
|
i++;
|
|
pPtr++;
|
|
}
|
|
self->Token[i] = '\0';
|
|
self->pPtr = pPtr;
|
|
/* now it can be one of the keywords, a motor or a symbol */
|
|
if (strcmp(self->Token, "alias") == 0) {
|
|
self->iCurrentToken = ALIAS;
|
|
return ALIAS;
|
|
} else if (strcmp(self->Token, "pos") == 0) {
|
|
self->iCurrentToken = POS;
|
|
return POS;
|
|
} else if (strcmp(self->Token, "endconfig") == 0) {
|
|
self->iCurrentToken = ENDCONFIG;
|
|
return ENDCONFIG;
|
|
} else {
|
|
self->iCurrentToken = SYMBOL;
|
|
return SYMBOL;
|
|
}
|
|
}
|
|
return UNKNOWN;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
int MakeMulti(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
/* this does not do much, just installs the configuration command */
|
|
pMulMot pNew = NULL;
|
|
int iRet;
|
|
char pBueffel[512];
|
|
|
|
if (argc < 2) {
|
|
SCWrite(pCon, "You need to specify a name for a MultiMotor", eError);
|
|
return 0;
|
|
}
|
|
|
|
/* check rights */
|
|
if (!SCMatchRights(pCon, usMugger)) {
|
|
SCWrite(pCon, "ERROR: you are not permitted to do this", eError);
|
|
return 0;
|
|
}
|
|
|
|
pNew = MakeMultiMotor();
|
|
if (!pNew) {
|
|
SCWrite(pCon, "No Memory for creating MultiMot", eError);
|
|
return 0;
|
|
}
|
|
pNew->name = strdup(argv[1]);
|
|
iRet = AddCommand(pSics, argv[1], ConfigMulti, NULL, pNew);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "ERROR: duplicate command %s not created", argv[2]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int ParseAlias(SicsInterp * pSics, psParser pPP, pMulMot self,
|
|
SConnection * pCon)
|
|
{
|
|
int iToken;
|
|
char pError[132];
|
|
pMotor pMot;
|
|
|
|
/* next token should be a motor name */
|
|
iToken = GetNextToken(pPP);
|
|
if (iToken != SYMBOL) {
|
|
snprintf(pError,sizeof(pError)-1, "ERROR: Token %s not recognized in MulMot alias",
|
|
pPP->Token);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
/* try find the motor and verify that it is a motor */
|
|
pMot = FindMotor(pSics, pPP->Token);
|
|
if (!pMot) {
|
|
snprintf(pError,sizeof(pError)-1, "ERROR: Motor %s not found, no alias created",
|
|
pPP->Token);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* now pMot holds all info ever needed about the motor */
|
|
/* the next Token should be a symbol giving the alias */
|
|
iToken = GetNextToken(pPP);
|
|
if (iToken == EQUALITY) { /* tolerate Equality */
|
|
iToken = GetNextToken(pPP);
|
|
}
|
|
if (iToken != SYMBOL) {
|
|
snprintf(pError,sizeof(pError)-1, "ERROR: Token %s not recognized in MulMot alias",
|
|
pPP->Token);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* now we have all that is ever needed to create an alias. We have done
|
|
so much work in order to get here, that it will be done, here and
|
|
now!
|
|
*/
|
|
StringDictAddPair(self->pAlias, pPP->Token, pMot->name);
|
|
return 1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
static int ParsePos(SicsInterp * pSics, psParser pPP,
|
|
pMulMot self, SConnection * pCon)
|
|
{
|
|
pMotor pMot = NULL;
|
|
char pError[132];
|
|
int iToken;
|
|
float fVal;
|
|
|
|
iToken = GetNextToken(pPP);
|
|
if (iToken != SYMBOL) { /* we want a name here */
|
|
snprintf(pError,sizeof(pError)-1, "ERROR: Invalid Token %s in ParsePos", pPP->Token);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|
|
|
|
/* The rest of the stuff should be the motors to drive until
|
|
we are there
|
|
*/
|
|
StringDictAddPair(self->pNamPos, pPP->Token, pPP->pPtr);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int ConfigMulti(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pMulMot self;
|
|
char pBueffel[512];
|
|
char pError[132];
|
|
int i, iToken, iRet;
|
|
sParser PP;
|
|
CommandList *pCom = NULL;
|
|
|
|
assert(pCon);
|
|
assert(pSics);
|
|
assert(pData);
|
|
|
|
self = (pMulMot) pData;
|
|
|
|
iRet = Arg2Text(argc, argv, pBueffel, 511);
|
|
if (!iRet) {
|
|
snprintf(pBueffel,sizeof(pBueffel)-1, "Argument string to long for %s configuration",
|
|
argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
strtolower(pBueffel);
|
|
|
|
/* first token is name, ignore */
|
|
PP.pCommand = pBueffel;
|
|
PP.pPtr = pBueffel;
|
|
iToken = GetNextToken(&PP);
|
|
iToken = GetNextToken(&PP);
|
|
while (iToken != END) {
|
|
switch (iToken) {
|
|
case END:
|
|
return 1; /* ignored */
|
|
break;
|
|
case ENDCONFIG:
|
|
/* reconfigure command to final state */
|
|
pCom = FindCommand(pSics, argv[0]);
|
|
assert(pCom != NULL);
|
|
pCom->OFunc = MultiWrapper;
|
|
pCom->KFunc = KillMultiMotor;
|
|
return 1;
|
|
break;
|
|
case ALIAS:
|
|
return ParseAlias(pSics, &PP, self, pCon);
|
|
break;
|
|
case POS:
|
|
return ParsePos(pSics, &PP, self, pCon);
|
|
break;
|
|
default:
|
|
snprintf(pError,sizeof(pError)-1, "ERROR: Invalid Token %s found in %s",
|
|
PP.Token, argv[0]);
|
|
SCWrite(pCon, pBueffel, eError);
|
|
return 0;
|
|
}
|
|
iToken = GetNextToken(&PP);
|
|
}
|
|
/* should never end here */
|
|
snprintf(pError,sizeof(pError)-1, "ERROR: %s was NOT understood in mumoconf", pBueffel);
|
|
SCWrite(pCon, pError, eError);
|
|
return 0;
|
|
}
|