diff --git a/amorcomp.c b/amorcomp.c new file mode 100644 index 0000000..a86a512 --- /dev/null +++ b/amorcomp.c @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------- + AMOR component handling module. For the new (2005) calculation of the + positions using the beam height as zero. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +-----------------------------------------------------------------------*/ +#include "amorcomp.h" +#define ABS(x) (x < 0 ? -(x) : (x)) + +double calcCompPosition(pamorComp comp){ + return ABS(comp->scaleOffset - comp->markOffset - comp->readPosition); +} +/*-------------------------------------------------------------------*/ +int handleCompCommand(pamorComp comp, SConnection *pCon, + int argc, char *argv[]){ + char pBueffel[512]; + + if(argc < 3) { + SCWrite(pCon,"ERROR: not enough arguments",eError); + return 0; + } + strtolower(argv[2]); + if(strcmp(argv[2],"list") == 0){ + snprintf(pBueffel,511, +"%s %s active = %d\n%s %s offset = %f\n%s %s scaleoffset = %f\n%s %s read = %f\n%s %s calc = %f\n", + argv[0], argv[1], comp->activeFlag, + argv[0], argv[1], comp->markOffset, + argv[0], argv[1], comp->scaleOffset, + argv[0], argv[1], comp->readPosition, + argv[0], argv[1], calcCompPosition(comp)); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else if (strcmp(argv[2], "active") == 0) { + if(argc > 3) { + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + SCparChange(pCon); + comp->activeFlag = atoi(argv[3]); + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,511," %s %s active = %d", + argv[0], argv[1], comp->activeFlag); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } else if (strcmp(argv[2], "offset") == 0) { + if(argc > 3) { + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + SCparChange(pCon); + comp->markOffset = atof(argv[3]); + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,511," %s %s offset = %f", + argv[0], argv[1], comp->markOffset); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } else if (strcmp(argv[2], "scaleoffset") == 0) { + if(argc > 3) { + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + comp->scaleOffset = atof(argv[3]); + SCparChange(pCon); + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,511," %s %s scaleoffset = %f", + argv[0], argv[1], comp->scaleOffset); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } else if (strcmp(argv[2], "read") == 0) { + if(argc > 3) { + if(!SCMatchRights(pCon,usUser)){ + return 0; + } + comp->readPosition = atof(argv[3]); + SCparChange(pCon); + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,511," %s %s read = %f", + argv[0], argv[1], comp->readPosition); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } else { + snprintf(pBueffel,511,"ERROR: subcommand %s to %s %s not understood", + argv[2], argv[0], argv[1]); + SCWrite(pCon,pBueffel,eError); + return 0; + } + return 1; +} +/*------------------------------------------------------------------------*/ +int saveAmorComp(FILE *fd, char *name, char *compname, pamorComp comp){ + fprintf(fd,"%s %s active %d\n", name, compname, comp->activeFlag); + fprintf(fd,"%s %s offset %f\n", name, compname, comp->markOffset); + fprintf(fd,"%s %s scaleoffset %f\n", name, compname, comp->scaleOffset); + fprintf(fd,"%s %s read %f\n", name, compname, comp->readPosition); + return 1; +} diff --git a/amorcomp.h b/amorcomp.h new file mode 100644 index 0000000..0b697f5 --- /dev/null +++ b/amorcomp.h @@ -0,0 +1,28 @@ + +/*--------------------------------------------------------------------- + AMOR component handling module. For the new (2005) calculation of the + positions using the beam height as zero. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +-----------------------------------------------------------------------*/ + #ifndef AMORCOMP + #define AMORCOMP + #include + #include + + typedef struct { + int activeFlag; /* component present */ + double markOffset; /* offset mark to real */ + double scaleOffset; /* offset of the scale */ + double readPosition; /* the position as read */ + } amorComp, *pamorComp; + /*----------------------------------------------------------------------*/ + double calcCompPosition(pamorComp comp); + int handleCompCommand(pamorComp comp, SConnection *pCon, + int argc, char *argv[]); + int saveAmorComp(FILE *fd, char *name, char *compname, pamorComp comp); + + #endif + diff --git a/amordrive.c b/amordrive.c new file mode 100644 index 0000000..540de81 --- /dev/null +++ b/amordrive.c @@ -0,0 +1,170 @@ + /*-------------------------------------------------------------------- + Part of the AMOR position calculation module. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +----------------------------------------------------------------------*/ +#include "amorset.h" +#include "amordrive.h" + +/*---------------------------------------------------------------*/ +static void *AMODRIVGetInterface(void *data, int iD){ + pamorDrive self = NULL; + + self = (pamorDrive)data; + + if(iD == DRIVEID && self != NULL){ + return self->pDriv; + } else { + return NULL; + } + return NULL; +} +/*---------------------------------------------------------------- + This routine can return either OKOK or HWFault when thing + go wrong. However, the return value of Halt is usually ignored! +------------------------------------------------------------------*/ +static int AMODRIVHalt(void *data) { + pamorDrive self = NULL; + + self = (pamorDrive)data; + + return self->mama->pDriv->Halt(self->mama); +} +/*---------------------------------------------------------------- + This routine can return either 1 or 0. 1 means the position can + be reached, 0 NOT + If 0, error shall contain up to errlen characters of information + about which limit was violated + Due to the complex nauture of the calculation: no check here +------------------------------------------------------------------*/ +static int AMODRIVCheckLimits(void *data, float val, + char *error, int errlen){ + pamorDrive self = NULL; + + self = (pamorDrive)data; + + return 1; +} +/*---------------------------------------------------------------- + This routine can return 0 when a limit problem occurred + OKOK when the motor was successfully started + HWFault when a problem occured starting the device + Possible errors shall be printed to pCon + For real motors, this is supposed to try at least three times + to start the motor in question + val is the value to drive the motor too +------------------------------------------------------------------*/ +static long AMODRIVSetValue(void *data, SConnection *pCon, float val){ + pamorDrive self = NULL; + + self = (pamorDrive)data; + + amorSetMotor(self->mama, self->type, val); + + return 1; +} +/*---------------------------------------------------------------- + Checks the status of a running motor. Possible return values + HWBusy The motor is still running + OKOK or HWIdle when the motor finished driving + HWFault when a hardware problem ocurred + HWPosFault when the hardware cannot reach a position + Errors are duly to be printed to pCon + For real motors CheckStatus again shall try hard to fix any + issues with the motor +------------------------------------------------------------------*/ +static int AMODRIVCheckStatus(void *data, SConnection *pCon){ + pamorDrive self = NULL; + + self = (pamorDrive)data; + + return self->mama->pDriv->CheckStatus(self->mama, pCon); +} +/*---------------------------------------------------------------- + GetValue is supposed to read a motor position + On errors, -99999999.99 is returned and messages printed to pCon +------------------------------------------------------------------*/ +static float AMODRIVGetValue(void *data, SConnection *pCon){ + pamorDrive self = NULL; + float val = -99999999.99; + + self = (pamorDrive)data; + return amorGetMotor(self->mama,pCon,self->type); +} +/*---------------------------------------------------------------- + returns NULL on failure, a new datastrcuture else +------------------------------------------------------------------*/ +static pamorDrive AMODRIVMakeObject(){ + pamorDrive self = NULL; + + self = (pamorDrive)malloc(sizeof(amorDrive)); + if(self == NULL){ + return NULL; + } + memset(self,0,sizeof(amorDrive)); + self->pDes = CreateDescriptor("AmorDrive"); + self->pDriv = CreateDrivableInterface(); + if(self->pDes == NULL || self->pDriv == NULL){ + free(self); + return NULL; + } + + self->pDes->GetInterface = AMODRIVGetInterface; + self->pDriv->Halt = AMODRIVHalt; + self->pDriv->CheckLimits = AMODRIVCheckLimits; + self->pDriv->SetValue = AMODRIVSetValue; + self->pDriv->CheckStatus = AMODRIVCheckStatus; + self->pDriv->GetValue = AMODRIVGetValue; + + return self; +} +/*-----------------------------------------------------------------*/ +void killAmorDrive(void *data){ + pamorDrive self = NULL; + + self = (pamorDrive)data; + if(self == NULL){ + return; + } + if(self->pDes != NULL){ + DeleteDescriptor(self->pDes); + } + if(self->pDriv != NULL){ + free(self->pDriv); + } + free(self); +} +/*-----------------------------------------------------------------*/ +pamorDrive makeAmorDrive(pamorSet papa, int type){ + pamorDrive self = NULL; + + self = AMODRIVMakeObject(); + if(self == NULL){ + return self; + } + self->mama = papa; + self->type = type; + return self; +} +/*----------------------------------------------------------------*/ +int AmorDriveAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pamorDrive self = NULL; + float val; + char pBueffel[132]; + + self = (pamorDrive)pData; + assert(self); + val = amorGetMotor(self->mama, pCon,self->type); + if(val > -999999) { + snprintf(pBueffel,131, " %s = %f", argv[0], val); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + return 0; + } + return 0; +} + diff --git a/amordrive.h b/amordrive.h new file mode 100644 index 0000000..d1a53c5 --- /dev/null +++ b/amordrive.h @@ -0,0 +1,25 @@ + + /*-------------------------------------------------------------------- + Part of the AMOR position calculation module. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +----------------------------------------------------------------------*/ +#ifndef AMORDRIVE +#define AMORDRIVE + +typedef struct{ + pObjectDescriptor pDes; + pIDrivable pDriv; + pamorSet mama; + int type; +} amorDrive, *pamorDrive; +/*-----------------------------------------------------------------*/ +pamorDrive makeAmorDrive(pamorSet papa, int type); +void killAmorDrive(void *data); +int AmorDriveAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); + +#endif + diff --git a/amorset.c b/amorset.c new file mode 100644 index 0000000..3ddfc86 --- /dev/null +++ b/amorset.c @@ -0,0 +1,600 @@ +/*------------------------------------------------------------------- + AMORSET together with amorcomp and amordrive implement the position + control facility for the reflectometer AMOR. This uses the algorithm + with the beam height as the baseline. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +--------------------------------------------------------------------*/ +#include +#include +#include +#include "amorset.h" +#include +#include "amorcomp.h" +#include "amordrive.h" +#include +#include +#include "motor.h" +/*--------------------- type defines ------------------------------*/ +#define TYM2T 1 +#define TYS2T 2 +#define TYATH 3 + +#define ABS(x) (x < 0 ? -(x) : (x)) +/*------------ The meat of it all: The settings calculation --------*/ +static int readMotors(pamorSet self, SConnection *pCon){ + int result, status; + float val; + + result = LLDcreate(sizeof(MotControl)); + status = addMotorToList(result,"d2t",.0); + if(status != 1){ + SCWrite(pCon,"ERROR: configuration error: d2t not found", eError); + return -1; + } + status = addMotorToList(result,"d3t",.0); + if(status != 1){ + SCWrite(pCon,"ERROR: configuration error: d3t not found", eError); + return -1; + } + status = addMotorToList(result,"d4t",.0); + if(status != 1){ + SCWrite(pCon,"ERROR: configuration error: d4t not found", eError); + return -1; + } + status = addMotorToList(result,"d5t",.0); + if(status != 1){ + SCWrite(pCon,"ERROR: configuration error: d5t not found", eError); + return -1; + } + val = self->listDrive->GetValue(&result,pCon); + if(val < -99999){ + LLDdelete(result); + return -1; + } + return result; +} +/*------------------------------------------------------------------*/ +static int calcAmorSettings(pamorSet self,SConnection *pCon){ + int readList; + double val, dist, com = .0, soz, mot; + + /* + * read motors + */ + readList = readMotors(self,pCon); + if(readList < 0){ + SCWrite(pCon, + "ERROR: failed to read motors for amor settings",eError); + return 0; + } + /** + * initialize drive list + */ + LLDdelete(self->driveList); + self->driveList = LLDcreate(sizeof(MotControl)); + + /* + * soz + */ + dist = calcCompPosition(&self->S) - calcCompPosition(&self->M); + soz = dist*Tand(self->targetm2t); + addMotorToList(self->driveList,"soz",soz); + + /* + * monochromator slit + */ + if(self->DS.activeFlag == 1){ + dist = calcCompPosition(&self->DS) - calcCompPosition(&self->M); + val = dist*Tand(self->targetm2t) - self->dspar; + addMotorToList(self->driveList,"dbs",val); + } + + /* + * slit 2 + */ + if(self->D2.activeFlag == 1){ + dist = calcCompPosition(&self->D2) - calcCompPosition(&self->M); + mot = getListMotorPosition(readList,"d2t"); + if(mot < -99999){ + SCWrite(pCon,"WARNING: skipping d2 because of bad read on d2t", + eWarning); + } else { + val = dist*Tand(self->targetm2t) - .5 * mot; + addMotorToList(self->driveList,"d2b",val); + } + } + + /* + * slit 3 + */ + if(self->D3.activeFlag == 1){ + dist = calcCompPosition(&self->D3) - calcCompPosition(&self->M); + mot = getListMotorPosition(readList,"d3t"); + if(mot < -99999){ + SCWrite(pCon,"WARNING: skipping d3 because of bad read on d3t", + eWarning); + } else { + val = dist*Tand(self->targetm2t) - .5 * mot; + addMotorToList(self->driveList,"d3b",val); + } + } + + + /* + * detector + */ + com = self->targetm2t + self->targets2t; + if(self->D.activeFlag == 1){ + addMotorToList(self->driveList,"com",com); + dist = calcCompPosition(&self->D) - calcCompPosition(&self->S); + val = dist*(Cosd(com) - 1.); + addMotorToList(self->driveList,"cox",val); + val = dist*Sind(com) + soz; + addMotorToList(self->driveList,"coz",val); + } + + /* + * slit 4 + */ + if(self->D4.activeFlag == 1){ + dist = calcCompPosition(&self->D4) - calcCompPosition(&self->S); + mot = getListMotorPosition(readList,"d4t"); + if(mot < -99999){ + SCWrite(pCon,"WARNING: skipping d4 because of bad read on d4t", + eWarning); + } else { + val = soz + dist*Tand(com) - .5 * mot; + addMotorToList(self->driveList,"d4b",val); + } + } + + /* + * slit 5 + */ + if(self->D5.activeFlag == 1){ + dist = calcCompPosition(&self->D5) - calcCompPosition(&self->S); + mot = getListMotorPosition(readList,"d5t"); + if(mot < -99999){ + SCWrite(pCon,"WARNING: skipping d5 because of bad read on d5t", + eWarning); + } else { + val = soz + dist*Tand(com) - .5 * mot; + addMotorToList(self->driveList,"d5b",val); + } + } + + /* + * Analyzer + */ + if(self->A.activeFlag == 1){ + dist = calcCompPosition(&self->A) - calcCompPosition(&self->S); + val = soz + dist*Tand(com); + addMotorToList(self->driveList,"aoz",val); + addMotorToList(self->driveList,"aom",com + self->targetath); + } + + LLDdelete(readList); + self->mustDrive = 0; + return 1; +} +/*----------------------------------------------------------------*/ +static int updateActualPositions(pamorSet self, SConnection *pCon){ + int readList, status; + float val, dist, tmp, com; + + /** + * read some motors + */ + readList = LLDcreate(sizeof(MotControl)); + addMotorToList(readList,"soz",125); + addMotorToList(readList,"com",125); + addMotorToList(readList,"aom",125); + val = self->listDrive->GetValue(&readList,pCon); + if(val < -99999.){ + SCWrite(pCon, + "ERROR: failed to read motors, values for m2t,s2t,ath invalid", + eError); + LLDdelete(readList); + return 0; + } + val = getListMotorPosition(readList,"soz"); + dist = calcCompPosition(&self->S) - calcCompPosition(&self->M); + tmp = val/dist; + if(ABS(tmp) > .0001){ + self->actualm2t = Atand(tmp); + } else { + self->actualm2t = .0; + } + com = getListMotorPosition(readList,"com"); + self->actuals2t = com - self->actualm2t; + + val = getListMotorPosition(readList,"aom"); + self->actualath = val - com; + + LLDdelete(readList); + self->mustRecalculate = 1; + return 1; +} +/*=================== SICS internal interface functions============*/ +static void *AMOSETGetInterface(void *data, int iD){ + pamorSet self = NULL; + + /* + * this object shall never be driven directly + */ + return NULL; +} +/*---------------------------------------------------------------- + This routine can return either OKOK or HWFault when thing + go wrong. However, the return value of Halt is usually ignored! +------------------------------------------------------------------*/ +static int AMOSETHalt(void *data) { + pamorSet self = NULL; + + self = (pamorSet)data; + + self->listDrive->Halt(&self->driveList); + return OKOK; +} +/*---------------------------------------------------------------- + This routine can return either 1 or 0. 1 means the position can + be reached, 0 NOT + If 0, error shall contain up to errlen characters of information + about which limit was violated +------------------------------------------------------------------*/ +static int AMOSETCheckLimits(void *data, float val, + char *error, int errlen){ + pamorSet self = NULL; + return 1; +} +/*---------------------------------------------------------------- + This routine can return 0 when a limit problem occurred + OKOK when the motor was successfully started + HWFault when a problem occured starting the device + Possible errors shall be printed to pCon + For real motors, this is supposed to try at least three times + to start the motor in question + val is the value to drive the motor too +------------------------------------------------------------------*/ +static long AMOSETSetValue(void *data, SConnection *pCon, float val){ + pamorSet self = NULL; + return OKOK; +} +/*---------------------------------------------------------------- + Checks the status of a running motor. Possible return values + HWBusy The motor is still running + OKOK or HWIdle when the motor finished driving + HWFault when a hardware problem ocurred + HWPosFault when the hardware cannot reach a position + Errors are duly to be printed to pCon + For real motors CheckStatus again shall try hard to fix any + issues with the motor +------------------------------------------------------------------*/ +static int AMOSETCheckStatus(void *data, SConnection *pCon){ + pamorSet self = NULL; + int status; + + self = (pamorSet)data; + + if(self->mustDrive == 1){ + status = calcAmorSettings(self,pCon); + if(status <= 0){ + return HWFault; + } + if(self->verbose == 1){ + printMotorList(self->driveList,pCon); + } + return self->listDrive->SetValue(&self->driveList,pCon,.37); + } else { + self->mustRecalculate = 1; + return self->listDrive->CheckStatus(&self->driveList,pCon); + } +} +/*---------------------------------------------------------------- + GetValue is supposed to read a motor position + On errors, -99999999.99 is returned and messages printed to pCon +------------------------------------------------------------------*/ +static float AMOSETGetValue(void *data, SConnection *pCon){ + pamorSet self = NULL; + float val = -99999999.99; + + self = (pamorSet)data; + + return val; +} +/*================ external functions for amordrive ============*/ +void amorSetMotor(pamorSet amor, int type, double value){ + switch(type){ + case TYM2T: + amor->targetm2t = value; + break; + case TYS2T: + amor->targets2t = value; + break; + case TYATH: + amor->targetath = value; + break; + default: + assert(0); + break; + } + amor->mustDrive = 1; +} +/*----------------------------------------------------------------*/ +double amorGetMotor(pamorSet amor, SConnection *pCon, int type){ + if(amor->mustRecalculate == 1){ + updateActualPositions(amor,pCon); + } + switch(type){ + case TYM2T: + return amor->actualm2t; + break; + case TYS2T: + return amor->actuals2t; + break; + case TYATH: + return amor->actualath; + break; + default: + assert(0); + break; + } + return -99999.999; +} +/*---------------------------------------------------------------- + Live and Deatch of objects......... + returns NULL on failure, a new datastructure else +------------------------------------------------------------------*/ +static int amorSetSave(void *data, char *name,FILE *fd){ + pamorSet self = NULL; + + self = (pamorSet)data; + if(self == NULL){ + return 0; + } + fprintf(fd,"%s dspar %f\n", name, self->dspar); + fprintf(fd,"%s verbose %d\n", name, self->verbose); + saveAmorComp(fd,name,"mono",&self->M); + saveAmorComp(fd,name,"ds",&self->DS); + saveAmorComp(fd,name,"slit2",&self->D2); + saveAmorComp(fd,name,"slit3",&self->D3); + saveAmorComp(fd,name,"sample",&self->S); + saveAmorComp(fd,name,"slit4",&self->D4); + saveAmorComp(fd,name,"slit5",&self->D5); + saveAmorComp(fd,name,"ana",&self->A); + saveAmorComp(fd,name,"detector",&self->D); + return 1; +} +/*---------------------------------------------------------------*/ +static pamorSet AMOSETMakeObject(){ + pamorSet self = NULL; + + self = (pamorSet)malloc(sizeof(amorSet)); + if(self == NULL){ + return NULL; + } + memset(self,0,sizeof(amorSet)); + self->pDes = CreateDescriptor("AmorSet"); + self->pDriv = CreateDrivableInterface(); + self->listDrive = makeMotListInterface(); + self->driveList = LLDcreate(sizeof(MotControl)); + if(self->pDes == NULL || self->pDriv == NULL || + self->listDrive == NULL || self->driveList < 0){ + free(self); + return NULL; + } + + self->pDes->GetInterface = AMOSETGetInterface; + self->pDes->SaveStatus = amorSetSave; + self->pDriv->Halt = AMOSETHalt; + self->pDriv->CheckLimits = AMOSETCheckLimits; + self->pDriv->SetValue = AMOSETSetValue; + self->pDriv->CheckStatus = AMOSETCheckStatus; + self->pDriv->GetValue = AMOSETGetValue; + + return self; +} +/*-----------------------------------------------------------------*/ +static void killAmorSet(void *data){ + pamorSet self = (pamorSet)data; + + if(self == NULL){ + return; + } + + if(self->pDes != NULL) { + DeleteDescriptor(self->pDes); + } + if(self->pDriv != NULL){ + free(self->pDriv); + } + if(self->listDrive != NULL){ + free(self->listDrive); + } + LLDdelete(self->driveList); + free(self); +} +/*-------------------------------------------------------------------*/ +static int testRequiredMotors(SConnection *pCon){ + char motList[][20] = {"soz", "com", + "cox","coz","dbs","d2b","d2t", + "d3b", "d3t", "d4b","d4t", + "d5t", "d5b","aoz", "aom"}; + int i = 0, status = 1; + pMotor pMot = NULL; + char pBueffel[132]; + + + for(i = 0; i < 15; i++){ + pMot = NULL; + pMot = FindMotor(pServ->pSics,motList[i]); + if(pMot == NULL){ + snprintf(pBueffel,131,"ERROR: motor %s for amorset not found", + motList[i]); + SCWrite(pCon,pBueffel,eError); + status = 0; + } + } + return status; +} +/*======================= interpreter interface section ============*/ +int AmorSetFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + int status; + pamorSet pNew = NULL; + pamorDrive pTuk = NULL; + + if(testRequiredMotors(pCon) == 0){ + SCWrite(pCon, + "ERROR: aborting initialization of amorset due to missing motors", + eError); + return 0; + } + + pNew = AMOSETMakeObject(); + if(pNew == NULL){ + SCWrite(pCon,"ERROR: out of memory creating amorset", + eError); + return 0; + } + status = AddCommand(pSics,"amorset",AmorSetAction,killAmorSet,pNew); + if(!status){ + SCWrite(pCon,"ERROR: duplicate command amorset NOT created",eError); + return 0; + } + pTuk = makeAmorDrive(pNew,TYM2T); + if(pTuk == NULL){ + SCWrite(pCon,"ERROR: failed to allocate data fro m2t",eError); + return 0; + } + status = AddCommand(pSics,"m2t",AmorDriveAction,killAmorDrive,pTuk); + if(!status){ + SCWrite(pCon,"ERROR: duplicate command amorset m2t reated",eError); + return 0; + } + pTuk = makeAmorDrive(pNew,TYATH); + if(pTuk == NULL){ + SCWrite(pCon,"ERROR: failed to allocate data for ath",eError); + return 0; + } + status = AddCommand(pSics,"ath",AmorDriveAction,killAmorDrive,pTuk); + if(!status){ + SCWrite(pCon,"ERROR: duplicate command amorset ath reated",eError); + return 0; + } + pTuk = makeAmorDrive(pNew,TYS2T); + if(pTuk == NULL){ + SCWrite(pCon,"ERROR: failed to allocate data for s2t",eError); + return 0; + } + status = AddCommand(pSics,"s2t",AmorDriveAction,killAmorDrive,pTuk); + if(!status){ + SCWrite(pCon,"ERROR: duplicate command amorset s2t reated",eError); + return 0; + } + SCSendOK(pCon); + return 1; +} +/*-----------------------------------------------------------------------*/ +static pamorComp locateComponent(pamorSet self, char *name){ + if(strcmp(name,"mono") == 0){ + return &self->M; + } else if(strcmp(name,"ds") == 0){ + return &self->DS; + }else if(strcmp(name,"slit2") == 0){ + return &self->D2; + }else if(strcmp(name,"slit3") == 0){ + return &self->D3; + }else if(strcmp(name,"sample") == 0){ + return &self->S; + } else if(strcmp(name,"slit4") == 0){ + return &self->D4; + }else if(strcmp(name,"slit5") == 0){ + return &self->D5; + }else if(strcmp(name,"detector") == 0){ + return &self->D; + }else if(strcmp(name,"ana") == 0){ + return &self->A; + } else { + return NULL; + } +} +/*----------------------------------------------------------------------*/ +static double calcCD(pamorSet self){ + double soz, cmh, smh, sdh, cd, dist; + + soz = dist*Cotd(self->targetm2t); + cmh = calcCompPosition(&self->M); + smh = calcCompPosition(&self->S) - calcCompPosition(&self->M); + sdh = calcCompPosition(&self->D) - calcCompPosition(&self->M); + cd = cmh + sqrt(smh*smh + soz*soz) + sdh; + return cd; +} +/*-----------------------------------------------------------------------*/ +int AmorSetAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]){ + pamorSet self = NULL; + pamorComp comp = NULL; + char pBueffel[132]; + + self = (pamorSet)pData; + assert(self); + + if(argc < 2){ + SCWrite(pCon,"ERROR: not enough arguments to amorset",eError); + return 0; + } + + /* + * catch component commands + */ + strtolower(argv[1]); + comp = locateComponent(self,argv[1]); + if(comp != NULL){ + return handleCompCommand(comp,pCon,argc,argv); + } + + /* + * now it is for us .... + */ + if(strcmp(argv[1],"dspar") == 0){ + if(argc > 2){ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + self->dspar = atof(argv[2]); + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,131,"%s dspar = %f", argv[0], self->dspar); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + }else if(strcmp(argv[1],"verbose") == 0){ + if(argc > 2){ + if(!SCMatchRights(pCon,usMugger)){ + return 0; + } + self->verbose = atoi(argv[2]); + SCSendOK(pCon); + return 1; + } else { + snprintf(pBueffel,131,"%s verbose = %d", argv[0], self->verbose); + SCWrite(pCon,pBueffel,eValue); + return 1; + } + } else if(strcmp(argv[1],"cd") == 0){ + snprintf(pBueffel,131,"%s cd = %f", argv[0], calcCD(self)); + SCWrite(pCon,pBueffel,eValue); + return 1; + } else { + SCWrite(pCon,"ERROR: unknown subcommand to amorset",eError); + return 0; + } + + return 1; +} + diff --git a/amorset.h b/amorset.h new file mode 100644 index 0000000..6b0cbd7 --- /dev/null +++ b/amorset.h @@ -0,0 +1,50 @@ + +/*------------------------------------------------------------------- + AMORSET together with amorcomp and amordrive implement the position + control facility for the reflectometer AMOR. This uses the algorithm + with the beam height as the baseline. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +--------------------------------------------------------------------*/ +#ifndef AMORSET +#define AMORSET +#include "amorcomp.h" + +typedef struct { + pObjectDescriptor pDes; + pIDrivable pDriv; + pIDrivable listDrive; + amorComp M; + amorComp DS; + amorComp D2; + amorComp D3; + amorComp S; + amorComp D4; + amorComp A; + amorComp D5; + amorComp D; + double targetm2t; + double targets2t; + double targetath; + double actualm2t; + double actuals2t; + double actualath; + int mustDrive; + int mustRecalculate; + int driveList; + double dspar; + int verbose; +}amorSet, *pamorSet; +/*--------------------------------------------------------------------*/ +int AmorSetFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int AmorSetAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +/*============ helper functions for the virtual motors ===============*/ +void amorSetMotor(pamorSet amor, int type, double value); +double amorGetMotor(pamorSet amor, SConnection *pCon, int type); + +#endif + diff --git a/amorset.tex b/amorset.tex new file mode 100644 index 0000000..61203d8 --- /dev/null +++ b/amorset.tex @@ -0,0 +1,209 @@ +\subsection{AMOR Reflectometer Settings} +This is yet another module for calculating the settings for the AMOR + spectrometer. This version is of 2005 and implements the new calculation + scheme as devised by the Jochen where the base line and height zero point + is the beam height at the chop, chop, chopper. + + Again a lot of parameters have to be maintained. For each optical bench + component an active flag, a fixed offset for correcting the scale reading to + the actual position and an offset regarding the zero point of the scale need + to be kept. And of course the value as read. This is offloaded into a + separate module, amorcomp. Beamline components to be controlled are: + \begin{description} + \item[DS] The slit at the monochromator bunker + \item[M] The monochromator + \item[Dx] various slits + \item[A] the analyzer + \item[D] the detector. + \end{description} + + A master module encloses all those beamline components and performs the + actual calculation. The calculation is controlled through three virtual + motors: m2t (monochromator 2 theta), s2t (sample 2 theta) and ath, the + analyzer angle. For the formula used for the exact calculation, see the + paper from the Jochen. + + + The amorcomp module provides the following interface: + \begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap1} +$\langle$amorcompint {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@ typedef struct {@\\ +\mbox{}\verb@ int activeFlag; /* component present */@\\ +\mbox{}\verb@ double markOffset; /* offset mark to real */@\\ +\mbox{}\verb@ double scaleOffset; /* offset of the scale */@\\ +\mbox{}\verb@ double readPosition; /* the position as read */@\\ +\mbox{}\verb@} amorComp, *pamorComp;@\\ +\mbox{}\verb@/*----------------------------------------------------------------------*/@\\ +\mbox{}\verb@double calcCompPosition(pamorComp comp); @\\ +\mbox{}\verb@int handleCompCommand(pamorComp comp, SConnection *pCon, @\\ +\mbox{}\verb@ int argc, char *argv[]);@\\ +\mbox{}\verb@int saveAmorComp(FILE *fd, char *name, char *compname, pamorComp comp); @\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +The amorset module implements the container for all the data and the actual + calculation. Most of the interesting stuff is in the functions relating to + the interpreter interface and the drivable interface. Again the virtual + motors only set values in the amorset data structure and amorset then takes + control off the driving operation. + +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap2} +$\langle$amorsetint {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@typedef struct {@\\ +\mbox{}\verb@ pObjectDescriptor pDes;@\\ +\mbox{}\verb@ pIDrivable pDriv;@\\ +\mbox{}\verb@ pIDrivable listDrive;@\\ +\mbox{}\verb@ amorComp M;@\\ +\mbox{}\verb@ amorComp DS;@\\ +\mbox{}\verb@ amorComp D2;@\\ +\mbox{}\verb@ amorComp D3;@\\ +\mbox{}\verb@ amorComp S;@\\ +\mbox{}\verb@ amorComp D4;@\\ +\mbox{}\verb@ amorComp A;@\\ +\mbox{}\verb@ amorComp D5;@\\ +\mbox{}\verb@ amorComp D;@\\ +\mbox{}\verb@ double targetm2t;@\\ +\mbox{}\verb@ double targets2t;@\\ +\mbox{}\verb@ double targetath;@\\ +\mbox{}\verb@ double actualm2t;@\\ +\mbox{}\verb@ double actuals2t;@\\ +\mbox{}\verb@ double actualath;@\\ +\mbox{}\verb@ int mustDrive;@\\ +\mbox{}\verb@ int mustRecalculate;@\\ +\mbox{}\verb@ int driveList;@\\ +\mbox{}\verb@ double dspar;@\\ +\mbox{}\verb@ int verbose;@\\ +\mbox{}\verb@}amorSet, *pamorSet;@\\ +\mbox{}\verb@/*--------------------------------------------------------------------*/@\\ +\mbox{}\verb@int AmorSetFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ +\mbox{}\verb@ int argc, char *argv[]);@\\ +\mbox{}\verb@int AmorSetAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ +\mbox{}\verb@ int argc, char *argv[]);@\\ +\mbox{}\verb@/*============ helper functions for the virtual motors ===============*/ @\\ +\mbox{}\verb@void amorSetMotor(pamorSet amor, int type, double value);@\\ +\mbox{}\verb@double amorGetMotor(pamorSet amor, SConnection *pCon, int type);@\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +The virtual motors just implement the bare minimum: +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap3} +$\langle$amordriveint {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@typedef struct{@\\ +\mbox{}\verb@ pObjectDescriptor pDes;@\\ +\mbox{}\verb@ pIDrivable pDriv;@\\ +\mbox{}\verb@ pamorSet mama;@\\ +\mbox{}\verb@ int type;@\\ +\mbox{}\verb@} amorDrive, *pamorDrive;@\\ +\mbox{}\verb@/*-----------------------------------------------------------------*/@\\ +\mbox{}\verb@pamorDrive makeAmorDrive(pamorSet papa, int type);@\\ +\mbox{}\verb@void killAmorDrive(void *data);@\\ +\mbox{}\verb@int AmorDriveAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ +\mbox{}\verb@ int argc, char *argv[]);@\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap4} +\verb@"amorset.h"@ {\footnotesize ? }$\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@/*-------------------------------------------------------------------@\\ +\mbox{}\verb@ AMORSET together with amorcomp and amordrive implement the position@\\ +\mbox{}\verb@ control facility for the reflectometer AMOR. This uses the algorithm@\\ +\mbox{}\verb@ with the beam height as the baseline.@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ copyright: see file COPYRIGHT@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ Mark Koennecke, October 2005@\\ +\mbox{}\verb@--------------------------------------------------------------------*/@\\ +\mbox{}\verb@#ifndef AMORSET@\\ +\mbox{}\verb@#define AMORSET@\\ +\mbox{}\verb@#include "amorcomp.h"@\\ +\mbox{}\verb@@$\langle$amorsetint {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@#endif@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-2ex} +\end{minipage}\\[4ex] +\end{flushleft} +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap5} +\verb@"amorcomp.h"@ {\footnotesize ? }$\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@/*---------------------------------------------------------------------@\\ +\mbox{}\verb@ AMOR component handling module. For the new (2005) calculation of the@\\ +\mbox{}\verb@ positions using the beam height as zero.@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ copyright: see file COPYRIGHT@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ Mark Koennecke, October 2005@\\ +\mbox{}\verb@-----------------------------------------------------------------------*/@\\ +\mbox{}\verb@ #ifndef AMORCOMP@\\ +\mbox{}\verb@ #define AMORCOMP@\\ +\mbox{}\verb@ #include @\\ +\mbox{}\verb@ #include @\\ +\mbox{}\verb@ @$\langle$amorcompint {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@ #endif@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-2ex} +\end{minipage}\\[4ex] +\end{flushleft} +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap6} +\verb@"amordrive.h"@ {\footnotesize ? }$\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@ /*--------------------------------------------------------------------@\\ +\mbox{}\verb@ Part of the AMOR position calculation module.@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ copyright: see file COPYRIGHT@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ Mark Koennecke, October 2005@\\ +\mbox{}\verb@----------------------------------------------------------------------*/@\\ +\mbox{}\verb@#ifndef AMORDRIVE@\\ +\mbox{}\verb@#define AMORDRIVE@\\ +\mbox{}\verb@@$\langle$amordriveint {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@#endif@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ @$\diamond$ +\end{list} +\vspace{-2ex} +\end{minipage}\\[4ex] +\end{flushleft} diff --git a/amorset.w b/amorset.w new file mode 100644 index 0000000..8d9098d --- /dev/null +++ b/amorset.w @@ -0,0 +1,152 @@ +\subsection{AMOR Reflectometer Settings} +This is yet another module for calculating the settings for the AMOR + spectrometer. This version is of 2005 and implements the new calculation + scheme as devised by the Jochen where the base line and height zero point + is the beam height at the chop, chop, chopper. + + Again a lot of parameters have to be maintained. For each optical bench + component an active flag, a fixed offset for correcting the scale reading to + the actual position and an offset regarding the zero point of the scale need + to be kept. And of course the value as read. This is offloaded into a + separate module, amorcomp. Beamline components to be controlled are: + \begin{description} + \item[DS] The slit at the monochromator bunker + \item[M] The monochromator + \item[Dx] various slits + \item[A] the analyzer + \item[D] the detector. + \end{description} + + A master module encloses all those beamline components and performs the + actual calculation. The calculation is controlled through three virtual + motors: m2t (monochromator 2 theta), s2t (sample 2 theta) and ath, the + analyzer angle. For the formula used for the exact calculation, see the + paper from the Jochen. + + + The amorcomp module provides the following interface: + @d amorcompint @{ + typedef struct { + int activeFlag; /* component present */ + double markOffset; /* offset mark to real */ + double scaleOffset; /* offset of the scale */ + double readPosition; /* the position as read */ +} amorComp, *pamorComp; +/*----------------------------------------------------------------------*/ +double calcCompPosition(pamorComp comp); +int handleCompCommand(pamorComp comp, SConnection *pCon, + int argc, char *argv[]); +int saveAmorComp(FILE *fd, char *name, char *compname, pamorComp comp); +@} + +The amorset module implements the container for all the data and the actual + calculation. Most of the interesting stuff is in the functions relating to + the interpreter interface and the drivable interface. Again the virtual + motors only set values in the amorset data structure and amorset then takes + control off the driving operation. + +@d amorsetint @{ +typedef struct { + pObjectDescriptor pDes; + pIDrivable pDriv; + pIDrivable listDrive; + amorComp M; + amorComp DS; + amorComp D2; + amorComp D3; + amorComp S; + amorComp D4; + amorComp A; + amorComp D5; + amorComp D; + double targetm2t; + double targets2t; + double targetath; + double actualm2t; + double actuals2t; + double actualath; + int mustDrive; + int mustRecalculate; + int driveList; + double dspar; + int verbose; +}amorSet, *pamorSet; +/*--------------------------------------------------------------------*/ +int AmorSetFactory(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +int AmorSetAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +/*============ helper functions for the virtual motors ===============*/ +void amorSetMotor(pamorSet amor, int type, double value); +double amorGetMotor(pamorSet amor, SConnection *pCon, int type); +@} + + +The virtual motors just implement the bare minimum: +@d amordriveint @{ +typedef struct{ + pObjectDescriptor pDes; + pIDrivable pDriv; + pamorSet mama; + int type; +} amorDrive, *pamorDrive; +/*-----------------------------------------------------------------*/ +pamorDrive makeAmorDrive(pamorSet papa, int type); +void killAmorDrive(void *data); +int AmorDriveAction(SConnection *pCon, SicsInterp *pSics, void *pData, + int argc, char *argv[]); +@} + + +@o amorset.h @{ +/*------------------------------------------------------------------- + AMORSET together with amorcomp and amordrive implement the position + control facility for the reflectometer AMOR. This uses the algorithm + with the beam height as the baseline. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +--------------------------------------------------------------------*/ +#ifndef AMORSET +#define AMORSET +#include "amorcomp.h" +@ +#endif + +@} + +@o amorcomp.h @{ +/*--------------------------------------------------------------------- + AMOR component handling module. For the new (2005) calculation of the + positions using the beam height as zero. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +-----------------------------------------------------------------------*/ + #ifndef AMORCOMP + #define AMORCOMP + #include + #include + @ + #endif + +@} + + + @o amordrive.h @{ + /*-------------------------------------------------------------------- + Part of the AMOR position calculation module. + + copyright: see file COPYRIGHT + + Mark Koennecke, October 2005 +----------------------------------------------------------------------*/ +#ifndef AMORDRIVE +#define AMORDRIVE +@ +#endif + + @} + \ No newline at end of file diff --git a/dspcode.c b/dspcode.c new file mode 100644 index 0000000..8b9293b --- /dev/null +++ b/dspcode.c @@ -0,0 +1,418 @@ +void slsdspCodeToText(int code, char *text, int textlen){ + switch(code){ + case 0x0: + strncpy(text,"NO",textlen); + break; + case 0x1: + strncpy(text,"DEVICE_STATE_ERROR",textlen); + break; + case 0x2: + strncpy(text,"DEVICE_SUPERVISOR_DISABLED",textlen); + break; + case 0x3: + strncpy(text,"COMMAND_ABORT",textlen); + break; + case 0x4: + strncpy(text,"DATA_NOT_STORED",textlen); + break; + case 0x5: + strncpy(text,"ERROR_ERASING_FLASH",textlen); + break; + case 0x6: + strncpy(text,"COMMUNICATION_BREAK",textlen); + break; + case 0x7: + strncpy(text,"INTERNAL_COMMUNICATION_ERROR",textlen); + break; + case 0x8: + strncpy(text,"MASTER_CARD_ERROR",textlen); + break; + case 0x9: + strncpy(text,"INTERNAL_BUFFER_FULL",textlen); + break; + case 0xa: + strncpy(text,"WRONG_SECTOR",textlen); + break; + case 0xb: + strncpy(text,"DATA_NOT_COPIED",textlen); + break; + case 0xc: + strncpy(text,"WRONG_DOWNLOAD_PARAMETERS",textlen); + break; + case 0xd: + strncpy(text,"DEVICE_PARAMETRIZATION_ERROR",textlen); + break; + case 0x10: + strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE",textlen); + break; + case 0x11: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_ON",textlen); + break; + case 0x12: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_OFF",textlen); + break; + case 0x13: + strncpy(text,"TIMEOUT_MAIN_RELAY_ON",textlen); + break; + case 0x14: + strncpy(text,"TIMEOUT_MAIN_RELAY_OFF",textlen); + break; + case 0x15: + strncpy(text,"TIMEOUT_DATA_DOWNLOAD",textlen); + break; + case 0x20: + strncpy(text,"INTERLOCK",textlen); + break; + case 0x21: + strncpy(text,"MASTER_SWITCH",textlen); + break; + case 0x22: + strncpy(text,"MAGNET_INTERLOCK",textlen); + break; + case 0x23: + strncpy(text,"TEMPERATURE_TRANSFORMER",textlen); + break; + case 0x24: + strncpy(text,"TEMPERATURE_RECTIFIER",textlen); + break; + case 0x25: + strncpy(text,"TEMPERATURE_CONVERTER",textlen); + break; + case 0x26: + strncpy(text,"CURRENT_TRANSDUCER",textlen); + break; + case 0x27: + strncpy(text,"TEMPERATURE_POLARITY_SWITCH",textlen); + break; + case 0x28: + strncpy(text,"POWER_SEMICONDUCTOR",textlen); + break; + case 0x29: + strncpy(text,"MAIN_RELAY",textlen); + break; + case 0x2a: + strncpy(text,"AD_CONVERTER_CARD",textlen); + break; + case 0x2b: + strncpy(text,"POLARITY_SWITCH",textlen); + break; + case 0x2c: + strncpy(text,"AUXILIARY_RELAY",textlen); + break; + case 0x2d: + strncpy(text,"MASTER_SWITCH_T1",textlen); + break; + case 0x2e: + strncpy(text,"MASTER_SWITCH_T2",textlen); + break; + case 0x2f: + strncpy(text,"TEMPERATURE_MAGNET",textlen); + break; + case 0x30: + strncpy(text,"WATER_MAGNET",textlen); + break; + case 0x31: + strncpy(text,"WATER_RACK",textlen); + break; + case 0x40: + strncpy(text,"LOAD_CURRENT_TOO_HIGH",textlen); + break; + case 0x41: + strncpy(text,"DC_LINK_VOLTAGE_TOO_LOW",textlen); + break; + case 0x42: + strncpy(text,"DC_LINK_VOLTAGE_TOO_HIGH",textlen); + break; + case 0x43: + strncpy(text,"LOAD_VOLTAGE_TOO_HIGH",textlen); + break; + case 0x44: + strncpy(text,"LOAD_CURRENT_RIPPLE_TOO_HIGH",textlen); + break; + case 0x45: + strncpy(text,"DC_LINK_ISOLATION_NOT_OK",textlen); + break; + case 0x46: + strncpy(text,"LOAD_ISOLATION_NOT_OK",textlen); + break; + case 0x47: + strncpy(text,"LOAD_IMPEDANCE_OUT_OF_RANGE",textlen); + break; + case 0x48: + strncpy(text,"SHUT_OFF_CURRENT_TOO_HIGH",textlen); + break; + case 0x49: + strncpy(text,"LOAD_DC_CURRENT_TOO_HIGH",textlen); + break; + case 0x4a: + strncpy(text,"CURRENT_I1A1_TOO_HIGH",textlen); + break; + case 0x4b: + strncpy(text,"CURRENT_I1B1_TOO_HIGH",textlen); + break; + case 0x4c: + strncpy(text,"CURRENT_I1A2_TOO_HIGH",textlen); + break; + case 0x4d: + strncpy(text,"CURRENT_I1B2_TOO_HIGH",textlen); + break; + case 0x4e: + strncpy(text,"CURRENT_I2A1_TOO_HIGH",textlen); + break; + case 0x4f: + strncpy(text,"CURRENT_I2B1_TOO_HIGH",textlen); + break; + case 0x50: + strncpy(text,"CURRENT_I2A2_TOO_HIGH",textlen); + break; + case 0x51: + strncpy(text,"CURRENT_I2B2_TOO_HIGH",textlen); + break; + case 0x52: + strncpy(text,"CURRENT_I3P_TOO_HIGH",textlen); + break; + case 0x53: + strncpy(text,"CURRENT_I3N_TOO_HIGH",textlen); + break; + case 0x54: + strncpy(text,"CURRENT_IE_TOO_HIGH",textlen); + break; + case 0x55: + strncpy(text,"VOLTAGE_U1A_TOO_LOW",textlen); + break; + case 0x56: + strncpy(text,"VOLTAGE_U1B_TOO_LOW",textlen); + break; + case 0x57: + strncpy(text,"DIFF_CURRENT_I1A1_I1A2_TOO_HIGH",textlen); + break; + case 0x58: + strncpy(text,"DIFF_CURRENT_I1B1_I1B2_TOO_HIGH",textlen); + break; + case 0x59: + strncpy(text,"DIFF_CURRENT_I2A1_I2A2_TOO_HIGH",textlen); + break; + case 0x5a: + strncpy(text,"DIFF_CURRENT_I2B1_I2B2_TOO_HIGH",textlen); + break; + case 0x5b: + strncpy(text,"DIFF_CURRENT_I3P_I3N_TOO_HIGH",textlen); + break; + case 0x5c: + strncpy(text,"CURRENT_I1A_TOO_HIGH",textlen); + break; + case 0x5d: + strncpy(text,"CURRENT_I1B_TOO_HIGH",textlen); + break; + case 0x5e: + strncpy(text,"CURRENT_I3A1_TOO_HIGH",textlen); + break; + case 0x5f: + strncpy(text,"CURRENT_I3B1_TOO_HIGH",textlen); + break; + case 0x60: + strncpy(text,"CURRENT_I3A2_TOO_HIGH",textlen); + break; + case 0x61: + strncpy(text,"CURRENT_I3B2_TOO_HIGH",textlen); + break; + case 0x62: + strncpy(text,"CURRENT_I4_TOO_HIGH",textlen); + break; + case 0x63: + strncpy(text,"CURRENT_I5_TOO_HIGH",textlen); + break; + case 0x64: + strncpy(text,"DIFF_CURRENT_I3A1_I3A2_TOO_HIGH",textlen); + break; + case 0x65: + strncpy(text,"DIFF_CURRENT_I3B1_I3B2_TOO_HIGH",textlen); + break; + case 0x66: + strncpy(text,"DIFF_CURRENT_I4_I5_TOO_HIGH",textlen); + break; + case 0x67: + strncpy(text,"VOLTAGE_U3A_TOO_LOW",textlen); + break; + case 0x68: + strncpy(text,"VOLTAGE_U3B_TOO_LOW",textlen); + break; + case 0x69: + strncpy(text,"VOLTAGE_U1_TOO_LOW",textlen); + break; + case 0x6a: + strncpy(text,"VOLTAGE_U3A_TOO_HIGH",textlen); + break; + case 0x6b: + strncpy(text,"VOLTAGE_U3B_TOO_HIGH",textlen); + break; + case 0x6c: + strncpy(text,"SPEED_ERROR_TOO_HIGH",textlen); + break; + case 0x70: + strncpy(text,"MAIN_RELAY_A",textlen); + break; + case 0x71: + strncpy(text,"MAIN_RELAY_B",textlen); + break; + case 0x72: + strncpy(text,"POWER_SWITCH_A",textlen); + break; + case 0x73: + strncpy(text,"POWER_SWITCH_B",textlen); + break; + case 0x74: + strncpy(text,"MONITOR_TRAFO_A",textlen); + break; + case 0x75: + strncpy(text,"MONITOR_TRAFO_B",textlen); + break; + case 0x76: + strncpy(text,"TEMPERATURE_RECTIFIER_A",textlen); + break; + case 0x77: + strncpy(text,"TEMPERATURE_RECTIFIER_B",textlen); + break; + case 0x78: + strncpy(text,"TEMPERATURE_CONVERTER_A",textlen); + break; + case 0x79: + strncpy(text,"TEMPERATURE_CONVERTER_B",textlen); + break; + case 0x7a: + strncpy(text,"TEMPERATURE_CONVERTER_A1",textlen); + break; + case 0x7b: + strncpy(text,"TEMPERATURE_CONVERTER_B1",textlen); + break; + case 0x7c: + strncpy(text,"TEMPERATURE_CONVERTER_A2",textlen); + break; + case 0x7d: + strncpy(text,"TEMPERATURE_CONVERTER_B2",textlen); + break; + case 0x7e: + strncpy(text,"TEMPERATURE_TRANSFORMER_A",textlen); + break; + case 0x7f: + strncpy(text,"TEMPERATURE_TRANSFORMER_B",textlen); + break; + case 0x80: + strncpy(text,"WATER_RECTIFIER_A",textlen); + break; + case 0x81: + strncpy(text,"WATER_RECTIFIER_B",textlen); + break; + case 0x82: + strncpy(text,"WATER_CONVERTER_A",textlen); + break; + case 0x83: + strncpy(text,"WATER_CONVERTER_B",textlen); + break; + case 0x84: + strncpy(text,"WATER_CONVERTER_A1",textlen); + break; + case 0x85: + strncpy(text,"WATER_CONVERTER_B1",textlen); + break; + case 0x86: + strncpy(text,"WATER_CONVERTER_A2",textlen); + break; + case 0x87: + strncpy(text,"WATER_CONVERTER_B2",textlen); + break; + case 0x88: + strncpy(text,"WATER_TRANSFORMER_A",textlen); + break; + case 0x89: + strncpy(text,"WATER_TRANSFORMER_B",textlen); + break; + case 0x8a: + strncpy(text,"DOOR_A",textlen); + break; + case 0x8b: + strncpy(text,"DOOR_B",textlen); + break; + case 0x8c: + strncpy(text,"DOOR_C",textlen); + break; + case 0x8d: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A",textlen); + break; + case 0x8e: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B",textlen); + break; + case 0x8f: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A1",textlen); + break; + case 0x90: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B1",textlen); + break; + case 0x91: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A2",textlen); + break; + case 0x92: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B2",textlen); + break; + case 0x93: + strncpy(text,"CURRENT_TRANSDUCER_I3P",textlen); + break; + case 0x94: + strncpy(text,"CURRENT_TRANSDUCER_I3N",textlen); + break; + case 0x95: + strncpy(text,"MAGNET_INTERLOCK_1",textlen); + break; + case 0x96: + strncpy(text,"MAGNET_INTERLOCK_2",textlen); + break; + case 0x97: + strncpy(text,"VENTILATOR",textlen); + break; + case 0x98: + strncpy(text,"EMERGENCY_SWITCH",textlen); + break; + case 0x99: + strncpy(text,"CAPACITOR_DISCHARGE_A_ON",textlen); + break; + case 0x9a: + strncpy(text,"CAPACITOR_DISCHARGE_B_ON",textlen); + break; + case 0x9b: + strncpy(text,"CURRENT_TRANSDUCER_I4",textlen); + break; + case 0x9c: + strncpy(text,"CURRENT_TRANSDUCER_I5",textlen); + break; + case 0xb0: + strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE_PART_A",textlen); + break; + case 0xb1: + strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE_PART_B",textlen); + break; + case 0xb2: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_A_ON",textlen); + break; + case 0xb3: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_B_ON",textlen); + break; + case 0xb4: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_A_OFF",textlen); + break; + case 0xb5: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_B_OFF",textlen); + break; + case 0xb6: + strncpy(text,"TIMEOUT_MAIN_RELAY_A_ON",textlen); + break; + case 0xb7: + strncpy(text,"TIMEOUT_MAIN_RELAY_B_ON",textlen); + break; + case 0xb8: + strncpy(text,"TIMEOUT_MAIN_RELAY_A_OFF",textlen); + break; + case 0xb9: + strncpy(text,"TIMEOUT_MAIN_RELAY_B_OFF",textlen); + break; + } +} diff --git a/ecbdriv.c b/ecbdriv.c index 4ec1ca8..03713ed 100644 --- a/ecbdriv.c +++ b/ecbdriv.c @@ -843,7 +843,7 @@ static void ECBGetError(void *pData, int *iCode, char *buffer, int bufferlen){ strncpy(buffer,"failed to start motor",bufferlen); break; case ECBLIMIT: - strncpy(buffer,"hit limit switch",bufferlen); + strncpy(buffer,"hit limit switch or amplifier error",bufferlen); break; default: strncpy(buffer,"unidentified error code",bufferlen); diff --git a/libpsi.a b/libpsi.a new file mode 100644 index 0000000..f4e7b40 Binary files /dev/null and b/libpsi.a differ diff --git a/make_gen b/make_gen index bf6c0a8..8056640 100644 --- a/make_gen +++ b/make_gen @@ -15,8 +15,9 @@ OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \ bruker.o ltc11.o A1931.o dilludriv.o eurodriv.o slsmagnet.o \ el755driv.o amorscan.o serial.o scontroller.o t_update.o \ t_rlp.o t_conv.o el737hpdriv.o dornier2.o el734hp.o \ - el737hpv2driv.o swmotor2.o tricssupport.o \ - fsm.o logger.o sugar.o pardef.o ease.o strobj.o oxinst.o \ + el737hpv2driv.o swmotor2.o tricssupport.o amorcomp.o \ + fsm.o logger.o sugar.o pardef.o amordrive.o\ + ease.o strobj.o oxinst.o amorset.o\ ipsdriv.o ilmdriv.o itcdriv.o ighdriv.o euro2kdriv.o modbus.o \ dgrambroadcast.o sinq.o tabledrive.o diff --git a/makedspcodes b/makedspcodes new file mode 100755 index 0000000..9ddd882 --- /dev/null +++ b/makedspcodes @@ -0,0 +1,32 @@ +#!/usr/bin/tclsh +#----- little script which converts ukas Tanners error code header file into a +#------ subroutine which converts into text + +set f [open MessagesCodes.h r] + +puts stdout "void slsdspCodeToText(int code, char *text, int textlen){" +puts stdout " switch(code){" + +proc tokenize {txt} { + set l [split $txt] + foreach w $l { + if {[string length $w] > 1} { + lappend result $w + } + } + return $result +} + +while {[gets $f line] >= 0} { + if {[string first "#define" $line] >= 0} { + set l [tokenize $line] + puts stdout " case [lindex $l 2]:" + puts stdout " strncpy(text,\"[lindex $l 1]\",textlen);" + puts stdout " break;" + } +} + +puts stdout " }" +puts stdout "}" +close $f +exit 0 diff --git a/makefile_linux b/makefile_linux index 4cc8c7b..b26a726 100644 --- a/makefile_linux +++ b/makefile_linux @@ -12,7 +12,7 @@ include ../linux_def CC = gcc CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -Ihardsup \ -I.. -fwritable-strings -DCYGNUS -DNONINTF -g $(DFORTIFY) \ - -Wall -Wno-unused -Wno-comment -Wno-switch -Werror + -Wall -Wno-unused -Wno-comment -Wno-switch -Werror EXTRA=nintf.o diff --git a/nxamor.c b/nxamor.c index 1fb7a46..f9352fd 100644 --- a/nxamor.c +++ b/nxamor.c @@ -119,6 +119,13 @@ static int psdSave = 1; /* chopper */ NXDputalias(hfil,hdict,"cname",CHOPPERNAME); + SNXSPutDrivable(pServ->pSics, pCon,hfil,hdict, "chopperspeed", + "crot"); + SNXSPutDrivable(pServ->pSics, pCon,hfil,hdict,"chopper1phase", + "cphase1"); + SNXSPutDrivable(pServ->pSics, pCon,hfil,hdict, "chopper2phase", + "cphase2"); + SNXSPutVariable(pServ->pSics,pCon,hfil, hdict,"crot", "chopperrotation"); diff --git a/psi.c b/psi.c index 62fa387..aacf971 100644 --- a/psi.c +++ b/psi.c @@ -53,7 +53,7 @@ #include "tricssupport.h" #include "sinq.h" #include "tabledrive.h" - +#include "amorset.h" /*--------------------------------------------------------------------------*/ void SiteInit(void) { @@ -101,6 +101,7 @@ static void AddPsiCommands(SicsInterp *pInter){ AddCommand(pInter,"Remob",RemobCreate,NULL,NULL); AddCommand(pInter,"MakeSinq",SinqFactory,NULL,NULL); AddCommand(pInter,"MakeTableDrive",TableDriveFactory,NULL,NULL); + AddCommand(pInter,"MakeAmorSet",AmorSetFactory,NULL,NULL); /* AddCommand(pInter,"MakeDifrac",MakeDifrac,NULL,NULL); */ @@ -131,6 +132,7 @@ static void RemovePsiCommands(SicsInterp *pSics){ RemoveCommand(pSics,"SerialInit"); RemoveCommand(pSics,"MakeSinq"); RemoveCommand(pSics,"MakeTableDrive"); + RemoveCommand(pSics,"MakeAmorSet"); } /*---------------------------------------------------------------------*/ MotorDriver *CreateEL734(SConnection *pCon, int argc, char *argv[]); diff --git a/slsmagnet.c b/slsmagnet.c index 53dd945..15e8789 100644 --- a/slsmagnet.c +++ b/slsmagnet.c @@ -45,7 +45,9 @@ before doing a timeout. 100 corresponds to one second */ #define MAXLOOP 100 - +#define BADLOWLIM -5301 +#define BADHIGHLIM -5302 +#define DEVICERROR -5304 /* packet header codes */ @@ -153,7 +155,7 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) static int GetSLSPos(pEVDriver self, float *fPos) { pSLSDriv pMe = NULL; - int iRet, ival; + int iRet, ival, err; double dval; char msg[6], reply[6]; long lVal; @@ -178,19 +180,75 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) *fPos = (float)dval; pMe->iError = 0; + /* + * try read error codes + */ + msg[1] = 0x29; + iRet = communicateSLS(pMe->pSock,msg,reply); + if(iRet < 0) + { + pMe->iError = iRet; + return iRet; + } + err = (int)reply[5]; + if(err != 0){ + pMe->iError = -7000 - err; + return pMe->iError; + } + return 1; } /*----------------------------------------------------------------------------*/ static int SLSRun(pEVDriver self, float fVal) { pSLSDriv pMe = NULL; - int iRet, ival,i; + int iRet, ival, i; char msg[6], reply[6]; + double min, max; assert(self); pMe = (pSLSDriv )self->pPrivate; assert(pMe); + /* + * test high limit + */ + msg[0] = DSPREAD; + msg[1] = 0x76; + iRet = communicateSLS(pMe->pSock,msg,reply); + if(iRet <= 0) + { + pMe->iError = iRet; + return iRet; + } + memcpy(&ival,reply+2,4); + max = DSPfloat2double(ival); + if(fVal > max){ + pMe->iError = BADHIGHLIM; + return 0; + } + + /* + * test low limit + */ + msg[0] = DSPREAD; + msg[1] = 0x77; + iRet = communicateSLS(pMe->pSock,msg,reply); + if(iRet <= 0) + { + pMe->iError = iRet; + return iRet; + } + memcpy(&ival,reply+2,4); + min = DSPfloat2double(ival); + if(fVal < min){ + pMe->iError = BADLOWLIM; + return 0; + } + + /* + * actual set the new value + */ msg[0] = DSPWRITE; msg[1] = 0x90; ival = double2DSPfloat((double)fVal); @@ -199,18 +257,438 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) if(iRet <= 0) { pMe->iError = iRet; - return iRet; + return 0; } for(i = 1; i < 6; i++) { if(msg[i] != reply[i]) { pMe->iError = BADECHO; - return BADECHO; + return 0; } } return 1; } + /*---------------------------------------------------------------------*/ +static void slsdspCodeToText(int code, char *text, int textlen){ + switch(code){ + case 0x0: + strncpy(text,"NO",textlen); + break; + case 0x1: + strncpy(text,"DEVICE_STATE_ERROR",textlen); + break; + case 0x2: + strncpy(text,"DEVICE_SUPERVISOR_DISABLED",textlen); + break; + case 0x3: + strncpy(text,"COMMAND_ABORT",textlen); + break; + case 0x4: + strncpy(text,"DATA_NOT_STORED",textlen); + break; + case 0x5: + strncpy(text,"ERROR_ERASING_FLASH",textlen); + break; + case 0x6: + strncpy(text,"COMMUNICATION_BREAK",textlen); + break; + case 0x7: + strncpy(text,"INTERNAL_COMMUNICATION_ERROR",textlen); + break; + case 0x8: + strncpy(text,"MASTER_CARD_ERROR",textlen); + break; + case 0x9: + strncpy(text,"INTERNAL_BUFFER_FULL",textlen); + break; + case 0xa: + strncpy(text,"WRONG_SECTOR",textlen); + break; + case 0xb: + strncpy(text,"DATA_NOT_COPIED",textlen); + break; + case 0xc: + strncpy(text,"WRONG_DOWNLOAD_PARAMETERS",textlen); + break; + case 0xd: + strncpy(text,"DEVICE_PARAMETRIZATION_ERROR",textlen); + break; + case 0x10: + strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE",textlen); + break; + case 0x11: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_ON",textlen); + break; + case 0x12: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_OFF",textlen); + break; + case 0x13: + strncpy(text,"TIMEOUT_MAIN_RELAY_ON",textlen); + break; + case 0x14: + strncpy(text,"TIMEOUT_MAIN_RELAY_OFF",textlen); + break; + case 0x15: + strncpy(text,"TIMEOUT_DATA_DOWNLOAD",textlen); + break; + case 0x20: + strncpy(text,"INTERLOCK",textlen); + break; + case 0x21: + strncpy(text,"MASTER_SWITCH",textlen); + break; + case 0x22: + strncpy(text,"MAGNET_INTERLOCK",textlen); + break; + case 0x23: + strncpy(text,"TEMPERATURE_TRANSFORMER",textlen); + break; + case 0x24: + strncpy(text,"TEMPERATURE_RECTIFIER",textlen); + break; + case 0x25: + strncpy(text,"TEMPERATURE_CONVERTER",textlen); + break; + case 0x26: + strncpy(text,"CURRENT_TRANSDUCER",textlen); + break; + case 0x27: + strncpy(text,"TEMPERATURE_POLARITY_SWITCH",textlen); + break; + case 0x28: + strncpy(text,"POWER_SEMICONDUCTOR",textlen); + break; + case 0x29: + strncpy(text,"MAIN_RELAY",textlen); + break; + case 0x2a: + strncpy(text,"AD_CONVERTER_CARD",textlen); + break; + case 0x2b: + strncpy(text,"POLARITY_SWITCH",textlen); + break; + case 0x2c: + strncpy(text,"AUXILIARY_RELAY",textlen); + break; + case 0x2d: + strncpy(text,"MASTER_SWITCH_T1",textlen); + break; + case 0x2e: + strncpy(text,"MASTER_SWITCH_T2",textlen); + break; + case 0x2f: + strncpy(text,"TEMPERATURE_MAGNET",textlen); + break; + case 0x30: + strncpy(text,"WATER_MAGNET",textlen); + break; + case 0x31: + strncpy(text,"WATER_RACK",textlen); + break; + case 0x40: + strncpy(text,"LOAD_CURRENT_TOO_HIGH",textlen); + break; + case 0x41: + strncpy(text,"DC_LINK_VOLTAGE_TOO_LOW",textlen); + break; + case 0x42: + strncpy(text,"DC_LINK_VOLTAGE_TOO_HIGH",textlen); + break; + case 0x43: + strncpy(text,"LOAD_VOLTAGE_TOO_HIGH",textlen); + break; + case 0x44: + strncpy(text,"LOAD_CURRENT_RIPPLE_TOO_HIGH",textlen); + break; + case 0x45: + strncpy(text,"DC_LINK_ISOLATION_NOT_OK",textlen); + break; + case 0x46: + strncpy(text,"LOAD_ISOLATION_NOT_OK",textlen); + break; + case 0x47: + strncpy(text,"LOAD_IMPEDANCE_OUT_OF_RANGE",textlen); + break; + case 0x48: + strncpy(text,"SHUT_OFF_CURRENT_TOO_HIGH",textlen); + break; + case 0x49: + strncpy(text,"LOAD_DC_CURRENT_TOO_HIGH",textlen); + break; + case 0x4a: + strncpy(text,"CURRENT_I1A1_TOO_HIGH",textlen); + break; + case 0x4b: + strncpy(text,"CURRENT_I1B1_TOO_HIGH",textlen); + break; + case 0x4c: + strncpy(text,"CURRENT_I1A2_TOO_HIGH",textlen); + break; + case 0x4d: + strncpy(text,"CURRENT_I1B2_TOO_HIGH",textlen); + break; + case 0x4e: + strncpy(text,"CURRENT_I2A1_TOO_HIGH",textlen); + break; + case 0x4f: + strncpy(text,"CURRENT_I2B1_TOO_HIGH",textlen); + break; + case 0x50: + strncpy(text,"CURRENT_I2A2_TOO_HIGH",textlen); + break; + case 0x51: + strncpy(text,"CURRENT_I2B2_TOO_HIGH",textlen); + break; + case 0x52: + strncpy(text,"CURRENT_I3P_TOO_HIGH",textlen); + break; + case 0x53: + strncpy(text,"CURRENT_I3N_TOO_HIGH",textlen); + break; + case 0x54: + strncpy(text,"CURRENT_IE_TOO_HIGH",textlen); + break; + case 0x55: + strncpy(text,"VOLTAGE_U1A_TOO_LOW",textlen); + break; + case 0x56: + strncpy(text,"VOLTAGE_U1B_TOO_LOW",textlen); + break; + case 0x57: + strncpy(text,"DIFF_CURRENT_I1A1_I1A2_TOO_HIGH",textlen); + break; + case 0x58: + strncpy(text,"DIFF_CURRENT_I1B1_I1B2_TOO_HIGH",textlen); + break; + case 0x59: + strncpy(text,"DIFF_CURRENT_I2A1_I2A2_TOO_HIGH",textlen); + break; + case 0x5a: + strncpy(text,"DIFF_CURRENT_I2B1_I2B2_TOO_HIGH",textlen); + break; + case 0x5b: + strncpy(text,"DIFF_CURRENT_I3P_I3N_TOO_HIGH",textlen); + break; + case 0x5c: + strncpy(text,"CURRENT_I1A_TOO_HIGH",textlen); + break; + case 0x5d: + strncpy(text,"CURRENT_I1B_TOO_HIGH",textlen); + break; + case 0x5e: + strncpy(text,"CURRENT_I3A1_TOO_HIGH",textlen); + break; + case 0x5f: + strncpy(text,"CURRENT_I3B1_TOO_HIGH",textlen); + break; + case 0x60: + strncpy(text,"CURRENT_I3A2_TOO_HIGH",textlen); + break; + case 0x61: + strncpy(text,"CURRENT_I3B2_TOO_HIGH",textlen); + break; + case 0x62: + strncpy(text,"CURRENT_I4_TOO_HIGH",textlen); + break; + case 0x63: + strncpy(text,"CURRENT_I5_TOO_HIGH",textlen); + break; + case 0x64: + strncpy(text,"DIFF_CURRENT_I3A1_I3A2_TOO_HIGH",textlen); + break; + case 0x65: + strncpy(text,"DIFF_CURRENT_I3B1_I3B2_TOO_HIGH",textlen); + break; + case 0x66: + strncpy(text,"DIFF_CURRENT_I4_I5_TOO_HIGH",textlen); + break; + case 0x67: + strncpy(text,"VOLTAGE_U3A_TOO_LOW",textlen); + break; + case 0x68: + strncpy(text,"VOLTAGE_U3B_TOO_LOW",textlen); + break; + case 0x69: + strncpy(text,"VOLTAGE_U1_TOO_LOW",textlen); + break; + case 0x6a: + strncpy(text,"VOLTAGE_U3A_TOO_HIGH",textlen); + break; + case 0x6b: + strncpy(text,"VOLTAGE_U3B_TOO_HIGH",textlen); + break; + case 0x6c: + strncpy(text,"SPEED_ERROR_TOO_HIGH",textlen); + break; + case 0x70: + strncpy(text,"MAIN_RELAY_A",textlen); + break; + case 0x71: + strncpy(text,"MAIN_RELAY_B",textlen); + break; + case 0x72: + strncpy(text,"POWER_SWITCH_A",textlen); + break; + case 0x73: + strncpy(text,"POWER_SWITCH_B",textlen); + break; + case 0x74: + strncpy(text,"MONITOR_TRAFO_A",textlen); + break; + case 0x75: + strncpy(text,"MONITOR_TRAFO_B",textlen); + break; + case 0x76: + strncpy(text,"TEMPERATURE_RECTIFIER_A",textlen); + break; + case 0x77: + strncpy(text,"TEMPERATURE_RECTIFIER_B",textlen); + break; + case 0x78: + strncpy(text,"TEMPERATURE_CONVERTER_A",textlen); + break; + case 0x79: + strncpy(text,"TEMPERATURE_CONVERTER_B",textlen); + break; + case 0x7a: + strncpy(text,"TEMPERATURE_CONVERTER_A1",textlen); + break; + case 0x7b: + strncpy(text,"TEMPERATURE_CONVERTER_B1",textlen); + break; + case 0x7c: + strncpy(text,"TEMPERATURE_CONVERTER_A2",textlen); + break; + case 0x7d: + strncpy(text,"TEMPERATURE_CONVERTER_B2",textlen); + break; + case 0x7e: + strncpy(text,"TEMPERATURE_TRANSFORMER_A",textlen); + break; + case 0x7f: + strncpy(text,"TEMPERATURE_TRANSFORMER_B",textlen); + break; + case 0x80: + strncpy(text,"WATER_RECTIFIER_A",textlen); + break; + case 0x81: + strncpy(text,"WATER_RECTIFIER_B",textlen); + break; + case 0x82: + strncpy(text,"WATER_CONVERTER_A",textlen); + break; + case 0x83: + strncpy(text,"WATER_CONVERTER_B",textlen); + break; + case 0x84: + strncpy(text,"WATER_CONVERTER_A1",textlen); + break; + case 0x85: + strncpy(text,"WATER_CONVERTER_B1",textlen); + break; + case 0x86: + strncpy(text,"WATER_CONVERTER_A2",textlen); + break; + case 0x87: + strncpy(text,"WATER_CONVERTER_B2",textlen); + break; + case 0x88: + strncpy(text,"WATER_TRANSFORMER_A",textlen); + break; + case 0x89: + strncpy(text,"WATER_TRANSFORMER_B",textlen); + break; + case 0x8a: + strncpy(text,"DOOR_A",textlen); + break; + case 0x8b: + strncpy(text,"DOOR_B",textlen); + break; + case 0x8c: + strncpy(text,"DOOR_C",textlen); + break; + case 0x8d: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A",textlen); + break; + case 0x8e: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B",textlen); + break; + case 0x8f: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A1",textlen); + break; + case 0x90: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B1",textlen); + break; + case 0x91: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_A2",textlen); + break; + case 0x92: + strncpy(text,"POWER_SEMICONDUCTOR_CONVERTER_B2",textlen); + break; + case 0x93: + strncpy(text,"CURRENT_TRANSDUCER_I3P",textlen); + break; + case 0x94: + strncpy(text,"CURRENT_TRANSDUCER_I3N",textlen); + break; + case 0x95: + strncpy(text,"MAGNET_INTERLOCK_1",textlen); + break; + case 0x96: + strncpy(text,"MAGNET_INTERLOCK_2",textlen); + break; + case 0x97: + strncpy(text,"VENTILATOR",textlen); + break; + case 0x98: + strncpy(text,"EMERGENCY_SWITCH",textlen); + break; + case 0x99: + strncpy(text,"CAPACITOR_DISCHARGE_A_ON",textlen); + break; + case 0x9a: + strncpy(text,"CAPACITOR_DISCHARGE_B_ON",textlen); + break; + case 0x9b: + strncpy(text,"CURRENT_TRANSDUCER_I4",textlen); + break; + case 0x9c: + strncpy(text,"CURRENT_TRANSDUCER_I5",textlen); + break; + case 0xb0: + strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE_PART_A",textlen); + break; + case 0xb1: + strncpy(text,"TIMEOUT_DC_LINK_VOLTAGE_PART_B",textlen); + break; + case 0xb2: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_A_ON",textlen); + break; + case 0xb3: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_B_ON",textlen); + break; + case 0xb4: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_A_OFF",textlen); + break; + case 0xb5: + strncpy(text,"TIMEOUT_AUXILIARY_RELAY_B_OFF",textlen); + break; + case 0xb6: + strncpy(text,"TIMEOUT_MAIN_RELAY_A_ON",textlen); + break; + case 0xb7: + strncpy(text,"TIMEOUT_MAIN_RELAY_B_ON",textlen); + break; + case 0xb8: + strncpy(text,"TIMEOUT_MAIN_RELAY_A_OFF",textlen); + break; + case 0xb9: + strncpy(text,"TIMEOUT_MAIN_RELAY_B_OFF",textlen); + break; + } +} + /*--------------------------------------------------------------------------*/ static int SLSError(pEVDriver self, int *iCode, char *error, int iErrLen) { @@ -224,6 +702,12 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) assert(pMe); *iCode = pMe->iError; + if(*iCode < -7000){ + slsdspCodeToText(-(pMe->iError + 7000),error,iErrLen); + return 1; + } + + switch(*iCode) { case BADECHO: @@ -235,6 +719,12 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) case TIMEOUT: strncpy(error,"Timeout waiting for response", iErrLen); break; + case BADHIGHLIM: + strncpy(error,"Device internal upper limit violated",iErrLen); + break; + case BADLOWLIM: + strncpy(error,"Device internal lower limit violated",iErrLen); + break; default: getRS232Error(*iCode,error,iErrLen); break; @@ -276,6 +766,9 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) msg[1] = 0x31; */ msg[1] = 0x3c; + /* + * ival = 0: ausschalten + */ ival = 1; memcpy(msg+2, &ival,4); iRet = communicateSLS(pMe->pSock,msg,reply); @@ -299,12 +792,28 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) static int SLSClose(pEVDriver self) { pSLSDriv pMe = NULL; - int iRet; + int iRet, ival; + char msg[6], reply[6]; assert(self); pMe = (pSLSDriv )self->pPrivate; assert(pMe); + /* + * switch the thing off + */ + msg[0] = DSPWRITE; + msg[1] = 0x3c; + /* + * ival = 0: ausschalten + */ + ival = 0; + memcpy(msg+2, &ival,4); + iRet = communicateSLS(pMe->pSock,msg,reply); + /* + * we are on our way out: ignore errors + */ + NETClosePort(pMe->pSock); pMe->pSock = NULL; return 1; @@ -319,8 +828,16 @@ static int communicateSLS(mkChannel *pSock, char msg[6], char reply[6]) pMe = (pSLSDriv )self->pPrivate; assert(pMe); + if(iError < -7000){ + return DEVFAULT; + } + switch(iError) { + case BADHIGHLIM: + case BADLOWLIM: + return DEVFAULT; + break; case BADECHO: case TIMEOUT: return DEVREDO; diff --git a/tabledrive.tex b/tabledrive.tex new file mode 100644 index 0000000..202cbd8 --- /dev/null +++ b/tabledrive.tex @@ -0,0 +1,175 @@ +\subsection{Tabled Driving} +This object implements driving several motors along a predefined path. The definition + of the path happens through a table. Positions between tabulated positions are + interpolated by linear interpolation. Additionally, each motor may be driven a + bit from the tabulated positions for fine adjustments. Of course the limits are + variable from position to position. Thus this object also sets the software limits of the + motors accordingly. This object assumes that motors can be driven between positions + without watching for collisions. The original use of this module is to coordinate the + movements of the MARS triffids or girafs. + +The table lives in a separate file. The format of the file is very simple: +Each block starts with a line containing: +\begin{verbatim} +# motorname +\end{verbatim} +This is a hash and the name of the motor. +These lines are followed by n lines of: +\begin{verbatim} +lower position upper +\end{verbatim} +These are three numbers giving the lower and upper limit for this position in the table + and, as the middle value, the target position for this entry. + + + In order to achieve all this, we need a data structure per table entry: + \begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap1} +$\langle$tdentry {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@typedef struct{@\\ +\mbox{}\verb@ double lower, position, upper;@\\ +\mbox{}\verb@ int tablePos;@\\ +\mbox{}\verb@ }tdEntry, *ptdEntry;@\\ +\mbox{}\verb@ @$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +The fields are the lower and upper limits, the position for this table entry and the +number of the entry. + + +For each motor we need another data structure: +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap2} +$\langle$tdmotor {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@typedef struct {@\\ +\mbox{}\verb@ char motorName[132];@\\ +\mbox{}\verb@ int table;@\\ +\mbox{}\verb@ pMotor pMot;@\\ +\mbox{}\verb@ }tdMotor, *ptdMotor; @\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +The fields: +\begin{description} +\item[motorName] The name of the motor +\item[table] A list of tabulated positions in the form of tdEntry +\item[pMot] A pointer to the motor data structure. +\end{description} + + +The tabledrive object itself needs a data structure too: +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap3} +$\langle$tdobj {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@typedef struct{@\\ +\mbox{}\verb@ pObjectDescriptor pDes;@\\ +\mbox{}\verb@ pIDrivable pDriv;@\\ +\mbox{}\verb@ int motorTable;@\\ +\mbox{}\verb@ int tableLength;@\\ +\mbox{}\verb@ float targetPosition;@\\ +\mbox{}\verb@ float currentPosition;@\\ +\mbox{}\verb@ int state;@\\ +\mbox{}\verb@ char orientMotor[80];@\\ +\mbox{}\verb@ int debug;@\\ +\mbox{}\verb@ }TableDrive, *pTableDrive;@\\ +\mbox{}\verb@@$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +The fields: +\begin{description} +\item[pDes] The standard SICS object descriptor +\item[pDriv] The drivable interface which encapsulates most of the magic of this module. +\item[motorTable] A list of tdMotor entries. +\item[tableLength] The length of the path of positions. +\item[targetPosition] The target position we have to drive to. +\item[currentPosition] where we are now. +\item[state] A state variable used during driving the path. +\item[orientMotor] is the name of the orienting motor, i.e. the one used to determine + the position. +\end{description} + + +In terms of an interface, this object implements the drivable interface which has to + deal with most of the work. There is just an interpreter interface which allows to + configure and query the object. + + \begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap4} +$\langle$tdint {\footnotesize ?}$\rangle\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@int TableDriveFactory(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ +\mbox{}\verb@ int argc, char *argv[]);@\\ +\mbox{}\verb@int TableDriveAction(SConnection *pCon, SicsInterp *pSics, void *pData,@\\ +\mbox{}\verb@ int argc, char *argv[]);@\\ +\mbox{}\verb@ @\\ +\mbox{}\verb@ @$\diamond$ +\end{list} +\vspace{-1ex} +\footnotesize\addtolength{\baselineskip}{-1ex} +\begin{list}{}{\setlength{\itemsep}{-\parsep}\setlength{\itemindent}{-\leftmargin}} +\item Macro referenced in scrap ?. +\end{list} +\end{minipage}\\[4ex] +\end{flushleft} +\begin{flushleft} \small +\begin{minipage}{\linewidth} \label{scrap5} +\verb@"tabledrive.h"@ {\footnotesize ? }$\equiv$ +\vspace{-1ex} +\begin{list}{}{} \item +\mbox{}\verb@@\\ +\mbox{}\verb@ /*---------------------------------------------------------------------------@\\ +\mbox{}\verb@ SICS object for driving a couple of motors along a tabulated given path.@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ copyright: see file COPYRIGHT@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ Mark Koennecke, July 2005@\\ +\mbox{}\verb@---------------------------------------------------------------------------*/@\\ +\mbox{}\verb@#ifndef SICSTABLEDRIVE@\\ +\mbox{}\verb@#define SICSTABLEDRIVE@\\ +\mbox{}\verb@#include @\\ +\mbox{}\verb@#include "../motor.h"@\\ +\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\ +\mbox{}\verb@@$\langle$tdentry {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\ +\mbox{}\verb@@$\langle$tdmotor {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\ +\mbox{}\verb@@$\langle$tdobj {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@/*-------------------------------------------------------------------------*/@\\ +\mbox{}\verb@@$\langle$tdint {\footnotesize ?}$\rangle$\verb@@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@#endif@\\ +\mbox{}\verb@@\\ +\mbox{}\verb@ @$\diamond$ +\end{list} +\vspace{-2ex} +\end{minipage}\\[4ex] +\end{flushleft} diff --git a/tas.h b/tas.h index 4998ede..98075ed 100644 --- a/tas.h +++ b/tas.h @@ -146,8 +146,14 @@ #define HCONV3 127 #define HCONV4 128 #define POLFIL 129 +#define PIX 130 +#define PIY 131 +#define PIZ 132 +#define PFX 133 +#define PFY 134 +#define PFZ 135 -#define MAXPAR 130 +#define MAXPAR 136 #define MAXADD 20 #define MAXEVAR 12 diff --git a/tasinit.c b/tasinit.c index 6c5c5df..166529d 100644 --- a/tasinit.c +++ b/tasinit.c @@ -201,6 +201,12 @@ char *tasVariableOrder[] = { "hconv3", "hconv4", "polfile", + "pix", + "piy", + "piz", + "pfx", + "pfy", + "pfz", NULL}; /*------------------------------------------------------------------- Normally SICS does not store motor hardware limits into status files as diff --git a/tasutil.c b/tasutil.c index 4ac2940..7ac1fc1 100644 --- a/tasutil.c +++ b/tasutil.c @@ -755,6 +755,7 @@ int TASUpdate(pTASdata self, SConnection *pCon) self->tasPar[HX]->fVal = hx; self->tasPar[HY]->fVal = hy; self->tasPar[HZ]->fVal = hz; + SCparChange(pCon); /* now check the analyzer or monochromator angles