- Fixed a bug in hmdata.c - Fixed an issue with tempoerature writing through RemObjects in mesure - Added auxiliary reflections to tasub - Make maximize use soft motor positions
375 lines
11 KiB
C
375 lines
11 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;
|
|
}
|
|
/*--------------------------------------------------------------------------
|
|
in this code we need to find a motor for a name quite frequently.......
|
|
*/
|
|
pMotor FindMotor(SicsInterp *pSics, char *name)
|
|
{
|
|
CommandList *pC;
|
|
pMotor pMot;
|
|
|
|
pC = FindCommand(pSics,name);
|
|
if(!pC)
|
|
{
|
|
return NULL;
|
|
}
|
|
pMot = (pMotor)pC->pData;
|
|
if(!pMot)
|
|
{
|
|
return NULL;
|
|
}
|
|
if(strcmp(pMot->pDescriptor->name,"Motor") != 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
return pMot;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
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)
|
|
{
|
|
sprintf(pBueffel,"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)
|
|
{
|
|
sprintf(pError,"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)
|
|
{
|
|
sprintf(pError,"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)
|
|
{
|
|
sprintf(pError,"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 */
|
|
{
|
|
sprintf(pError,"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)
|
|
{
|
|
sprintf(pBueffel,"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:
|
|
sprintf(pError,"ERROR: Invalid Token %s found in %s",
|
|
PP.Token, argv[0]);
|
|
SCWrite(pCon,pBueffel,eError);
|
|
return 0;
|
|
}
|
|
iToken = GetNextToken(&PP);
|
|
}
|
|
/* should never end here */
|
|
sprintf(pError,"ERROR: %s was NOT understood in mumoconf",pBueffel);
|
|
SCWrite(pCon,pError,eError);
|
|
return 0;
|
|
}
|
|
|