- Adding first working version of new AMOR settings module

- Improved sls magnet driver
This commit is contained in:
koennecke
2005-10-05 07:36:37 +00:00
parent c7280ec25d
commit 544dd37279
21 changed files with 2521 additions and 12 deletions

110
amorcomp.c Normal file
View File

@ -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;
}

28
amorcomp.h Normal file
View File

@ -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 <stdio.h>
#include <sics.h>
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

170
amordrive.c Normal file
View File

@ -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;
}

25
amordrive.h Normal file
View File

@ -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

600
amorset.c Normal file
View File

@ -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 <stdlib.h>
#include <assert.h>
#include <math.h>
#include "amorset.h"
#include <motorlist.h>
#include "amorcomp.h"
#include "amordrive.h"
#include <trigd.h>
#include <lld.h>
#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;
}

50
amorset.h Normal file
View File

@ -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

209
amorset.tex Normal file
View File

@ -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 <stdio.h>@\\
\mbox{}\verb@ #include <sics.h>@\\
\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}

152
amorset.w Normal file
View File

@ -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"
@<amorsetint@>
#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 <stdio.h>
#include <sics.h>
@<amorcompint@>
#endif
@}
@o amordrive.h @{
/*--------------------------------------------------------------------
Part of the AMOR position calculation module.
copyright: see file COPYRIGHT
Mark Koennecke, October 2005
----------------------------------------------------------------------*/
#ifndef AMORDRIVE
#define AMORDRIVE
@<amordriveint@>
#endif
@}

418
dspcode.c Normal file
View File

@ -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;
}
}

View File

@ -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);

BIN
libpsi.a Normal file

Binary file not shown.

View File

@ -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

32
makedspcodes Executable file
View File

@ -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

View File

@ -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

View File

@ -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");

4
psi.c
View File

@ -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[]);

View File

@ -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;

175
tabledrive.tex Normal file
View File

@ -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 <sics.h>@\\
\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}

8
tas.h
View File

@ -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

View File

@ -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

View File

@ -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